From cbc0ed72c43bff3062ded210c43a1597a2865e9a Mon Sep 17 00:00:00 2001 From: MiaoWoo Date: Wed, 10 Jul 2019 12:01:15 +0800 Subject: [PATCH] feat: first commit Signed-off-by: MiaoWoo --- .gitignore | 40 + package.json | 6 + src/HTML/123 | 162 ++ src/HTML/CSS/blockviewer.css | 440 +++ src/HTML/CSS/buttons.css | 201 ++ src/HTML/CSS/codes.css | 90 + src/HTML/CSS/history.css | 440 +++ src/HTML/CSS/mobile-wallet.css | 2744 +++++++++++++++++++ src/HTML/CSS/style.css | 180 ++ src/HTML/CSS/wallet.css | 535 ++++ src/HTML/JS/client-electron.js | 32 + src/HTML/JS/client.js | 1937 ++++++++++++++ src/HTML/JS/coinlib.js | 112 + src/HTML/JS/crypto-client.js | 372 +++ src/HTML/JS/dapp-inner.js | 521 ++++ src/HTML/JS/diagram.js | 455 ++++ src/HTML/JS/highlight-html.js | 1 + src/HTML/JS/highlight-js.js | 1 + src/HTML/JS/highlight.js | 1 + src/HTML/JS/lexer.js | 1686 ++++++++++++ src/HTML/JS/marked.js | 1 + src/HTML/JS/mobile-wallet.js | 1099 ++++++++ src/HTML/JS/sec256k1.js | 190 ++ src/HTML/JS/sha3.js | 803 ++++++ src/HTML/JS/sign-lib-min.js | 4140 +++++++++++++++++++++++++++++ src/HTML/JS/terahashlib.js | 411 +++ src/HTML/JS/tx-lib.js | 10 + src/HTML/JS/wallet-lib.js | 706 +++++ src/HTML/JS/wallet-node.js | 542 ++++ src/HTML/JS/wallet-web.js | 276 ++ src/HTML/PIC/B.svg | 4 + src/HTML/PIC/T.svg | 3 + src/HTML/PIC/TeraLogo.svg | 13 + src/HTML/PIC/Tera_logo.svg | 6 + src/HTML/PIC/Tera_logo2.svg | 6 + src/HTML/PIC/add-icon.svg | 4 + src/HTML/PIC/address_book.png | Bin 0 -> 2608 bytes src/HTML/PIC/blank.svg | 4 + src/HTML/PIC/chains.png | Bin 0 -> 1617 bytes src/HTML/PIC/check.svg | 3 + src/HTML/PIC/console.png | Bin 0 -> 821 bytes src/HTML/PIC/console0.png | Bin 0 -> 1225 bytes src/HTML/PIC/counters.png | Bin 0 -> 3025 bytes src/HTML/PIC/dapp.png | Bin 0 -> 1174 bytes src/HTML/PIC/down-arrow.svg | 3 + src/HTML/PIC/down.png | Bin 0 -> 1785 bytes src/HTML/PIC/glass.svg | 3 + src/HTML/PIC/info.svg | 3 + src/HTML/PIC/invoice.png | Bin 0 -> 1174 bytes src/HTML/PIC/invoice2.png | Bin 0 -> 1130 bytes src/HTML/PIC/key.png | Bin 0 -> 1621 bytes src/HTML/PIC/lock_closed.png | Bin 0 -> 5988 bytes src/HTML/PIC/lock_open.png | Bin 0 -> 6010 bytes src/HTML/PIC/monitor.png | Bin 0 -> 4078 bytes src/HTML/PIC/network.png | Bin 0 -> 1396 bytes src/HTML/PIC/reload.svg | 4 + src/HTML/PIC/right-arrow.svg | 3 + src/HTML/PIC/smart.png | Bin 0 -> 7693 bytes src/HTML/PIC/table.png | Bin 0 -> 494 bytes src/HTML/PIC/tera-sign.svg | 3 + src/HTML/PIC/tera.ico | Bin 0 -> 9662 bytes src/HTML/PIC/up.png | Bin 0 -> 1632 bytes src/HTML/PIC/viewer.png | Bin 0 -> 2652 bytes src/HTML/PIC/wallet.png | Bin 0 -> 5515 bytes src/HTML/PIC/wallet16.png | Bin 0 -> 461 bytes src/HTML/SOUND/click.mp3 | Bin 0 -> 1088 bytes src/HTML/SOUND/coin.mp3 | Bin 0 -> 4347 bytes src/HTML/SOUND/soundbt.mp3 | Bin 0 -> 1197 bytes src/HTML/blockviewer.html | 131 + src/HTML/chains.html | 1457 ++++++++++ src/HTML/console.html | 515 ++++ src/HTML/dapp-edit.html | 1048 ++++++++ src/HTML/dapp-frame.html | 594 +++++ src/HTML/history.html | 253 ++ src/HTML/mobile-wallet.html | 716 +++++ src/HTML/monitor.html | 832 ++++++ src/HTML/network.html | 530 ++++ src/HTML/password.html | 339 +++ src/HTML/stat.html | 382 +++ src/HTML/tera.ico | Bin 0 -> 9662 bytes src/HTML/wallet.html | 2063 ++++++++++++++ src/HTML/web-wallet.html | 669 +++++ src/a.sh | 6 + src/core/api/api-exchange.ts | 40 + src/core/api/api-wallet.ts | 10 + src/core/base.ts | 390 +++ src/core/block-exchange.ts | 1376 ++++++++++ src/core/block-loader-const.ts | 16 + src/core/block-loader.ts | 1284 +++++++++ src/core/buffer.ts | 364 +++ src/core/code.ts | 204 ++ src/core/connect.ts | 1372 ++++++++++ src/core/constant.ts | 352 +++ src/core/crypto-library.ts | 993 +++++++ src/core/db/block-db.ts | 1026 +++++++ src/core/db/db-row.ts | 229 ++ src/core/db/db.ts | 106 + src/core/geo.ts | 77 + src/core/html-server.ts | 1710 ++++++++++++ src/core/library.ts | 424 +++ src/core/log-strict.ts | 36 + src/core/log.ts | 237 ++ src/core/node.ts | 598 +++++ src/core/rest-loader.ts | 453 ++++ src/core/rest_tables.ts | 73 + src/core/server.ts | 1061 ++++++++ src/core/startlib.ts | 46 + src/core/terahashmining.ts | 202 ++ src/core/transaction-validator.ts | 220 ++ src/core/transfer-msg.ts | 220 ++ src/core/update.ts | 165 ++ src/core/wallet.ts | 226 ++ src/global.d.ts | 548 ++++ src/package.json | 27 + src/process/api-exchange.ts | 363 +++ src/process/dogs.ts | 10 + src/process/main-process.ts | 732 +++++ src/process/pow-process.ts | 91 + src/process/static-process.ts | 373 +++ src/process/tx-process.ts | 354 +++ src/process/web-process.ts | 864 ++++++ src/run-node.bat | 5 + src/run-node.ts | 8 + src/run-nw.ts | 70 + src/run-test.ts | 13 + src/set-test.ts | 14 + src/set.ts | 13 + src/system/accounts.ts | 1426 ++++++++++ src/system/dapp.ts | 61 + src/system/file.ts | 40 + src/system/messager.ts | 123 + src/system/names.ts | 38 + src/system/smart.ts | 1220 +++++++++ tsconfig.json | 10 + 134 files changed, 47644 insertions(+) create mode 100644 .gitignore create mode 100644 package.json create mode 100644 src/HTML/123 create mode 100644 src/HTML/CSS/blockviewer.css create mode 100644 src/HTML/CSS/buttons.css create mode 100644 src/HTML/CSS/codes.css create mode 100644 src/HTML/CSS/history.css create mode 100644 src/HTML/CSS/mobile-wallet.css create mode 100644 src/HTML/CSS/style.css create mode 100644 src/HTML/CSS/wallet.css create mode 100644 src/HTML/JS/client-electron.js create mode 100644 src/HTML/JS/client.js create mode 100644 src/HTML/JS/coinlib.js create mode 100644 src/HTML/JS/crypto-client.js create mode 100644 src/HTML/JS/dapp-inner.js create mode 100644 src/HTML/JS/diagram.js create mode 100644 src/HTML/JS/highlight-html.js create mode 100644 src/HTML/JS/highlight-js.js create mode 100644 src/HTML/JS/highlight.js create mode 100644 src/HTML/JS/lexer.js create mode 100644 src/HTML/JS/marked.js create mode 100644 src/HTML/JS/mobile-wallet.js create mode 100644 src/HTML/JS/sec256k1.js create mode 100644 src/HTML/JS/sha3.js create mode 100644 src/HTML/JS/sign-lib-min.js create mode 100644 src/HTML/JS/terahashlib.js create mode 100644 src/HTML/JS/tx-lib.js create mode 100644 src/HTML/JS/wallet-lib.js create mode 100644 src/HTML/JS/wallet-node.js create mode 100644 src/HTML/JS/wallet-web.js create mode 100644 src/HTML/PIC/B.svg create mode 100644 src/HTML/PIC/T.svg create mode 100644 src/HTML/PIC/TeraLogo.svg create mode 100644 src/HTML/PIC/Tera_logo.svg create mode 100644 src/HTML/PIC/Tera_logo2.svg create mode 100644 src/HTML/PIC/add-icon.svg create mode 100644 src/HTML/PIC/address_book.png create mode 100644 src/HTML/PIC/blank.svg create mode 100644 src/HTML/PIC/chains.png create mode 100644 src/HTML/PIC/check.svg create mode 100644 src/HTML/PIC/console.png create mode 100644 src/HTML/PIC/console0.png create mode 100644 src/HTML/PIC/counters.png create mode 100644 src/HTML/PIC/dapp.png create mode 100644 src/HTML/PIC/down-arrow.svg create mode 100644 src/HTML/PIC/down.png create mode 100644 src/HTML/PIC/glass.svg create mode 100644 src/HTML/PIC/info.svg create mode 100644 src/HTML/PIC/invoice.png create mode 100644 src/HTML/PIC/invoice2.png create mode 100644 src/HTML/PIC/key.png create mode 100644 src/HTML/PIC/lock_closed.png create mode 100644 src/HTML/PIC/lock_open.png create mode 100644 src/HTML/PIC/monitor.png create mode 100644 src/HTML/PIC/network.png create mode 100644 src/HTML/PIC/reload.svg create mode 100644 src/HTML/PIC/right-arrow.svg create mode 100644 src/HTML/PIC/smart.png create mode 100644 src/HTML/PIC/table.png create mode 100644 src/HTML/PIC/tera-sign.svg create mode 100644 src/HTML/PIC/tera.ico create mode 100644 src/HTML/PIC/up.png create mode 100644 src/HTML/PIC/viewer.png create mode 100644 src/HTML/PIC/wallet.png create mode 100644 src/HTML/PIC/wallet16.png create mode 100644 src/HTML/SOUND/click.mp3 create mode 100644 src/HTML/SOUND/coin.mp3 create mode 100644 src/HTML/SOUND/soundbt.mp3 create mode 100644 src/HTML/blockviewer.html create mode 100644 src/HTML/chains.html create mode 100644 src/HTML/console.html create mode 100644 src/HTML/dapp-edit.html create mode 100644 src/HTML/dapp-frame.html create mode 100644 src/HTML/history.html create mode 100644 src/HTML/mobile-wallet.html create mode 100644 src/HTML/monitor.html create mode 100644 src/HTML/network.html create mode 100644 src/HTML/password.html create mode 100644 src/HTML/stat.html create mode 100644 src/HTML/tera.ico create mode 100644 src/HTML/wallet.html create mode 100644 src/HTML/web-wallet.html create mode 100755 src/a.sh create mode 100644 src/core/api/api-exchange.ts create mode 100644 src/core/api/api-wallet.ts create mode 100644 src/core/base.ts create mode 100644 src/core/block-exchange.ts create mode 100644 src/core/block-loader-const.ts create mode 100644 src/core/block-loader.ts create mode 100644 src/core/buffer.ts create mode 100644 src/core/code.ts create mode 100644 src/core/connect.ts create mode 100644 src/core/constant.ts create mode 100644 src/core/crypto-library.ts create mode 100644 src/core/db/block-db.ts create mode 100644 src/core/db/db-row.ts create mode 100644 src/core/db/db.ts create mode 100644 src/core/geo.ts create mode 100644 src/core/html-server.ts create mode 100644 src/core/library.ts create mode 100644 src/core/log-strict.ts create mode 100644 src/core/log.ts create mode 100644 src/core/node.ts create mode 100644 src/core/rest-loader.ts create mode 100644 src/core/rest_tables.ts create mode 100644 src/core/server.ts create mode 100644 src/core/startlib.ts create mode 100644 src/core/terahashmining.ts create mode 100644 src/core/transaction-validator.ts create mode 100644 src/core/transfer-msg.ts create mode 100644 src/core/update.ts create mode 100644 src/core/wallet.ts create mode 100644 src/global.d.ts create mode 100644 src/package.json create mode 100644 src/process/api-exchange.ts create mode 100644 src/process/dogs.ts create mode 100644 src/process/main-process.ts create mode 100644 src/process/pow-process.ts create mode 100644 src/process/static-process.ts create mode 100644 src/process/tx-process.ts create mode 100644 src/process/web-process.ts create mode 100644 src/run-node.bat create mode 100644 src/run-node.ts create mode 100644 src/run-nw.ts create mode 100644 src/run-test.ts create mode 100644 src/set-test.ts create mode 100644 src/set.ts create mode 100644 src/system/accounts.ts create mode 100644 src/system/dapp.ts create mode 100644 src/system/file.ts create mode 100644 src/system/messager.ts create mode 100644 src/system/names.ts create mode 100644 src/system/smart.ts create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7fd9f58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +**/node_modules +# roadhog-api-doc ignore +/src/utils/request-temp.js +_roadhog-api-doc + +# production +/dist +/.vscode + +# misc +.DS_Store +npm-debug.log* +yarn-error.log + +/coverage +.idea +yarn.lock +package-lock.json +*bak +.vscode + +# visual studio code +.history +*.log +functions/* +.temp/** + +# umi +.umi +.umi-production + +# screenshot +screenshot +.firebase +.eslintcache + +build diff --git a/package.json b/package.json new file mode 100644 index 0000000..59d6af3 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "devDependencies": { + "@types/node": "^12.6.1", + "typescript": "^3.5.3" + } +} \ No newline at end of file diff --git a/src/HTML/123 b/src/HTML/123 new file mode 100644 index 0000000..bf20623 --- /dev/null +++ b/src/HTML/123 @@ -0,0 +1,162 @@ +‘à ¢­¥­¨¥ ä ©«®¢ mobile-wallet.html ¨ _MOBILE-WALLET.HTML +***** mobile-wallet.html + + + +***** _MOBILE-WALLET.HTML + + + +***** + +***** mobile-wallet.html +
+
+

From:

+ + +***** + +***** mobile-wallet.html + + + +***** _MOBILE-WALLET.HTML + + + +***** + +***** mobile-wallet.html + + 2 000 000 000,00000000--> + + Description: + +***** _MOBILE-WALLET.HTML + + +***** + +***** mobile-wallet.html +
+ + +***** _MOBILE-WALLET.HTML +
+ + +***** + +***** mobile-wallet.html + + +
+***** _MOBILE-WALLET.HTML + + +
+***** + +***** mobile-wallet.html +
+ + +***** _MOBILE-WALLET.HTML +
+
+ +***** + +***** mobile-wallet.html +
+ Item.Name + +***** _MOBILE-WALLET.HTML +
+ Item.Name + +***** + +***** mobile-wallet.html +
+ dApp
+ logo +
+***** _MOBILE-WALLET.HTML +
+ dApp logo +
+***** + diff --git a/src/HTML/CSS/blockviewer.css b/src/HTML/CSS/blockviewer.css new file mode 100644 index 0000000..fe0032b --- /dev/null +++ b/src/HTML/CSS/blockviewer.css @@ -0,0 +1,440 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:400,500,700&subset=cyrillic'); + +:root { + --blue-grey: #445368; + --light-blue: #718CAF; +} + +body { + margin: 0 auto; + box-sizing: border-box; + font-family: "Roboto", "Arial", sans-serif; + + color: #445368; + background: #f2f2f2; +} +main { + max-width: 1200px; + margin: 0 auto; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + +*::placeholder { + color: rgba(0, 0, 0, 0.5); + font-family: "Roboto"; + font-size: 16px; +} + +a { + text-decoration: none; + color: #445368; +} + +a:hover, +a:focus { + color: #718CAF; +} + +.hidden { + display: none; +} + +.btn { + color: #fff; + background: #445368; + + display: block; + padding: 15px 25px; + border: none; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.3); + border-radius: 4px; + + text-decoration: none; + text-transform: uppercase; + font-family: inherit; + font-weight: 500; + font-size: 18px; + line-height: 21px; + cursor: pointer; + text-align: center; +} + +.btn:hover, +.btn:focus { + background: #718CAF; + color: #fff; +} + +.btn[disabled], +.btn.disabled { + opacity: .3; + cursor: not-allowed; +} + + +.reconnect { + background-image: url("./../PIC/reload.svg"); + background-repeat: no-repeat; + background-size: 18px 18px; + background-position: center center; + padding: 5px; + width: 27px; + margin-left: 5px; +} +.reconnect span { + display: none; +} +.grey-btn { + border: none; + background: #F2F2F2; + border-radius: 3px; + font-family: inherit; + font-size: 14px; + line-height: 16px; + color: #000; + height: 27px; + white-space: nowrap; +} + +.header { + background: linear-gradient(270deg, #3D4C61 0%, #445368 100%); + color: #fff; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); +} +.header__wrapper { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + height: 100%; +} + +.header__logo { + margin-right: 2px; + padding: 0 15px; +} +.header__logo-link:hover { + opacity: .5; + cursor: pointer; +} +.header__right { + display: flex; + align-items: center; + position: relative; +} +.header__right select { + /* background: var(--blue-grey); */ + background: transparent; + border: none; + color: #fff; + padding: 5px; + width: 55px; + font-family: inherit; + font-size: 12px; + line-height: 14px; +} +.white-select { + display: none; +} +.header__nav { + width: 100%; +} +.page-pagination { + display: flex; + justify-content: center; + padding-bottom: 15px; + padding-right: 15px; +} +.page-pagination__num { + width: 33%; + margin: 0 5px; +} +.page-pagination .btn { + padding: 0; + white-space: nowrap; + width: 45px; + height: 40px; + margin: 0 5px; +} +.page-pagination .btn:first-of-type { + margin-left: 0; +} +.page-pagination .btn:last-of-type { + margin-right: 0; +} +.back-link { + cursor: pointer; + position: relative; + width: 30px; +} +.back-link span { + display: none; +} +.back-link::before { + content: ''; + display: block; + color: var(--blue-grey); + background: url("./../PIC/right-arrow.svg") no-repeat; + background-size: 18px 18px; + transform: translateY(-50%) rotate(180deg); + height: 18px; + width: 18px; + position: absolute; + left: 15px; + top: 50%; +} +.back-link:hover::before, +.back-link:focus::before { + opacity: .5; +} + + + + + +.back-link--history { + position: absolute; + top: 15px; + font-size: 16px; + line-height: 19px; + font-weight: 400; + text-decoration: none; +} + +.back-link--history::before { + left: 0; +} + +.back-link--history span { + display: block; + padding-left: 23px; +} + +.header__logo--history { + padding: 10px 15px; +} + +.history-page { + position: relative; + padding-bottom: 110px; +} +.history__text-block { + padding: 65px 15px 10px; +} +.history-page__id { + margin-bottom: 7px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + color: #445368; +} +.history-page__id-count { + max-width: 140px; + margin-left: 2px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + text-align-last: left; + color: #445368; + border: none; + background: #f2f2f2; +} +.history-page__description { + margin: 0; + margin-bottom: 17px; + font-size: 12px; + line-height: 14px; + color: rgba(0, 0, 0, 0.5); +} +.history-page__balance { + display: flex; + align-items: center; + + font-size: 14px; + line-height: 16px; + font-weight: 700; +} +.history-page__tera-icon { + margin-left: 5px; +} +.history-page__table { + padding: 15px 0 15px 15px; + background-color: #ffffff; +} +.history-page__table .grid { + width: 100%; + border-collapse: collapse; +} +.history-page__table-wrap { + overflow-x: auto; +} +.history-page__table th { + background: var(--blue-grey); + color: #fff; + border-right: 1px solid rgba(0, 0, 0, 0.1); + height: 30px; + padding: 0 20px 0 10px; + font-size: 16px; + line-height: 19px; + font-weight: 400; + white-space: nowrap; + text-align-last: left; +} +.history-page__table th:first-child { + border-top-left-radius: 5px; +} +.history-page__table th:last-child { + border-top-right-radius: 5px; +} +.history-page__table .grid tr td { + padding: 8px 10px 6px; + font-size: 14px; + line-height: 16px; + white-space: nowrap; + color: #000000; + background-color: #ffffff; + border: 1px solid #C4C4C4; +} +.history-page__table .grid tr td:first-of-type { + text-align: center; +} +.history-page__table .grid tr td.code +{ + white-space: normal; + width: 340px; + min-width:200px; + font-family: "courier new", "times new roman", monospace; + font-size: small; + word-break: break-all; +} + +.history-page__table .grid tr td.hash +{ + white-space: normal; + width: 160px; + font-family: "courier new", "times new roman", monospace; + font-size: small; + word-break: break-all; +} + + + +@media (min-width: 576px) { + .history__text-block { + padding: 65px 33px 10px; + } + .history-page__table { + padding: 15px 33px; + } + .back-link::before { + left: 0; + } +} + +@media (min-width: 768px) { + .header { + height: 60px; + } + .fixed-status .grey-btn { + height: 40px; + padding: 10px; + } + .reconnect { + width: 40px; + margin-left: 15px; + background-position: 11px 11px; + } + .main-logo { + width: 125px; + height: 30px; + } + .back-link { + display: block; + padding-left: 34px; + } + .back-link span { + display: inline; + text-decoration: underline; + } + .back-link::before { + left: 0; + } + .back-link--history span { + padding-left: 0; + } +} + +@media (min-width: 960px) { + .header__logo { + padding-left: 20px; + } + .reconnect.grey-btn { + width: 130px; + margin-left: 15px; + padding-top: 12px; + padding-left: 39px; + background-position: 11px 11px; + } + .reconnect span { + display: inline; + } + .history-page { + padding-right: 40px; + padding-left: 40px; + } + .history__text-block { + padding: 65px 0 10px; + } + .history-page__table { + padding: 15px 0 10px; + } +} + +@media (min-width: 1200px) { + .header__wrapper { + max-width: 1150px; + margin: 0 auto; + } + .history__text-block { + padding-top: 60px; + padding-bottom: 0; + } + .history-page__id { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__id-count { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__description { + margin-bottom: 30px; + font-size: 16px; + line-height: 19px; + text-align: center; + } + .history-page__balance { + justify-content: center; + margin-bottom: 30px; + font-size: 16px; + line-height: 19px; + } + .history-page__table { + padding: 30px 15px; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + background-color: #ffffff; + } + .page-pagination { + padding-bottom: 20px; + } +} diff --git a/src/HTML/CSS/buttons.css b/src/HTML/CSS/buttons.css new file mode 100644 index 0000000..3652ff2 --- /dev/null +++ b/src/HTML/CSS/buttons.css @@ -0,0 +1,201 @@ +/*Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons Buttons*/ + +/*TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader TabHeader*/ +#TabHeader th +{ + /*border: 1px solid black;*/ + width:205px; + + color: white; + background-color: #22547f; + margin: 0; + padding: 0; + height: 34px; +} +.bttab +{ + background-color: black; + vertical-align: middle; + cursor: pointer; + color: white; + width: 100%; + margin: 0; + padding-top: 7px; + height: 100%; +} + + + + + +/*User action*/ +.btdoit +{ + width: 130px; + height: 32px; + line-height: 20px; + margin: 10px; + cursor: pointer; + font-family: monospace; +} + + +.btdoitm +{ + width: 40px; + height: 32px; + line-height: 20px; + margin: 10px; + cursor: pointer; + font-family: monospace; +} + + +/*All buttons*/ +.bt +{ + border: 1px solid black; + background: transparent; + font-weight: 400; + cursor: pointer; +} +.bt:hover,button:hover +{ + filter: brightness(120%); + cursor: pointer; +} + + +.bt:active +{ + cursor: progress; +} + + + + +.btlong +{ + width: 160px; +} + +.btopen +{ + width: 136px; +} + +.btsmall +{ + width: 10px; +} + +#idSendList +{ + width: 800px; + border: 0 solid black; + font-weight: 700; +} + +#PaiListInfo +{ + width: 800px; + height:20px; + text-align: center; +} + +.btinvoice +{ + width: 133px; + min-width: 133px; + max-width: 133px; + height:40px; + white-space: pre-line; + background-image: url('/HTML/PIC/invoice.png'); + background-repeat: no-repeat; + background-size: 16px; +} +.btinvoice_use +{ + width: 110px; + min-width: 110px; + max-width: 110px; + height:62px; +} + + + +#idCounters +{ + background-image: url('/HTML/PIC/counters.png'); + background-repeat: no-repeat; + background-size: 16px; +} + +#idChains +{ + background-image: url('/HTML/PIC/chains.png'); + background-repeat: no-repeat; + background-size: 16px; +} + + + + +#idMonitor +{ + background-image: url('/HTML/PIC/monitor.png'); + background-repeat: no-repeat; + background-size: 16px; +} + +#idConsole +{ + background-image: url('/HTML/PIC/console.png'); + background-repeat: no-repeat; + background-size:16px; +} +#idOpenSmart +{ + background-image: url('/HTML/PIC/smart.png'); + background-repeat: no-repeat; + background-size:16px; +} + +#idNetwork +{ + background-image: url('/HTML/PIC/network.png'); + background-repeat: no-repeat; + background-size:16px; +} + +#idDown +{ + background-image: url('/HTML/PIC/down.png'); + background-repeat: no-repeat; + background-size: 16px; + background-position: right; +} + +#idUp +{ + background-image: url('/HTML/PIC/up.png'); + background-repeat: no-repeat; + background-size: 16px; + background-position: right; + + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(82, 168, 236, 1); +} + + + + +.btexlporer +{ + width: 136px; +} + + +input[type="checkbox"] +{ + vertical-align: middle; +} diff --git a/src/HTML/CSS/codes.css b/src/HTML/CSS/codes.css new file mode 100644 index 0000000..61dbdf1 --- /dev/null +++ b/src/HTML/CSS/codes.css @@ -0,0 +1,90 @@ +/* + +Google Code style (c) Aahan Krish +Some correct by vtools + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #eff5eb; + color: black; +} + +.hljs-comment, +.hljs-quote { + color: #800; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-title, +.hljs-name { + color: #008; +} + +.hljs-variable, +.hljs-template-variable { + color: #660; +} + +.hljs-string, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-regexp { + color: #080; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-meta, +.hljs-number, +.hljs-link { + color: #066; +} + +.hljs-title, +.hljs-doctag, +.hljs-type, +.hljs-attr, +.hljs-built_in, +.hljs-builtin-name, +.hljs-params { + color: #606; +} + +.hljs-attribute, +.hljs-subst { + color: #000; +} + +.hljs-formula { + background-color: #eee; + font-style: italic; +} + +.hljs-selector-id, +.hljs-selector-class { + color: #9B703F +} + +.hljs-addition { + background-color: #baeeba; +} + +.hljs-deletion { + background-color: #ffc8bd; +} + +.hljs-doctag, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/src/HTML/CSS/history.css b/src/HTML/CSS/history.css new file mode 100644 index 0000000..261f923 --- /dev/null +++ b/src/HTML/CSS/history.css @@ -0,0 +1,440 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:400,500,700&subset=cyrillic'); + +:root { + --blue-grey: #445368; + --light-blue: #718CAF; +} + +body { + margin: 0 auto; + box-sizing: border-box; + font-family: "Roboto", "Arial", sans-serif; + + color: #445368; + background: #f2f2f2; +} +main { + max-width: 1200px; + margin: 0 auto; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + +*::placeholder { + color: rgba(0, 0, 0, 0.5); + font-family: "Roboto"; + font-size: 16px; +} + +a { + text-decoration: none; + color: #445368; +} + +a:hover, +a:focus { + color: #718CAF; +} + +.hidden { + display: none; +} + +.btn { + color: #fff; + background: #445368; + + display: block; + padding: 15px 25px; + border: none; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.3); + border-radius: 4px; + + text-decoration: none; + text-transform: uppercase; + font-family: inherit; + font-weight: 500; + font-size: 18px; + line-height: 21px; + cursor: pointer; + text-align: center; +} + +.btn:hover, +.btn:focus { + background: #718CAF; + color: #fff; +} + +.btn[disabled], +.btn.disabled { + opacity: .3; + cursor: not-allowed; +} + + +.reconnect { + background-image: url("./../PIC/reload.svg"); + background-repeat: no-repeat; + background-size: 18px 18px; + background-position: center center; + padding: 5px; + width: 27px; + margin-left: 5px; +} +.reconnect span { + display: none; +} +.grey-btn { + border: none; + background: #F2F2F2; + border-radius: 3px; + font-family: inherit; + font-size: 14px; + line-height: 16px; + color: #000; + height: 27px; + white-space: nowrap; +} + +.header { + background: linear-gradient(270deg, #3D4C61 0%, #445368 100%); + color: #fff; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); +} +.header__wrapper { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + height: 100%; +} + +.header__logo { + margin-right: 2px; + padding: 0 15px; +} +.header__logo-link:hover { + opacity: .5; + cursor: pointer; +} +.header__right { + display: flex; + align-items: center; + position: relative; +} +.header__right select { + /* background: var(--blue-grey); */ + background: transparent; + border: none; + color: #fff; + padding: 5px; + width: 55px; + font-family: inherit; + font-size: 12px; + line-height: 14px; +} +.white-select { + display: none; +} +.header__nav { + width: 100%; +} +.header__wallet-set { + margin-left: 5px; +} +.header__wallet-link { + color: rgba(255, 255, 255, 0.6); + display: block; + padding: 13px 15px 9px 15px; +} +.header__wallet-link:hover, +.header__wallet-link:focus { + background: #55657C; +} +.header__wallet-link span { + display: none; +} +.header__wallet-link:active, +.header__wallet-link.active { + box-shadow: inset 0px 4px 0px rgba(255, 255, 255, 0.25); +} +.dapps-page__pagination, +.page-pagination { + display: flex; + justify-content: center; + padding-bottom: 15px; + padding-right: 15px; +} +.page-pagination__num { + width: 33%; + margin: 0 5px; +} +.page-pagination .btn { + padding: 0; + white-space: nowrap; + width: 45px; + height: 40px; + margin: 0 5px; +} +.page-pagination .btn:first-of-type { + margin-left: 0; +} +.page-pagination .btn:last-of-type { + margin-right: 0; +} + +.back-link { + position: relative; + width: 30px; + cursor: pointer; +} +.back-link span { + display: none; +} +.back-link::before { + content: ''; + display: block; + color: var(--blue-grey); + background: url("./../PIC/right-arrow.svg") no-repeat; + background-size: 18px 18px; + transform: translateY(-50%) rotate(180deg); + height: 18px; + width: 18px; + position: absolute; + left: 15px; + top: 50%; +} +.back-link:hover::before, +.back-link:focus::before { + opacity: .5; +} + + + +.header__logo--history { + padding: 10px 15px; +} + +.back-link--history { + position: absolute; + top: 15px; + font-size: 16px; + line-height: 19px; + line-height: 19px; + font-weight: 400; + text-decoration: none; +} + +.back-link--history::before { + left: 0; +} + +.back-link--history span { + display: block; + padding-left: 23px; +} + +.history-page { + padding-bottom: 110px; +} +.history__text-block { + position: relative; + padding: 10px 15px 10px; +} +.history-page__id { + margin-bottom: 7px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + color: #445368; +} +.history-page__id-count { + max-width: 140px; + margin-left: 2px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + text-align-last: left; + color: #445368; + border: none; + background: #f2f2f2; +} +.history-page__description { + margin: 0; + margin-bottom: 17px; + font-size: 12px; + line-height: 14px; + color: rgba(0, 0, 0, 0.5); +} +.history-page__balance { + display: flex; + align-items: center; + + font-size: 14px; + line-height: 16px; + font-weight: 700; +} +.history-page__tera-icon { + margin-left: 5px; +} +.history-page__table { + padding: 15px 0 15px 15px; +} +.history-page__table .grid { + width: 100%; + border-collapse: collapse; +} +.history-page__table-wrap { + overflow-x: auto; +} +.history-page__table th { + background: var(--blue-grey); + color: #fff; + border-right: 1px solid rgba(0, 0, 0, 0.1); + height: 30px; + padding: 0 20px 0 10px; + font-size: 16px; + line-height: 19px; + font-weight: 400; + white-space: nowrap; + text-align-last: left; +} +.history-page__table th:first-child { + border-top-left-radius: 5px; +} +.history-page__table th:last-child { + border-top-right-radius: 5px; +} +.history-page__table .grid tr td { + padding: 2px 10px 0px; + font-size: 14px; + line-height: 16px; + color: #000000; + background-color: #ffffff; + border: 1px solid #C4C4C4; +} + +.history-page__table .grid tr th.direct { + max-width:30px; +} + +.history-page__table .grid tr td.date +{ + white-space: nowrap; +} + + +.history-page__table .grid tr td:first-of-type { + text-align: center; +} + +.history-page__table .grid tr td:first-of-type b { + font-size: 16px!important; + font-weight: 700!important; +} +.history-page__table .grid tr td.desc { + max-width: 170px; + word-break: break-all; +} + +@media (min-width: 576px) { + .history__text-block { + padding: 10px 33px 10px; + } + .history-page__table { + padding: 15px 33px; + } + .back-link::before { + left: 0; + } +} + +@media (min-width: 768px) { + .header { + height: 60px; + } + .main-logo { + width: 125px; + height: 30px; + } + .back-link { + display: block; + padding-left: 34px; + } + .back-link span { + display: inline; + text-decoration: underline; + } + .back-link::before { + left: 0; + } + .back-link--history span { + padding-left: 0; + } +} + +@media (min-width: 960px) { + .header__logo { + padding-left: 20px; + } + .history-page { + padding-right: 40px; + padding-left: 40px; + } + .history__text-block { + padding: 10px 0 10px; + } + .history-page__table { + padding: 15px 0 10px; + } +} + +@media (min-width: 1200px) { + .header__wrapper { + max-width: 1150px; + margin: 0 auto; + } + .history__text-block { + padding-top: 10px; + padding-bottom: 0; + } + .history-page__id { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__id-count { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__description { + margin-bottom: 20px; + font-size: 16px; + line-height: 19px; + min-height: 20px; + text-align: center; + } + .history-page__balance { + justify-content: center; + margin-bottom: 30px; + font-size: 16px; + line-height: 19px; + } + .history-page__table { + padding: 30px 15px; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + background-color: #ffffff; + } + .page-pagination { + padding-bottom: 20px; + } +} \ No newline at end of file diff --git a/src/HTML/CSS/mobile-wallet.css b/src/HTML/CSS/mobile-wallet.css new file mode 100644 index 0000000..e7e85a5 --- /dev/null +++ b/src/HTML/CSS/mobile-wallet.css @@ -0,0 +1,2744 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:400,500,700&subset=cyrillic'); + +:root { + --blue-grey: #445368; + --light-blue: #718CAF; + --fill--password:#000; +} + + + + +body { + margin: 0 auto; + box-sizing: border-box; + font-family: "Roboto", "Arial", sans-serif; + + color: #445368; + background: #f2f2f2; +} +main { + max-width: 1200px; + margin: 0 auto; +} + +*, +*::before, +*::after { + box-sizing: inherit; +} + +*::placeholder { + color: rgba(0, 0, 0, 0.5); + font-family: "Roboto"; + font-size: 16px; +} + +a { + text-decoration: none; + color: #445368; +} + +a:hover, +a:focus { + color: #718CAF; +} + +.hidden { + display: none; +} +.small-text { + font-size: 10px; + line-height: 12px; +} +.text-center { + text-align: center; +} +#overlay { + background: rgba(68, 83, 104, 0.65); + position: fixed; + width: 100%; + height: 100vh; + top: 0; + display: none; +} + +label[for=load-key] { + font-weight: 500; +} +textarea { + resize: none; +} +.currentBlockNum { + font-size: 14px; + padding: 15px; + padding-bottom: 0; + margin-bottom: 15px; +} +.currentBlockNum span { + display: inline-block; + min-width: 220px; +} +.currentBlockNum p { + display: flex; + justify-content: space-between; + margin-top: 8px; + margin-bottom: 8px; +} +.currentBlockNum p:first-child { + margin-top: 0; +} +.currentBlockNum p:last-child { + margin-bottom: 0; +} +.btn { + color: #fff; + background: #445368; + + display: block; + padding: 15px 25px; + border: none; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.3); + border-radius: 4px; + + text-decoration: none; + text-transform: uppercase; + font-family: inherit; + font-weight: 500; + font-size: 18px; + line-height: 21px; + cursor: pointer; + text-align: center; +} + +.btn:hover, +.btn:focus { + background: #718CAF; + color: #fff; +} + +.btn[disabled], +.btn.disabled { + opacity: .3; + cursor: not-allowed; +} + +.btn span { + opacity: .4; +} + +.btn--white { + background: #fff; + color: #445368; +} + +.btn--white:hover, +.btn--white:focus { + background: #F5F5F5; + color: #445368; +} + +.btn--full-width { + width: 100%; + border-radius: 0px; +} +.btn--270 { + max-width: 270px; + border-radius: 4px; +} + +.btn--450 { + max-width: 450px; + margin: 0 auto; +} + +.btn--center { + margin: 0 auto; +} + +.grey-btn { + border: none; + background: #F2F2F2; + border-radius: 3px; + font-family: inherit; + font-size: 14px; + line-height: 16px; + color: #000; + height: 27px; + + white-space: nowrap; +} + +.btn-no-bg { + color: var(--blue-grey); + background: none; + border: none; + text-transform: uppercase; + font-weight: 500; + font-size: 16px; + line-height: 19px; +} + +.prod-card__drop-btn:hover, +.prod-card__drop-btn:focus { + background: rgba(0, 0, 0, 0.1); +} + +.title { + font-weight: 700; + font-size: 20px; + line-height: 23px; +} + +.welcome, +.wallet-settings, +.wallet-settings--info, +.accounts-info, +.accounts-info__add, +.accounts-info__empty, +.send-page, +.dapps-page, +.explorer-page { + padding-bottom: 50px; +} + +.explorer-page { + padding-bottom: 100px; +} + +.header { + background: linear-gradient(270deg, #3D4C61 0%, #445368 100%); + color: #fff; + box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); +} +.header__wrapper { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; +} + +.header__logo { + margin-right: 2px; + padding: 0 15px; +} +.header__logo-link:hover { + opacity: .5; + cursor: pointer; +} +.header__right { + display: flex; + align-items: center; + position: relative; +} +.header__right select { + /* background: var(--blue-grey); */ + background: transparent; + border: none; + color: #fff; + padding: 5px; + width: 55px; + font-family: inherit; + font-size: 12px; + line-height: 14px; +} +.white-select { + display: none; +} +.header__nav { + width: 100%; +} +.header__wallet-set { + margin-left: 5px; +} +.header__wallet-link { + color: rgba(255, 255, 255, 0.6); + display: block; + padding: 13px 15px 9px 15px; +} +.header__wallet-link:hover, +.header__wallet-link:focus { + background: #55657C; +} +.header__wallet-link span { + display: none; +} +.header__wallet-link:active, +.header__wallet-link.active { + box-shadow: inset 0px 4px 0px rgba(255, 255, 255, 0.25); + } + + +.nav-tabs__list { + list-style: none; + padding: 0; + margin: 0; + + display: flex; + justify-content: space-between; + + font-size: 13px; +} + +.nav-tabs__tab { + background: linear-gradient(270deg, #3D4C61 0%, #445368 100%); + width: 100%; + text-align: center; +} + +.nav-tabs__link { + color: rgba(255, 255, 255, 0.6); + text-decoration: none; + padding: 17px 14px 18px 14px; + display: block; +} + +.tab-link:hover { + background: linear-gradient(180deg, #3D4C61 0%, #445368 100%); + opacity: .6; + cursor: pointer; +} + +.tab-link.active, +.tab-link:focus { + color: #fff; + background: #55657C; + box-shadow: inset 0px 4px 0px rgba(255, 255, 255, 0.25); + cursor: pointer; +} + +.welcome { + text-align: center; + padding: 50px 15px 35px; +} + +.welcome__link { + max-width: 270px; + margin: 0 auto; +} + +.social-list { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: 0 auto; + max-width: 300px; + list-style-type: none; + padding: 50px 0 80px; + font-weight: 500; +} + +.social-list__item { + text-align: center; + padding: 10px 0; + +} + +.social-list__item a { + padding: 0 15px; + border-right: 1px solid rgba(68, 83, 104, .2); +} + +.social-list__item:nth-child(3n) a { + border-right: none; +} + +.fixed-status { + background: var(--blue-grey); + color: rgba(255, 255, 255, 1); + font-size: 12px; + padding: 12px 10px 11px 10px; + padding-left: 17px; + + position: fixed; + bottom: 0; + left: 0; + + width: 100%; + font-family: "Roboto", sans-serif; +} +.fixed-status__wrap { + display: flex; + align-items: center; + max-width: 1170px; + margin: 0 auto; +} + +.fixed-status__status { + max-width: 330px; + margin-right: auto; + padding-right: 10px; +} +.fixed-status .grey-btn { + padding-left: 3px; + font-size: 12px; + line-height: 14px; +} + +.reconnect { + background-image: url("./../PIC/reload.svg"); + background-repeat: no-repeat; + background-size: 18px 18px; + background-position: center center; + padding: 5px; + width: 27px; + margin-left: 5px; +} +.reconnect span { + display: none; +} + + +.key-field { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + font-size: 16px; + line-height: 18px; + padding-bottom: 16px; + color: #445368; +} + +.key-field:first-of-type { + padding-top: 15px; +} + +.key-field__title { + font-weight: 500; + margin: 0 auto 0 0; + padding-left: 15px; +} + +.key-field__title span { + opacity: .6; +} +@media (max-width: 445px) +{ + .key-field__title--pay { + margin-bottom: 5px; + } +} + +.key-field__input { + width: 100%; + padding: 15px 15px 13px 14px; + margin: 10px 0 0; + border: 1px solid rgba(0, 0, 0, 0.1); + font-family: inherit; + font-size: 16px; + line-height: 18px; + color: #445368; +} +.key-field__input--select { + padding: 11px 15px 11px 10px; + font-size: 18px; + line-height: 21px; +} +.key-field__input--enter { + padding-top: 20px; + padding-bottom: 18px; +} + +.key-field__btn { + margin-right: 15px; +} + +.key-field__btn--with-icon { + display: flex; + align-items: center; +} +.key-field__btn--with-icon svg { + margin-left: 10px; +} + +.key-field__textarea { + width: 100%; + background: #FFFFFF; + border: 1px solid rgba(0, 0, 0, 0.1); + min-height: 50px; + padding: 21px 15px 14px 15px; + margin-top: 8px; + font-family: "Roboto", "Arial", sans-serif; + font-size: 16px; + line-height: 18px; + color: #445368; +} +.key-field__textarea--mobile { + max-height: 50px; + padding-top: 15px; +} + +.key-field__select::placeholder, +.key-field__input::placeholder, +.key-field__textarea::placeholder { + color: rgba(68, 83, 104, .5); + font-size: 16px; + font-family: "Roboto", "Arial", sans-serif; + color: #445368; + opacity: 0.5; +} + +.key-field__select { + width: 100%; + border: 1px solid rgba(0, 0, 0, 0.1); + padding: 12px 15px; + margin-top: 5px; + background: #fff; + font-family: inherit; + font-size: 16px; + line-height: 18px; + color: #445368; +} +.key-field__key-place { + word-wrap: break-word; + padding: 10px 15px; + width: 100%; + margin-bottom: 0; +} +.back-link { + position: relative; + width: 30px; +} +.back-link span { + display: none; +} +.back-link::before { + content: ''; + display: block; + color: var(--blue-grey); + background: url("./../PIC/right-arrow.svg") no-repeat; + background-size: 18px 18px; + transform: translateY(-50%) rotate(180deg); + height: 18px; + width: 18px; + position: absolute; + left: 15px; + top: 50%; +} +.back-link:hover::before, +.back-link:focus::before { + opacity: .5; +} +.wallet-settings__title-wrap { + position: relative; + display: flex; + align-items: center; + margin-bottom: 15px; +} +.wallet-settings__title, +.accounts-info__title { + display: block; + padding: 15px 20px; + text-align: center; + margin: 0 auto; +} +.accounts-info__title { + margin-left: calc(50% - 133px); +} +.wallet-settings__btns-wrapper { + display: flex; + /*flex-wrap: wrap;*/ + align-items: center; + justify-content: center; + padding: 0 20px 20px; +} +.wallet-settings__ok-btns { + padding-top: 30px; + flex-wrap: wrap; +} +.wallet-settings__ok-btns .btn { + width: 100%; +} + +.wallet-settings__btns-wrapper .btn { + margin: 10px 10px; + white-space: nowrap; + min-width: 125px; + text-align: center; +} + +.wallet-settings__go-btn { + margin: 0 auto; + min-width: 270px; + text-align: center; + + margin-bottom: 60px; + margin-top: auto; +} + +.wallet-settings__hidden-field { + border-top: 1px dotted var(--blue-grey); + width: 100%; + margin: 20px 15px 5px; +} + +.wallet-settings__btn-270.btn { + max-width: 270px; + margin: 0 auto; + border-radius: 4px; +} + +.accounts-info__counter { + text-transform: uppercase; + padding: 15px; + margin: 0; +} + +.accounts-info__btn { + margin: 30px auto 50px; +} + +.accounts-info__add-btn { + margin-top: 44px; + max-width: 330px; +} + +.accounts-info__to-send-link { + padding: 15px; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + display: block; + position: relative; + width: 100%; + margin-bottom: 15px; + font-family: inherit; + font-size: 16px; + line-height: 18px; +} + +.accounts-info__to-send-link::after { + content: ''; + color: var(--blue-grey); + background: url("./../PIC/right-arrow.svg") no-repeat; + position: absolute; + background-size: 17px 17px; + transform: translateY(-50%); + height: 17px; + width: 17px; + right: 15px; + top: 50%; +} + +.accounts-info__to-send-link:hover::after, +.accounts-info__to-send-link:focus::after { + opacity: .5; +} + +.accounts-info__counter-wrapper { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + -ms-align-items: center; + align-items: center; + padding: 0 15px 15px; +} + +.accounts-info__counter-wrapper .title { + margin: 0; + margin-right: -30px; +} + +.accounts-info__empty img { + width: 100%; + display: none; +} +.accounts-info__empty-img img:first-child { + display: block; +} + +.prod-list { + list-style-type: none; + padding: 0; + margin: 0; +} +.prod-card { + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + background: #FFFFFF; + margin-bottom: 5px; +} +.prod-card__dapp-icon { + margin-right: 2px; +} + +.prod-card__first-line, +.prod-card__second-line, +.prod-card__footer { + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: space-between; + white-space: nowrap; +} + +.prod-card__first-line { + padding: 15px; +} + +.prod-card__second-line { + padding: 0 15px 15px; +} + +.prod-card__footer { + padding: 15px; +} + +.prod-card__id { + color: #445368; + opacity: 0.5; + margin-right: 15px; + min-width: 56px; +} +.prod-card__id:first-of-type { + min-width: 45px; +} +.prod-card__id--desktop { + display: none; +} +.prod-card__id--mobile { + display: none; +} +.prod-card__id--mobile-active { + display: none; +} +@media (max-width: 960px) { + .prod-card__id--mobile { + display: block; + } +} +@media (min-width: 960px) { + .prod-card__id--desktop { + display: block; + } +} +.prod-card__descr { + width: 100%; + text-overflow: ellipsis; + overflow: hidden; +} + +.prod-card__heading { + font-size: 21px; + line-height: 25px; + font-weight: bold; + color: var(--blue-grey); + + display: flex; + -ms-align-items: center; + align-items: center; + justify-content: flex-end; + width: 100%; + /*padding-bottom: 15px;*/ +} +.prod-card__currency { + margin-left: 5px; + position: relative; +} +.prod-card__currency--with-dot:after { + content: ''; + position: absolute; + top: 0; + right: 0; + background: var(--blue-grey); + width: 5px; + height: 5px; + border-radius: 50%; +} +.prod-card__footer-empty { + position: relative; + padding-left: 40px; + color: rgba(0, 0, 0, 0.2);; +} +.prod-card__footer-empty:before { + content: ''; + position: absolute; + background-image: url("./../PIC/add-icon.svg"); + background-size: 30px 30px; + top: 50%; + transform: translateY(-50%); + left: 0; + width: 30px; + height: 30px; + border-radius: 50%; +} +.prod-card__heading sup { + font-size: 13px; + line-height: 15px; + vertical-align: unset; +} + +.prod-card__dropdown { + cursor: pointer; + position: absolute; + right: 38px; + top: 10px; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.15); + background: #fff; + border-radius: 4px; + width: 197px; + z-index: 20; +} +.prod-card__dropdown a { + display: block; + padding: 10px 15px; +} +.prod-card__drop-btn +{ + cursor: pointer; + padding: 6px 12px; + border-radius: 4px; +} +.accounts-info__accounts { + padding: 0 15px; + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + background: #FFFFFF; +} +.accounts-info__accounts .prod-card { + /*padding: 0 15px;*/ + box-shadow: none; + background: transparent; + font-size: 12px; + line-height: 14px; +} +.accounts-info__accounts .prod-card__heading { + width: 50%; +} +.prod-card__coins-count { + font-weight: normal; + font-size: 14px; + line-height: 16px; + padding: 0 15px; + display: inline; + text-align: right; +} +.accounts-info__accounts .prod-card__id { + opacity: 1; + text-decoration: underline; + margin-right: auto; +} +.accounts-info__accounts .prod-card__first-line { + flex-wrap: wrap; +} +.accounts-info__accounts .prod-card__second-line { + padding: 15px; +} +.prod-card__footer { + border-top: 1px solid rgba(68, 83, 104, 0.1); + position: relative; +} + +.prod-card__link +{ + cursor: pointer; + display: flex; + -ms-align-items: center; + align-items: center; + width: 100%; +} + +.prod-card__link:hover:after { + opacity: .5; +} + +.prod-card__link--empty { + color: rgba(68, 83, 104, 0.5); +} + +.prod-card__link--empty:before { + background: url("./../PIC/chain-off.svg") no-repeat; + opacity: .2; +} +.prod-card__link--info::after { + display: none; +} +.prod-card__link--info::before { + content: ""; + position: absolute; + top: 0; + left: -28px; + background: url("./../PIC/info.svg") no-repeat; + width: 18px; + height: 18px; +} +.prod-card__link--info { + position: relative; + width: auto; + margin-left: auto; +} +.accounts-info__total { + padding: 20px 15px 30px; +} + +.prod-card--line { + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: space-between; + padding: 10px 0; + margin-bottom: 0; +} +.prod-card--line:not(:last-child) { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); +} +.prod-card--line .prod-card__first-line { + width: 100%; + padding: 0 15px 0 0; +} +.prod-card--line .prod-card__footer { + border: 0; + border-left: 1px solid rgba(0, 0, 0, 0.1); + padding: 0 0 0 15px; + display: flex; + align-items: center; + +} +.prod-card--line .prod-card__footer-wrap { + width: 100%; + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + -ms-align-items: center; + align-items: center; + justify-content: flex-start; +} + +.prod-card__dapp-name { + margin-left: 10px; + margin-right: auto; +} + +.prod-card__dapp-text { + font-size: 14px; + line-height: 16px; + color: rgba(0, 0, 0, 0.2); +} + +.total-info__item { + display: -webkit-flex; + display: -moz-flex; + display: -ms-flex; + display: -o-flex; + display: flex; + justify-content: space-between; + width: 100%; + font-size: 14px; + line-height: 16px; + padding: 5px 0; +} + +.total-info__item dd { + font-weight: bold; +} +.send-page__send-btn { + border-radius: 4px; +} + +.send-page__send-btn-wrp { + padding: 0 15px 80px; +} +.send-page__setting .title, +.dapps-page .title { + display: none; +} + +.light-grey-text { + color: rgba(0, 0, 0, 0.5); +} +.lighter-grey-text { + color: rgba(0, 0, 0, 0.2); +} +.grey-blue-text { + color: var(--blue-grey); +} +.confirm-info { + font-size: 16px; + max-width: 950px; +} +.confirm-info__line { + display: flex; + align-items: flex-start; + padding: 15px; +} +.confirm-info__line .btn-no-bg { + margin-left: auto; +} +.confirm-info__line p { + margin: 0; +} +.confirm-info__title { + min-width: 90px; + text-align: right; + font-weight: 500; +} +.confirm-info__descr { + text-align: left; + margin-left: 3%; + font-weight: 500; +} +.confirm-info__descr p { + padding-top: 10px; +} +.send-page__btns-wrap { + display: flex; + justify-content: space-between; + padding: 20px 15px 80px; +} +.send-page__btns-wrap .btn { + width: 48%; + margin: 0; +} + +.dapps-page__field.key-field { + padding-top: 0; + margin-top: 5px; +} +.dapps-page__field select { + padding: 15px; + background: #fff; +} +.dapps-page__pagination, +.page-pagination { + display: flex; + justify-content: center; + padding-bottom: 15px; + padding-right: 15px; +} +.page-pagination__num { + width: 33%; + margin: 0 5px; +} +.dapps-page__pagination input, +.page-pagination input { + margin: 0 5px; + border: 1px solid rgba(0, 0, 0, 0.1); +} +.dapps-page__page-btns, +.page-pagination .btn { + padding: 0; + white-space: nowrap; + width: 45px; + height: 40px; + margin: 0 5px; +} +.page-pagination .btn:first-of-type { + margin-left: 0; +} +.page-pagination .btn:last-of-type { + margin-right: 0; +} + + +.prod-card__second-line-left ol { + margin-top: 10px; + border-radius: 3px; + padding: 0; + list-style-position: inside; + display: flex; + flex-wrap: wrap; +} +.prod-card__second-line-left li { + border: 1px solid rgba(68, 83, 104, 0.1); + padding: 5px 10px; + margin: 0 10px 10px 0; + border-radius: 4px; +} +.prod-card__second-line-left p { + white-space: normal; + display: none; + padding-top: 5px; + margin-top: 0; +} +.dapp-modal__ok-token:before { + content: ""; + background: url("./../PIC/check.svg") no-repeat; + background-size: 20px 15px; + width: 20px; + height: 15px; + display: inline-block; + margin-right: 10px; +} +@media (max-width: 440px) { + .dapp-modal .modal__close { + left: -15px; + top: -15px; + } +} +@media (max-width: 960px) { + .modal__title-wrap { + margin-right: auto; + } +} + +.dapp-modal { + padding-bottom: 100px; +} + +.modal { + padding: 30px; + background: #fff; + border-radius: 3px; + color: #000; + position: fixed; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.15); + margin: 0 auto; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + max-width: 570px; + width: 87%; + z-index: 10; +} +.dapp-modal { + top: calc(50% - 210px); + left: 20px; + right: 20px; + transform: none; +} +.modal h3 { + font-size: 20px; + line-height: 23px; + letter-spacing: 0.02em; + margin: 15px 0 10px; + color: var(--blue-grey); +} +.modal__header { + display: flex; +} +.password-modal { + display: none; + padding: 15px 15px 45px 15px; + padding-top: 15px; + padding-bottom: 45px; + border-radius: 5px; +} +.password-modal__title { + width: 100%; + margin-top: 0; + margin-bottom: 10px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + text-align: center; + text-transform: uppercase; + color: #445368; +} +.password-modal__subtitle { + width: 100%; + margin-top: 0; + margin-bottom: 30px; + + font-size: 16px; + line-height: 18px; + text-align: center; + color: rgba(0, 0, 0, 0.5); +} +.password-modal--change .password-modal__input--margin { + margin-bottom: 30px; +} +.password-modal--set .btn, +.password-modal--change .btn { + max-width: 48%; + width: 48%; +} +.password-modal__buttons--one .btn { + width: 100%; +} +.password-modal__subtitle--red { + color: #eb5757; +} +.password-modal__input { + width: 100%; + margin-bottom: 10px; + padding: 11px 15px; + font-size: 18px; + line-height: 21px; + color: rgba(0, 0, 0, 0.2); + border: 1px solid rgba(0, 0, 0, 0.1); + border-radius: 4px; +} +.password-modal__input:last-of-type { + margin-bottom: 30px; +} +.password-modal__buttons { + display: flex; + justify-content: space-between; + flex-wrap: wrap; +} +.password-modal__buttons--one { + justify-content: center; +} +.password-modal__buttons .btn { + font-size: 16px; + line-height: 19px; +} +.password-modal__link { + display: block; + width: 100%; + margin-top: 30px; + font-size: 16px; + line-height: 19px; + font-weight: 500; + text-align: center; + text-transform: uppercase; + text-decoration: underline; + color: rgba(0, 0, 0, 0.5); +} +@media (max-width: 359px) { + .password-modal__buttons .btn { + padding: 15px 20px; + } + .accounts-info__add-btn { + max-width: 320px; + } +} +@media (min-width: 500px) { + .password-modal__buttons .btn { + width: 100%; + } +} +.modal__ol { + list-style-position: inside; + display: flex; + flex-wrap: wrap; + padding: 0; +} +.modal__category { + padding: 5px 10px; + border: 1px solid rgba(68, 83, 104, 0.1); + margin: 0 10px 10px 0; +} +.dapp-modal__token-status { + margin: 15px 0 0; +} +.dapp-modal__token-status .light-grey-text { + color: rgba(0, 0, 0, 0.2); +} +.modal__img-wrap { + padding: 10px 15px; + text-align: center; +} +.modal__img-wrap img { + display: block; + margin-bottom: 5px; +} + +.modal__btns-wrap { + display: flex; + justify-content: center; + padding: 30px 0 0; +} +.modal__close { + position: absolute; + width: 50px; + height: 50px; + box-shadow: 0px 5px 10px rgba(68, 83, 104, 0.15); + top: -25px; + left: -25px; + border: 0; + border-radius: 50%; +} +.modal__close::before, +.modal__close::after { + content: ""; + position: absolute; + left: 24px; + height: 35px; + width: 2px; + top: 7px; + background-color: var(--blue-grey); +} + +.modal__close:before { + transform: rotate(45deg); +} + +.modal__close:after { + transform: rotate(-45deg); +} +.modal__btns-wrap .btn { + margin: 0 15px; + padding: 14px 10px; + min-width: 125px; +} +.modal-lock { + position: absolute; + top: 17px; + right: 26px; + display: block; + width: 14px; + height: 18px; +} +.modal-lock2 { + position: absolute; + top: 18px; + right: 10px; + display: block; + width: 10px; + height: 20px; +} + + +.def-list__item { + display: flex; + align-items: center; +} +.def-list__item dt { + min-width: 90px; + margin-right: 30px; +} + +.def-list__item a { + text-decoration: underline; +} +.def-list__item dd { + margin: 5px 0; +} + +.explorer-page__explore { + margin-top: 10px; + text-align: left; + position: relative; + font-weight: bold; + font-size: 20px; + line-height: 23px; + text-transform: none; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + padding: 18px 12px 17px 15px; +} + +.explorer-page__explore:last-of-type { + margin-bottom: 20px; +} + +.explorer-page__explore::after { + content: ""; + display: block; + background: url("./../PIC/down-arrow.svg") no-repeat; + background-size: 20px 15px; + width: 20px; + height: 15px; + position: absolute; + top: 50%; + right: 13px; + transform: translateY(-50%); +} +.explorer-page__explore.btpress { + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: none; +} +.explorer-page__explore.btpress::after { + transform: translateY(-50%) rotate(180deg); +} + +.dapps__table { + width: 100%; +} +.dapps__table tr { + margin-bottom: 5px; +} +.dapps__table .prod-card__link--info { + font-size: 14px; + line-height: 16px; +} +.dapps__table .prod-card__id { + font-size: 16px; + line-height: 19px; + opacity: 1; +} +.dapps__table .prod-card__heading { + font-size: 20px; + line-height: 23px; +} +.dapps__table tr:first-of-type .dapp_card { + padding-bottom: 15px; +} + +.explorer-page__table { + background: #fff; + padding: 15px 0 15px 15px; + display: none; +} +.explorer-page__table-wrap { + overflow-x: scroll; +} +.dapps-page .explorer-page__table-wrap { + overflow-x: hidden; +} +.explorer-page__explore.btpress + .explorer-page__table { + display: block; +} +.explorer-page__table .grid { + border-collapse: collapse; + border-spacing: 1px; +} +.explorer-page__table th { + background: var(--blue-grey); + color: #fff; + border-right: 1px solid rgba(0, 0, 0, 0.1); + height: 30px; + padding: 0 40px; + font-size: 16px; + line-height: 19px; + font-weight: 400; + white-space: nowrap; +} +.explorer-page__table th:first-child { + border-top-left-radius: 5px; +} +.explorer-page__table th:last-child { + border-top-right-radius: 5px; +} + +.explorer-page__table td { + padding: 5px; + border: 1px solid #C4C4C4; + text-align: center; + font-size: 14px; + line-height: 16px; + letter-spacing: 0.02em; +} + +.explorer-page__table td:nth-child(2) { + text-align: right; +} +.explorer-page__table td:nth-child(4) { + text-align: left; +} +td.hash { + font-size: 10px; + line-height: 12px; + letter-spacing: 0.02em; + width: 220px; + min-width: 120px; + word-break: break-all; +} +.history-page__table .grid tr td.code +{ + white-space: normal; + width: 340px; + min-width:200px; + font-family: "courier new", "times new roman", monospace; + font-size: small; + word-break: break-all; +} +.explorer-page__table td.pubkey { + width: 215px; + min-width: 215px; +} + +.explorer-page__table td a { + text-decoration: underline; +} + +.explorer-page__table .num button { + background: none; + border: none; + color: var(--blue-grey); + text-decoration: underline; +} + +.explorer-page__diagramms canvas { + width: 100%; +} +.explorer-page__diagramms b { + padding-left: 15px; +} +.explorer-page__diagramms .delete { + margin-left: 10px; + margin-bottom: 10px; + background: #fff; + border: none; + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); +} +.addresses-modal { + padding-bottom: 0; +} +.addresses-modal .title { + text-transform: uppercase; + text-align: center; + color: #445368; + margin: 0; + padding-bottom: 15px; + font-size: 20px; +} +.addresses-modal__input { + padding: 14px 15px; + width: 100%; + border: 1px solid rgba(0, 0, 0, 0.1); + + background: url("./../PIC/glass.svg") no-repeat; + -webkit-background-size: 18px 18px; + background-size: 18px 18px; + background-position: 98% 13px; +} +.addresses-modal__list { + padding: 0 15px; + margin: 0; + list-style-type: none; + max-height: 350px; + overflow-y: auto; +} +.addresses-modal__item { + padding: 10px 0; + border-bottom: 1px solid rgba(0, 0, 0, 0.1); + display: flex; + position: relative; +} +.addresses-modal__text-wrap { + display: flex; + justify-content: space-between; + -ms-align-items: center; + align-items: center; + width: 100%; + padding-right: 30px; +} +.addresses-modal__btns-wrapper { + display: flex; + justify-content: flex-end; + padding-right: 5px; + position: absolute; + top: 4px; + width: 100%; + background: rgba(255,255,255,.6); +} +.addresses-modal__delete-item { + position: absolute; + right: 0; + top: 21px; + height: 15px; + width: 15px; + background: none; + border: none; +} +.addresses-modal__delete-item::before, +.addresses-modal__delete-item::after { + content: ""; + position: absolute; + left: 9px; + height: 15px; + width: 2px; + top: 0; + background-color: var(--blue-grey); +} + +.addresses-modal__delete-item:before { + transform: rotate(45deg); +} + +.addresses-modal__delete-item:after { + transform: rotate(-45deg); +} +.addresses-modal__btns-wrapper .btn { + width: 125px; + margin: 5px 10px; + padding: 10px 25px; +} +.addresses-modal__choosing { + display: flex; + justify-content: space-between; + padding-top: 30px; + padding-bottom: 30px; +} +.addresses-modal__choosing .btn { + width: 48%; + padding: 15px 0; +} +.wallet-settings__generate { + margin-bottom: 20px; +} + +.welcome__img .tablet { + display: none; + margin: 0 auto; +} + +.prod-card--line .mob-hidden { + display: none; +} + +@media (max-width: 1000px) +{ + .nomobile + { + display: none; + } +} + +@media (min-width: 576px) { + .welcome, + .wallet-settings--info, + .wallet-settings, + .accounts-info, + .send-page, + .dapps-page { + padding-left: 33px; + padding-right: 33px; + } + .welcome { + padding: 20px 0 0 0; + } + .wallet-settings__title { + padding: 15px 0; + } + .wallet-settings__title:before { + left: 5px; + } + .key-field__title { + padding-left: 0; + } + .wallet-settings__generate { + border-radius: 4px; + } + .social-list { + max-width: 100%; + padding: 102px 0 20px; + } + .accounts-info__counter-wrapper, + .accounts-info__total { + padding-left: 0; + padding-right: 0; + } + + .accounts-info__total h3 { + margin-top: 5px; + margin-bottom: 5px; + } + + .accounts-info__total .total-info { + margin-top: 10px; + } + .key-field__input { + padding-top: 20px; + padding-bottom: 18px; + } + .key-field { + padding-bottom: 30px; + } + .key-field:first-of-type { + padding-bottom: 16px; + } + .send-page__send-btn-wrp { + max-width: 330px; + width: 330px; + margin: 0 auto; + margin-top: 30px; + padding-left: 0; + padding-right: 0; + padding-bottom: 30px; + } + .dapps-page__field select { + padding-left: 10px; + } + /* .dapps-page__field select::placeholder { + color: rgba(0, 0, 0, 0.2); + } */ + .dapps-page__pagination, + .page-pagination { + max-width: 576px; + margin: 0 auto; + justify-content: space-between; + } + .explorer-page__explore.btpress + .explorer-page__table { + padding-left: 34px; + padding-right: 34px; + } + .dapps-page__page-btns, + .page-pagination .btn { + width: 60px; + height: 40px; + } + .dapps-page__page-btns:first-of-type { + margin-left: 0; + } + .page-pagination .btn:first-of-type { + margin-left: 0; + } + .dapps-page__page-btns:last-of-type { + margin-right: 0; + } + .page-pagination .btn:last-of-type { + margin-right: 0; + } + .dapps-page__pagination input, + .page-pagination input { + width: 150px; + height: 40px; + } + .dapps-page .key-field:first-of-type { + padding-bottom: 30px; + } + .dapps-page { + padding-bottom: 75px; + } + .explorer-page__explore { + padding-right: 33px; + padding-left: 33px; + } + .currentBlockNum { + padding-left: 33px; + padding-right: 33px; + } + .currentBlockNum p { + justify-content: flex-start; + } + .currentBlockNum p span:first-of-type { + min-width: 180px; + } + .explorer-page__explore::after { + right: 30px; + } + .explorer-page__table th.cur { + text-transform: uppercase; + } + .wallet-settings__field { + padding-bottom: 0; + } + .wallet-settings__generate { + margin: 0 auto; + margin-bottom: 5px; + max-width: 285px; + } + .back-link::before { + left: 0; + } + .accounts-info__add .key-field { + padding-bottom: 15px; + } + + .accounts-info__add .key-field__input { + max-height: 48px; + height: 48px; + padding-top: 15px; + padding-bottom: 14px; + } + .accounts-info__add .key-field__input--select { + padding-top: 10px; + padding-bottom: 10px; + } + .accounts-info__add-btn { + margin-top: 15px; + } + .dapp_card { + padding: 0; + } + .dapps-page__field.key-field { + margin-top: 10px; + } + .accounts-info__to-send-link { + padding-left: 0; + } +} + + +@media (min-width: 768px) { + .main-logo { + width: 125px; + height: 30px; + } + .no-mr { + margin-right: 0; + } + .accounts-info__counter-wrapper .title { + font-size: 28px!important; + line-height: 33px; + } + .header__logo { + margin-top: 3px; + } + .header__logo-link img { + height: 30px; + width: 125px; + } + .prod-card { + border-radius: 4px; + } + .welcome__img .mobile { + display: none; + } + .welcome__img .tablet { + display: block; + width: 410px; + height: 410px; + } + .wallet-settings__generate { + margin-bottom: 0; + } + .title { + font-size: 28px; + line-height: 33px; + } + .welcome, + .wallet-settings--info, + .wallet-settings, + .accounts-info, + .send-page, + .dapps-page { + padding-top: 45px; + padding-left: 39px; + padding-right: 39px; + } + .send-page { + padding-top: 25px; + } + .welcome { + padding-top: 53px; + } + .welcome__title.title { + margin-top: -8px; + margin-bottom: 30px; + } + .header { + height: 60px; + } + .header__wrapper { + flex-wrap: nowrap; + } + .header__right { + order: 2; + } + .header__right select { + text-decoration: underline; + width: 60px; + } + .header__wallet-link { + display: flex; + align-items: center; + padding: 18px 17px; + } + .header__wallet-link span { + white-space: nowrap; + margin-left: 10px; + display: block; + text-transform: uppercase; + } + .header__nav { + max-width: 350px; + } + .nav-tabs__list { + font-size: 16px; + line-height: 18px; + } + .nav-tabs__tab { + background: none; + } + .nav-tabs__link { + padding: 21px 15px; + + } + .welcome__link { + margin: 60px auto; + } + .social-list { + flex-wrap: wrap; + max-width: 550px; + padding-top: 0; + margin-top: 180px; + } + .header__right select { + position: absolute; + font-size: 14px; + line-height: 16px; + bottom: -38px; + right: 7px; + width: 60px; + border-radius: 3px; + background: transparent; + color: var(--blue-grey); + } + .white-select { + display: block; + border: 0; + padding: 10px; + margin: 10px 15px 10px auto; + } + .back-link { + display: block; + padding-left: 34px; + } + .back-link span { + display: inline; + text-decoration: underline; + } + .back-link::before { + left: 0; + } + .wallet-settings__title { + text-align: left; + padding: 30px 0; + } + .wallet-settings__ok-btns { + display: flex; + flex-wrap: nowrap; + } + .wallet-settings__btns-wrapper, + .wallet-settings__ok-btns { + padding: 30px 0; + justify-content: space-between; + } + .wallet-settings__btns-wrapper .btn, + .wallet-settings__ok-btns .btn { + margin: 0; + width: calc(50% - 15px); + max-width: none; + } + .wallet-settings__go-btn { + margin: 100px auto 150px; + width: 100%; + } + .accounts-info__empty-img { + display: flex; + justify-content: space-between; + padding-bottom: 100px; + } + .accounts-info__empty-img img { + width: 48%; + } + .accounts-info__empty-img img:nth-child(2) { + display: block; + } + .accounts-info__counter { + text-align: center; + font-size: 28px; + line-height: 33px; + } + .accounts-info__counter-wrapper { + padding: 15px 0 60px; + } + .accounts-info__to-send-link { + order: 2; + border-bottom: 0; + width: auto; + margin-bottom: 0; + padding-right: 35px; + } + .accounts-info__accounts .prod-card { + font-size: 16px; + line-height: 19px; + padding: 18px 0; + } + .accounts-info__to-send-link::after { + right: 0; + } + .accounts-info__counter-wrapper p { + order: 1; + + } + .accounts-info__counter-wrapper .btn { + order: 0; + } + .accounts-info__total { + padding-left: 0; + } + .total-info { + max-width: 330px; + } + .send-page .title, + .dapps-page .title { + display: block; + margin: 0 auto; + text-align: center; + padding-bottom: 0; + padding-top: 30px; + } + .send-page .title { + margin-bottom: 25px; + } + .send-page__send-btn-wrp { + padding-top: 75px; + } + .confirm-info__title { + min-width: 180px; + } + .confirm-info__descr { + margin-left: 30px; + } + .confirm-info__line .btn-no-bg { + margin-left: 0; + } + .send-page__btns-wrap { + padding-left: 0; + padding-right: 0; + justify-content: space-between; + padding-top: 75px; + } + .page-pagination { + justify-content: space-between; + max-width: 690px; + margin: 0 auto; + } + .page-pagination .btn { + width: 90px; + margin-left: 30px; + margin-right: 0; + } + .page-pagination .btn:first-child { + margin-left: 0; + } + .page-pagination input { + min-width: 210px; + margin-left: 30px; + } + .prod-card__second-line-left p { + white-space: normal; + display: block; + max-width: 550px; + } + .dapps-page__card .prod-card__heading { + justify-content: flex-start; + } + .prod-card__heading span { + display: inline; + } + .modal__btns-wrap .btn { + margin: 0 15px; + padding: 15px 10px; + min-width: 210px; + } + .accounts-info__accounts .prod-card__descr { + margin-top: 10px; + max-width: none; + } + .addresses-modal__item { + padding: 15px 0; + } + .addresses-modal__item-name { + display: flex; + width: 100%; + } + .addresses-modal__item-name .grey-blue-text { + width: 50%; + } + .addresses-modal__btns-wrapper .btn { + padding: 6px 30px; + } + .key-field__key-place { + margin: 0; + padding: 10px 0; + } + .fixed-status .grey-btn { + height: 40px; + padding: 10px; + } + .fixed-status .grey-btn--select { + padding-right: 0; + } + .reconnect { + width: 40px; + margin-left: 15px; + background-position: 11px 11px; + } + .fixed-status__status { + font-size: 14px; + max-width: none; + } + .currentBlockNum { + padding: 60px 30px 20px; + } + .key-field__title { + margin-bottom: 5px; + } + +.prod-card--line .prod-card__first-line { + flex-wrap: nowrap; + justify-content: flex-start; + -ms-align-items: center; + align-items: center; + } + .accounts-info__accounts .prod-card__id { + width: auto; + margin-right: 20px; + } + .prod-card--line .prod-card__descr { + order: 1; + margin: 0; + } + .prod-card--line .prod-card__heading { + order: 2; + margin-left: auto; + } + .send-page__field .key-field__input, + .key-field__select { + max-height: 58px; + height: 58px; + } + .key-field:first-of-type { + padding-bottom: 30px; + } + .send-page__send-btn-wrp { + max-width: 450px; + width: 450px; + padding-top: 25px; + } + .send-page__confirm .title { + margin-bottom: 40px; + } + .dapps-page .title { + margin-bottom: 10px; + padding-top: 20px; + } + .dapps-page .key-field:first-of-type { + padding-bottom: 15px; + } + .wallet-settings__title { + padding: 10px; + margin-bottom: 30px; + } + .wallet-settings__generate { + max-width: 100%; + width: 100%; + } + .wallet-wrapper { + margin-top: 90px; + } + .accounts-info__add .key-field { + padding-bottom: 25px; + } + .accounts-info__add-btn { + margin-top: 65px; + } + +} + + + +@media (max-width: 960px) { + /* .prod-card--line:hover { + transform: scale(1.05, 1.2); + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); + padding:5px 15px; + background: #fff; + display: block; + transition: all ease .5s; + } + .prod-card--line:hover .mob-hidden { + display: inline-block; + } + .prod-card--line:hover .prod-card__footer { + padding: 5px; + padding-left: 0; + border: 0; + } + .prod-card--line:hover .prod-card__footer-empty { + padding: 10px 0 10px 40px; + } + .prod-card--line:hover .prod-card__coins-count { + padding-top: 5px; + } + .prod-card--line:hover .prod-card__coins-count, + .prod-card--line:hover .prod-card__id { + font-weight: 500; + } + .prod-card--line:hover .small-text { + font-weight: normal; + } + .prod-card--line:hover .id-sign { + display: inline-block; + font-weight: 500; + } + .prod-card--line:hover .prod-card__first-line { + padding-right: 0; + } */ + + .prod-card--active { + /* transform: scale(1.05, 1.2); + box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2); + padding:5px 15px; */ + background: #fff; + display: block; + transition: all ease .5s; + } + .prod-card--active .mob-hidden { + display: inline-block; + } + .prod-card--active .prod-card__footer { + padding: 5px; + padding-left: 0; + border: 0; + } + .prod-card--active .prod-card__footer-empty { + padding: 10px 0 10px 40px; + } + .prod-card--active .prod-card__coins-count { + padding-top: 5px; + } + .accounts-info__accounts .prod-card__id { + text-decoration: none; + } + .prod-card--active .prod-card__coins-count, + .prod-card--active .prod-card__id { + font-weight: 500; + } + .prod-card--active .prod-card__id { + text-decoration: underline; + } + .prod-card--active .prod-card__id--mobile { + display: none; + } + .prod-card--active .prod-card__id--mobile-active { + display: block; + } + .prod-card--active .small-text { + font-weight: normal; + } + .prod-card--active .id-sign { + display: inline-block; + font-weight: 500; + } + .prod-card--active .prod-card__first-line { + padding-right: 0; + } +} + +@media (min-width: 960px) { + .welcome { + padding-top: 22px; + } + .social-list { + margin-top: 160px; + } + .header__logo { + padding-left: 42px; + } + .header__wallet-set { + margin-right: 39px; + margin-left: 0; + } + .header__right select { + right: 37px; + } + .send-page__send-btn-wrp { + max-width: 100%; + width: 100%; + padding-top: 0; + padding-bottom: 70px; + } + .accounts-info__counter-wrapper .btn { + width: 210px; + } + .accounts-info__counter-wrapper { + padding-bottom: 20px; + } + .prod-card__dapp-icon { + margin-right: 10px; + } + .prod-card--line .mob-hidden { + display: inline-block; + } + .accounts-info__accounts .prod-card { + padding: 10px 0 9px 0; + } + .addresses-modal { + padding: 15px 15px 0; + } + .accounts-info__btn { + max-width: 350px; + } + .prod-card--line .prod-card__footer { + min-width: 300px; + } + .welcome__img .tablet { + width: 225px; + height: 225px; + } + .addresses-modal__list { + max-height: 480px; + } + .accounts-info__empty-img { + padding-bottom: 60px; + } + .accounts-info__empty-img img { + display: block; + width: 32%; + } + .send-page__send-btn-wrp .btn { + margin-right: 0; + max-width: 210px; + border-radius: 4px; + } + .wallet-settings__btns-wrapper { + padding: 0; + justify-content: flex-end; + } + .wallet-settings__ok-btns { + padding-top: 100px; + justify-content: flex-end; + } + .send-page__btns-wrap { + padding-left: 0; + padding-right: 0; + padding-top: 15px; + justify-content: flex-end; + } + .dapps-page .title { + margin-bottom: 30px; + } + .accounts-info__add .key-field { + max-width: 770px; + margin: 0 auto; + } + .accounts-info__add-btn { + max-width: 210px; + width: 210px; + margin-left: auto; + margin-right: 0; + } + .wallet-settings__go-btn { + max-width: 290px; + } + .send-page__btns-wrap .btn, + .wallet-settings__ok-btns .btn { + margin-left: 30px; + max-width: 210px; + } + .wallet-settings__btns-wrapper .btn { + margin-left: 30px; + max-width: 130px; + } + .send-page__field, + .key-field__select, + .confirm-info__line, + .dapps-page__card { + max-width: 770px; + margin: 0 auto; + } + .dapps-page__card { + margin-bottom: 10px; + } + .page-pagination { + justify-content: space-between; + max-width: 770px; + margin: 0 auto; + } + .page-pagination .btn { + width: 50px; + } + .page-pagination input { + min-width: 450px; + } + .prod-card__second-line-left p { + max-width: 595px; + } + .modal { + max-width: 770px; + } + .modal__title-wrap { + width: 100%; + } + .modal__def-list { + display: flex; + } + .def-list__item { + margin-right: 30px; + } + .def-list__item dt { + min-width: auto; + margin-right: 15px; + } + .addresses-modal__choosing { + justify-content: flex-end; + } + + .addresses-modal__choosing .btn { + max-width: 210px; + margin-left: 30px; + } + .wallet-settings__generate { + float: left; + width: auto; + } + .wallet-settings__field { + position: relative; + justify-content: flex-start; + max-width: 770px; + margin: 0 auto; + } + .key-field__title { + margin-right: 30px; + } + .send-page__field .key-field__title { + margin-right: auto; + } + .wallet-settings__field .key-field__btn:not(.wallet-settings__hiding) { + position: absolute; + right: 0; + bottom: 42px; + } + .wallet-wrapper { + max-width: 770px; + margin: 0 auto; + padding-top: 15px; + } + .wallet-settings__generate { + width: 210px; + } + .reconnect span { + display: inline; + } + .reconnect.grey-btn { + width: 130px; + margin-left: 15px; + padding-top: 12px; + padding-left: 39px; + background-position: 11px 11px; + } + .explorer-page { + padding-right: 40px; + padding-left: 40px; + } + .currentBlockNum { + font-size: 16px; + padding-left: 0; + } + .currentBlockNum p { + margin-top: 10px; + margin-bottom: 0; + } + .key-field__textarea { + max-height: 58px; + padding-top: 21px; + padding-bottom: 16px; + } + .wallet-settings__hiding { + margin-bottom: 8px; + } + .password-modal { + padding-top: 45px; + } + .explorer-page__explore::after { + right: 10px; + } + .explorer-page__explore { + padding-right: 15px; + padding-left: 15px; + } + .explorer-page__explore.btpress + .explorer-page__table { + padding-right: 15px; + padding-left: 15px; + } +} + +@media (max-height: 700px) { + .social-list { + margin-top: 100px; + } +} + +@media (min-width: 1200px) { + .header__logo { + padding-left: 20px; + } + .header__wallet-set { + margin-right: 18px; + } + .header__right select { + right: 10px; + } + .accounts-info__add .key-field { + min-width: 920px; + width: 920px; + } + .wallet-settings__title-wrap { + margin-bottom: 50px; + } + .welcome__img svg { + width: 180px; + height: 150px; + } + .header__wrapper { + max-width: 1150px; + margin: 0 auto; + } + .total-info { + max-width: 360px; + } + .send-page__send-btn-wrp .btn, + .send-page__btns-wrap .btn, + .wallet-settings__ok-btns .btn { + max-width: 250px; + } + + .wallet-settings__btns-wrapper .btn { + max-width: 160px; + } + .send-page__field, + .key-field__select, + .dapps-page__card { + max-width: 920px; + } + .key-field__select { + min-height: 58px; + } + .key-field { + margin-bottom: 0; + } + .currentBlockNum p span:first-of-type { + min-width: 250px; + } + .page-pagination { + justify-content: space-between; + max-width: 920px; + margin: 0 auto; + } + .page-pagination .btn { + width: 65px; + } + .page-pagination input { + min-width: 540px; + } + .prod-card__second-line-left p { + max-width: 715px; + } + .wallet-settings .wallet-settings__field, + .wallet-settings .btn--full-width, + .wallet-wrapper { + max-width: 920px; + margin-left: auto; + margin-right: auto; + } + .wallet-settings__go-btn { + max-width: 350px; + margin-left: auto; + margin-right: auto; + } + + .wallet-settings__ok-btns { + padding-top: 150px; + } + .wallet-settings__generate { + width: 250px; + } + .wallet-settings__info { + margin-bottom: 35px; + } + +} + +.delete +{ + position: absolute; + display: none; +} + +.myhidden +{ + display: none; +} + + +.pointer +{ + cursor: pointer; +} + +.nodapp .editdapp +{ + display: none; +} + +.dapp_card +{ + width: 100%; +} + + + + + +/* правила Ñтилей Ð´Ð»Ñ history и explorer */ +.header__logo--history { + padding: 10px 15px; +} + +.history-page { + padding-bottom: 110px; +} +.history__text-block { + padding: 10px 15px 10px; +} +.history-page__id { + margin-bottom: 7px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + color: #445368; +} +.history-page__id-count { + max-width: 140px; + margin-left: 2px; + + font-size: 20px; + line-height: 23px; + font-weight: 700; + text-align-last: left; + color: #445368; + border: none; + background: #f2f2f2; +} +.history-page__description { + margin: 0; + margin-bottom: 17px; + font-size: 12px; + line-height: 14px; + color: rgba(0, 0, 0, 0.5); +} +.history-page__balance { + display: flex; + align-items: center; + + font-size: 14px; + line-height: 16px; + font-weight: 700; +} +.history-page__tera-icon { + margin-left: 5px; +} +.history-page__table { + padding: 15px 0 15px 15px; +} +.history-page__table .grid { + width: 100%; + border-collapse: collapse; +} +.history-page__table-wrap { + overflow-x: scroll; +} +.history-page__table th { + background: var(--blue-grey); + color: #fff; + border-right: 1px solid rgba(0, 0, 0, 0.1); + height: 30px; + padding: 0 20px 0 10px; + font-size: 16px; + line-height: 19px; + font-weight: 400; + white-space: nowrap; + text-align-last: left; +} +.history-page__table th:first-child { + border-top-left-radius: 5px; +} +.history-page__table th:last-child { + border-top-right-radius: 5px; +} +.history-page__table .grid tr td { + padding: 2px 10px 0px; + font-size: 14px; + line-height: 16px; + color: #000000; + background-color: #ffffff; + border: 1px solid #C4C4C4; +} +.history-page__table .grid tr td:first-of-type { + text-align: center; +} +.history-page__table .grid tr td.desc { + max-width: 170px; + word-break: break-all; +} + +@media (min-width: 576px) { + .history__text-block { + padding: 10px 33px 10px; + } + .history-page__table { + padding: 15px 33px; + } +} + +@media (min-width: 960px) { + .history-page { + padding-right: 40px; + padding-left: 40px; + } + .history__text-block { + padding: 10px 0 10px; + } + .history-page__table { + padding: 15px 0 10px; + } +} + +@media (min-width: 1200px) { + .history__text-block { + padding-top: 10px; + padding-bottom: 0; + } + .history-page__id { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__id-count { + font-size: 28px; + line-height: 33px; + text-align: center; + } + .history-page__description { + margin-bottom: 30px; + font-size: 16px; + line-height: 19px; + text-align: center; + } + .history-page__balance { + justify-content: center; + margin-bottom: 30px; + font-size: 16px; + line-height: 19px; + } + .history-page__table { + padding: 30px 15px; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.1); + background-color: #ffffff; + } +} + +/* vtools added*/ + +th.minwidth +{ + padding: 5px; +} +.minwidth +{ + width: 100px; +} +.accname +{ + width: 200px; + max-width: 200px; + word-break: break-all; +} + +.openblock +{ + cursor:pointer; +} + +.header__logo-name { + margin: 0; + margin-top: 3px; + font-size: 14px; + line-height: 18px; + font-weight: 300; + letter-spacing: 0.17em; + text-transform: uppercase; + color: #ffffff; +} + +.header__wrapper { + height: 100%; +} + +.header__logo-link { + display: flex; + flex-direction: column; +} diff --git a/src/HTML/CSS/style.css b/src/HTML/CSS/style.css new file mode 100644 index 0000000..090f86e --- /dev/null +++ b/src/HTML/CSS/style.css @@ -0,0 +1,180 @@ +/*STYLE STYLE STYLE*/ +/*STYLE STYLE STYLE*/ +/*STYLE STYLE STYLE*/ +/*STYLE STYLE STYLE*/ + + +root +{ + --colorText:#000; +} + + +body +{ + + font-family: Arial, sans-serif; + font-size: 15px; + font-weight: 300; +} + +body.styleBrown +{ + --color0:#503F13; + --color1:#86754A; + --color2:#F5E5BB; + --color3:#F5F0E3; +} + + +body.styleGreen +{ + --color0:#204410; + --color1:#4F7340; + --color2:#CBF4BA; + --color3:#E7F4E1; +} + +body.styleBlue +{ + --color0:#0D1B35; + --color1:#354259; + --color2:#BED0F2; + --color3:#E1E7F2; +} + +body.styleGray +{ + --color0:#424a5D; + --color1:#5b6775; + --color2:#FFFFFF; + --color3:#f3f3f4; +} + +body.styleContrast1 +{ + --color0:#101010; + --color1:#303030; + --color2: #b3cee8; + --color3:#FFFFFF; +} + +body.styleContrast2 +{ + --color0:#101010; + --color1:#303030; + --color2: #cee8df; + --color3:#FFFFFF; +} + +body.styleContrast3 +{ + --color0:#101010; + --color1:#303030; + --color2: #e8e0d4; + --color3:#FFFFFF; +} + + +body.univers .bt +{ + background: var(--color1); + color: var(--color2); +} +body.univers +{ + background: var(--color2); +} + +body.univers table.grid +{ + background:var(--color3); +} + +body.univers .bttab +{ + background: var(--color1); + color:white; +} + +body.univers .current +{ + background: var(--color0); + color:white; +} + +body.univers input,textarea,select +{ + background:white; + color: black; +} + + + + +/*dark*/ +body.styleDark +{ + background: #282828; + --colorText:white; + color: white; +} + +body.styleDark .bt +{ + background: #4c4c4c; + color: white; + border: 1px solid #5a5a5a; +} + +body.styleDark .header_tr +{ + color:white; +} + + +body.styleDark table.grid +{ + background: #565656; +} + +body.styleDark .bttab +{ + background: #202225; + color:white; +} + +body.styleDark .current +{ + background: #565b61; + color:white; +} + +body.styleDark input,textarea,select +{ + background:white; + color: black; +} + +/*bt*/ +body.styleDark button +{ + background: #939393; + border: 1px solid #282828; + color: white; +} + +body.styleDark .bold +{ + font-weight: 300; +} + +body.styleDark #idStatus +{ + color: #fffabd; +} + +body.styleDark #idOpenWallet +{ + border: 1px solid darkgrey; +} diff --git a/src/HTML/CSS/wallet.css b/src/HTML/CSS/wallet.css new file mode 100644 index 0000000..488a97d --- /dev/null +++ b/src/HTML/CSS/wallet.css @@ -0,0 +1,535 @@ + +/*СпиÑки*/ +table +{ + border-collapse: collapse; + width:100%; + max-width: 800px +} +.grid th, .grid td +{ + border: 1px solid #264378; + padding: 4px; +} +.grid td +{ + width: 60px; + vertical-align:top; +} + +.bold +{ + font-weight: 700; +} + +.smallbold +{ + font-weight: 600; +} + + + +td.sum +{ + text-align: right; + width: 120px; +} + + + +td.num +{ + text-align: right; + width: 50px; +} + +td.cur +{ + text-align: left; + width: 50px; + font-size:smaller; +} +td.snum +{ + text-align: center; + width: 20px; +} + +td.direct +{ + text-align: center; + vertical-align: middle; + width: 10px; + font-weight: 700; + font-size:x-large; +} +td.smart +{ + text-align: right; + width: 150px; + max-width: 200px; +} + + +td.txt +{ + text-align: left; + width: 100px; +} +td.desc +{ + text-align: left; + width: 200px; + max-width: 200px; + word-break: break-all; +} +td.name +{ + text-align: left; + width: 100px; +} + +td.date +{ + text-align: left; + width: 90px; + min-width: 70px; + font-size: small; +} + + + + + + +/*SEND SEND SEND SEND SEND SEND SEND SEND SEND SEND */ + +table.form_input +{ + border-collapse: collapse; + width: 600px; +} +.form_input td +{ + width: 20%; +} +.form_input td:nth-child(2) +{ + width: 80%; +} + +.form_input input, .form_input select +{ + width: 98%; + text-align: right; +} + +.form_input textarea +{ + width: 98%; + text-align: left; +} +.form_input .bsend +{ + width: 33%; + height: 30px; + text-align: center; + float: left; +} +.short_input input +{ + width: 120px; +} + + + + +td.code +{ + width: 240px; + font-family: "courier new", "times new roman", monospace; + font-size: small; + align-content: left; + text-align: left; + word-break: break-all; +} +td.code2 +{ + width: 340px; + font-family: "courier new", "times new roman", monospace; + font-size: small; + align-content: left; + text-align: left; + word-break: break-all; +} +.hash +{ + width: 250px; + min-width: 100px; + font-family: "courier new", "times new roman", monospace; + font-size: 60%; + align-content: left; + text-align: left; + word-break: break-all; +} +.pubkey +{ + width: 180px; + font-family: "courier new", "times new roman", monospace; + font-size: 75%; + align-content: left; + text-align: left; + word-break: break-all; +} + +.accname +{ + width: 180px; + font-family: Cambria,sans-serif; + align-content: left; + text-align: left; + word-break: break-all; +} + + +.verify +{ + +} + + + +/*CHECKBOX*/ + +.checkbox +{ + position: absolute; + z-index: -1; + opacity: 0; + margin: 10px 0 0 20px; +} +.checkbox + label +{ + position: relative; + padding: 0 20px 0 55px; + cursor: pointer; +} +.checkbox + label:before +{ + content: ''; + position: absolute; + top: -4px; + left: 0; + width: 50px; + height: 26px; + border-radius: 13px; + background: #CDD1DA; + box-shadow: inset 0 2px 3px rgba(0,0,0,.2); + transition: .2s; + +} +.checkbox + label:after +{ + content: ''; + position: absolute; + top: -2px; + left: 2px; + width: 22px; + height: 22px; + border-radius: 10px; + background: #FFF; + box-shadow: 0 2px 5px rgba(0,0,0,.3); + transition: .2s; +} +.checkbox:checked + label:before +{ + background: #46b319; +} +.checkbox_red:checked + label:before +{ + background: darkred; +} + +.checkbox_alert + label:before +{ + background: #f0b323; +} + +.checkbox:checked + label:after +{ + left: 26px; +} +.checkbox:focus + label:before +{ + box-shadow: inset 0 2px 3px rgba(0,0,0,.2), 0 0 0 3px rgba(217, 217, 217, 0.7); +} + + + + + + + + +#idPercentMining +{ + width: 40px; + text-align: center; + display:inline-block; +} + + + +#idNodeWhiteList +{ + width: 780px; +} + + +#idTotalSum +{ + text-align: left; +} + +/*CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG CONFIG*/ +/*ПроÑмотр ключей*/ +table.keys +{ + border-collapse: collapse; + width: 800px; +} +/*Редактирование приватного ключа*/ +#grid_edit_key .bt +{ + width: 80px; + height: 30px; + line-height: 20px; + margin: 10px; + text-align: center; +} +#idTypeKey,#idShortNameText +{ + width: 250px; + height: 20px; + text-align: left; +} + +/*Редактирование new acc Name*/ +#grid_edit_newacc .bt, #grid_mining_set .bt, #idTablePassword1 .bt, #idTablePassword2 .bt +{ + width: 80px; + height: 30px; + line-height: 20px; + margin: 10px; + text-align: center; +} +#idAutoSetMining +{ + width: 16px; + height: 16px; + text-align: left; + top: 3px; + position:relative; +} + +#grid_accounts_all, #grid_history +{ + font-size: smaller; +} +#grid_history .red td +{ + color: darkred; +} +#grid_history .blue td +{ + color: darkblue; +} +#grid_history .green td +{ + color: darkgreen; +} + + + +/*idStatus Log operations*/ +#idStatus +{ + z-index:1000; + position:relative; + top:40px; + left:10px; + text-align: left; + width:800px; /* ширина блока */ + color:blue; +} + +#idServerLog +{ + width:100%; + max-width: 800px; + text-align: left; + + border: 1px solid black; + height: 220px; + padding: 1px; + margin: 0px; + + + font-family: "courier new", "times new roman", monospace; + font-size: 80%; + align-content: left; + word-break: break-all; + +} + +#idTransaction +{ + width:100%; + min-width: 795px; + max-width: 795px; + text-align: left; + color:#204410; +} + +#idDescription +{ + width: 95%; + min-width: 560px; + max-width: 560px; +} + + +#idAccount +{ + width: 100%; + text-align: left; + align-content: left; +} +#idTo +{ + width: 99%; + text-align: left; + align-content: left; +} + +#idSumSend +{ + background-color: #f0ffb9; + font-weight: 700; + width: 75%; +} + +#view_header +{ + width: 800px; + font-weight: 600; + color: black; + text-align: center; +} +.header_tr +{ + width: 600px; + font-weight: 600; + text-align: center; + color:black; +} + + +#idPaginationHistory, #idPaginationBlock, #idPaginationAccount, #idPaginationAct, #idPaginationHash, #idUtilView, #idPaginationDapps +{ + width: 800px; + align-content: center; + text-align: center; +} + + +#MAIN +{ + align-content: left; +} + +#idStableScroll +{ + z-index:0; + position:absolute; + top:800px; + height: 10px; + color: darkred; + width: 97%; + margin: auto; +} + + + + +#idBlockOnSend +{ + z-index:100; + position:absolute; + height:170px; + width:380px; + top:20%; + left:0; + transform: translateX(50vw) translateX(-190px); + + font-size: larger; + padding: 10px; + background: #2b372d; + color: white; + text-align: left; + border: 1px solid gray; + box-shadow: 0 0 0 2px darkgrey; + border-radius: 8px; +} + + +#idCheckOnSend +{ + font-size: smaller; + position:absolute; + bottom: 10px; +} + +.radius +{ + border-radius: 4px; + max-height: 34px; + height: 34px; +} +button.radius +{ + color:white; + background-color: #337ab7; + border-color: #2e6da4; + width: 100px; + margin: 20px; +} + + + +.bt_open_dapp +{ + min-width: 160px; + max-width: 160px; + height: 40px; + min-height: 40px; + vertical-align:middle; + margin: 0; +} + +.setsmart +{ + color:saddlebrown; + margin: 0; +} + +.olink +{ + text-decoration: none; + color: var(--colorText); +} +.olink:hover +{ + font-weight: bold; +} + diff --git a/src/HTML/JS/client-electron.js b/src/HTML/JS/client-electron.js new file mode 100644 index 0000000..42ae61f --- /dev/null +++ b/src/HTML/JS/client-electron.js @@ -0,0 +1,32 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +const ipcRenderer = require('electron').ipcRenderer; + +function GetDataElectron(Method,ObjPost,Func) +{ + if(Func === undefined) + { + Func = ObjPost; + ObjPost = null; + } + var reply; + try + { + reply = ipcRenderer.sendSync('GetData', {path:Method, obj:ObjPost}); + } + catch(e) + { + reply = undefined; + } + if(Func) + Func(reply); +}; +window.GetData = GetDataElectron; diff --git a/src/HTML/JS/client.js b/src/HTML/JS/client.js new file mode 100644 index 0000000..0902dc8 --- /dev/null +++ b/src/HTML/JS/client.js @@ -0,0 +1,1937 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + + +function $(id) +{ + return document.getElementById(id); +}; +var WALLET_KEY_NAME = "WALLET_KEY"; +var WALLET_PUB_KEY_NAME = "WALLET_PUB_KEY"; +if(!Math.log2) + Math.log2 = Math.log2 || function (x) + { + return Math.log(x) * Math.LOG2E; + }; +if(!window.crypto) + window.crypto = window.msCrypto; +if(!window.toStaticHTML) + toStaticHTML = function (Str) + { + return Str; + }; +if(!String.prototype.padStart) +{ + window.BrowserIE = 1; + String.prototype.padStart = function padStart(targetLength,padString) + { + targetLength = targetLength >> 0; + padString = String((typeof padString !== 'undefined' ? padString : ' ')); + if(this.length > targetLength) + { + return String(this); + } + else + { + targetLength = targetLength - this.length; + if(targetLength > padString.length) + { + padString += padString.repeat(targetLength / padString.length); + } + return padString.slice(0, targetLength) + String(this); + } + }; +} +window.Storage = {}; +window.Storage.setItem = function (Key,Value) +{ + if(window.localStorage) + localStorage.setItem(Key, Value); +}; +window.Storage.getItem = function (Key) +{ + if(window.localStorage) + return localStorage.getItem(Key); +}; +window.IsLocalClient = function () +{ + return (window.location.protocol.substr(0, 4) !== "http"); +}; +var ServerHTTP; +var MainServer; +if(window.nw) +{ + window.Open = function (path,iconname,width,height) + { + width = width || 840; + height = height || 1000; + var params = {width:width, height:height}; + if(iconname) + params.icon = "../HTML/PIC/" + iconname + ".png"; + window.nw.Window.open(path, params, function (win) + { + }); + }; + window.GetData = function (Method,ObjPost,Func) + { + window.nw.global.RunRPC({path:Method, obj:ObjPost}, Func); + }; + global.RunRPC = function (message,Func) + { + if(!ServerHTTP) + ServerHTTP = require('../core/html-server'); + var reply = ServerHTTP.SendData(message); + if(Func) + { + Func(reply); + } + }; +} +else +{ + window.Open = function (path,iconname,width,height) + { + if(!window.NWMODE) + { + var win = window.open(path); + } + else + { + width = width || 840; + height = height || 1000; + var left = (screen.width - width) / 2; + var params = "left=" + left + ",top=24,menubar=no,location=no,resizable=yes,scrollbars=no,status=no"; + params += ",width=" + width; + params += ",height=" + height; + var win = window.open(path, undefined, params); + } + }; + window.GetData = function (Method,ObjPost,Func) + { + if(Method.substr(0, 4) !== "http") + { + if(Method.substr(0, 1) !== "/") + Method = "/" + Method; + if(MainServer) + { + Method = GetProtocolServerPath(MainServer) + Method; + } + else + { + if(IsLocalClient()) + return ; + } + } + var StrPost = null; + var serv = new XMLHttpRequest(); + if(ObjPost !== null) + { + StrPost = JSON.stringify(ObjPost); + serv.open("POST", Method, true); + } + else + { + throw "ERROR GET-TYPE"; + } + var STACK = "" + new Error().stack; + serv.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + serv.onreadystatechange = function () + { + if(serv.readyState == 4) + { + if(serv.status == 200) + { + if(Func) + { + var Data; + try + { + Data = JSON.parse(serv.responseText); + } + catch(e) + { + console.log("Error parsing: " + e); + console.log(serv.responseText); + console.log(STACK); + } + Func(Data, serv.responseText); + } + } + else + { + if(Func) + Func(undefined, undefined); + } + } + }; + serv.send(StrPost); + }; +} + +function IsIPAddres(Str) +{ + var arr = Str.split("."); + if(arr.length !== 3) + return 0; + for(var i = 0; i < arr.length; i++) + if(arr[i] !== "" + ParseNum(arr[i])) + return 0; + return 1; +}; + +function GetProtocolServerPath(Item) +{ + if(Item.port === 443) + return "https://" + Item.ip; + else + if(Item.port === 80) + return "http://" + Item.ip; + else + return "http://" + Item.ip + ":" + Item.port; +}; + +function SUM_TO_STRING(Value,Currency,bFloat,bLocal) +{ + var Str; + if(Value.SumCOIN || Value.SumCENT) + if(bFloat) + { + Str = "" + FLOAT_FROM_COIN(Value).toStringF(); + } + else + { + var SumCOIN = Value.SumCOIN; + if(bLocal) + SumCOIN = SumCOIN.toLocaleString(); + Str = "" + SumCOIN + "." + Rigth("000000000" + Value.SumCENT, 9); + } + else + Str = ""; + if(Currency !== undefined) + { + if(Str === "") + Str = "0"; + Str += " " + CurrencyName(Currency); + } + return Str; +}; + +function GetArrFromHex(Str) +{ + var array = []; + for(var i = 0; Str && i < Str.length / 2; i++) + { + array[i] = parseInt(Str.substr(i * 2, 2), 16); + } + return array; +}; + +function GetHexFromArr(arr) +{ + if(!(arr instanceof Array) && arr.data) + arr = arr.data; + var Str = ""; + for(var i = 0; arr && i < arr.length; i++) + { + if(!arr[i]) + Str += "00"; + else + { + var Val = arr[i] & 255; + var A = Val.toString(16); + if(A.length === 1) + A = "0" + A; + Str = Str + A; + } + } + return Str.toUpperCase(); +}; + +function GetStrFromAddr(arr) +{ + return GetHexFromArr(arr); +}; + +function GetHexFromArrBlock(Arr,LenBlock) +{ + var Str = ""; + var Arr2 = []; + for(var i = 0; i < Arr.length; i++) + { + Arr2[i % LenBlock] = Arr[i]; + if(Arr2.length >= LenBlock) + { + Str += GetHexFromArr(Arr2) + "\n"; + Arr2 = []; + } + } + if(Arr2.length) + { + Str += GetHexFromArr(Arr2); + } + return Str; +}; + +function Rigth(Str,Count) +{ + if(Str.length < Count) + return Str; + else + return Str.substr(Str.length - Count); +}; + +function toUTF8Array(str) +{ + var utf8 = []; + for(var i = 0; i < str.length; i++) + { + var charcode = str.charCodeAt(i); + if(charcode < 0x80) + utf8.push(charcode); + else + if(charcode < 0x800) + { + utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f)); + } + else + if(charcode < 0xd800 || charcode >= 0xe000) + { + utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); + } + else + { + i++; + charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); + utf8.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); + } + } + return utf8; +}; + +function Utf8ArrayToStr(array) +{ + var out, i, len, c; + var char2, char3; + out = ""; + len = array.length; + i = 0; + while(i < len) + { + c = array[i++]; + switch(c >> 4) + { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + out += String.fromCharCode(c); + break; + case 12: + case 13: + char2 = array[i++]; + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + char2 = array[i++]; + char3 = array[i++]; + out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); + break; + } + } + for(var i = 0; i < out.length; i++) + { + if(out.charCodeAt(i) === 0) + { + out = out.substr(0, i); + break; + } + } + return out; +}; + +function GetArr32FromStr(Str) +{ + return GetArrFromStr(Str, 32); +}; + +function GetArrFromStr(Str,Len) +{ + var arr = toUTF8Array(Str); + for(var i = arr.length; i < Len; i++) + { + arr[i] = 0; + } + return arr.slice(0, Len); +}; + +function WriteByte(arr,Num) +{ + arr[arr.length] = Num & 0xFF; +}; + +function WriteUint(arr,Num) +{ + var len = arr.length; + arr[len] = Num & 0xFF; + arr[len + 1] = (Num >>> 8) & 0xFF; + arr[len + 2] = (Num >>> 16) & 0xFF; + arr[len + 3] = (Num >>> 24) & 0xFF; + var NumH = Math.floor(Num / 4294967296); + arr[len + 4] = NumH & 0xFF; + arr[len + 5] = (NumH >>> 8) & 0xFF; +}; + +function WriteUint16(arr,Num) +{ + var len = arr.length; + arr[len] = Num & 0xFF; + arr[len + 1] = (Num >>> 8) & 0xFF; +}; + +function WriteUint32(arr,Num) +{ + var len = arr.length; + arr[len] = Num & 0xFF; + arr[len + 1] = (Num >>> 8) & 0xFF; + arr[len + 2] = (Num >>> 16) & 0xFF; + arr[len + 3] = (Num >>> 24) & 0xFF; +}; + +function WriteStr(arr,Str,ConstLength) +{ + if(!Str) + Str = ""; + var arrStr = toUTF8Array(Str); + var length; + var len = arr.length; + if(ConstLength) + { + length = ConstLength; + } + else + { + length = arrStr.length; + if(length > 65535) + length = 65535; + arr[len] = length & 0xFF; + arr[len + 1] = (length >>> 8) & 0xFF; + len += 2; + } + for(var i = 0; i < length; i++) + { + arr[len + i] = arrStr[i]; + } +}; + +function WriteArr(arr,arr2,ConstLength) +{ + var len = arr.length; + for(var i = 0; i < ConstLength; i++) + { + arr[len + i] = arr2[i]; + } +}; + +function WriteTr(arr,arr2) +{ + var len2 = arr2.length; + var len = arr.length; + arr[len] = len2 & 0xFF; + arr[len + 1] = (len2 >>> 8) & 0xFF; + len += 2; + for(var i = 0; i < len2; i++) + { + arr[len + i] = arr2[i]; + } +}; + +function ReadUintFromArr(arr,len) +{ + if(len === undefined) + { + len = arr.len; + arr.len += 6; + } + var value = (arr[len + 5] << 23) * 2 + (arr[len + 4] << 16) + (arr[len + 3] << 8) + arr[len + 2]; + value = value * 256 + arr[len + 1]; + value = value * 256 + arr[len]; + return value; +}; + +function ReadUint32FromArr(arr,len) +{ + if(len === undefined) + { + len = arr.len; + arr.len += 4; + } + var value = (arr[len + 3] << 23) * 2 + (arr[len + 3] << 16) + (arr[len + 1] << 8) + arr[len]; + return value; +}; + +function ReadArr(arr,length) +{ + var Ret = []; + var len = arr.len; + for(var i = 0; i < length; i++) + { + Ret[i] = arr[len + i]; + } + arr.len += length; + return Ret; +}; + +function ReadStr(arr) +{ + var length = arr[arr.len] + arr[arr.len + 1] * 256; + arr.len += 2; + var arr2 = arr.slice(arr.len, arr.len + length); + var Str = Utf8ArrayToStr(arr2); + arr.len += length; + return Str; +}; + +function ParseNum(Str) +{ + var Res = parseInt(Str); + if(isNaN(Res)) + Res = 0; + if(!Res) + Res = 0; + if(Res < 0) + Res = 0; + return Res; +}; + +function parseUint(Str) +{ + var Res = parseInt(Str); + if(isNaN(Res)) + Res = 0; + if(!Res) + Res = 0; + if(Res < 0) + Res = 0; + return Res; +}; + +function CopyObjKeys(dest,src) +{ + for(var key in src) + { + dest[key] = src[key]; + } +}; + +function SaveToArr(Arr,Obj) +{ + for(var key in Obj) + { + Arr[0]++; + var Value = Obj[key]; + switch(typeof Value) + { + case "number": + WriteByte(Arr, 241); + WriteUint(Arr, Value); + break; + case "string": + WriteByte(Arr, 242); + WriteStr(Arr, Value); + break; + case "object": + if(Value && (Value.length > 0 || Value.length === 0) && Value.length <= 240) + { + WriteByte(Arr, Value.length); + WriteArr(Arr, Value, Value.length); + break; + } + default: + WriteByte(Arr, 250); + } + } +}; + +function LoadFromArr(Arr,Obj) +{ + if(!Arr.length) + return false; + var Count = Arr[0]; + Arr.len = 1; + for(var key in Obj) + { + if(!Count) + break; + Count--; + var Type = Arr[Arr.len]; + Arr.len++; + switch(Type) + { + case 241: + Obj[key] = ReadUintFromArr(Arr); + break; + case 242: + Obj[key] = ReadStr(Arr); + break; + default: + if(Type <= 240) + { + var length = Type; + Obj[key] = ReadArr(Arr, length); + break; + } + else + { + Obj[key] = undefined; + } + } + } + if(Arr[0]) + return true; + else + return false; +}; +var entityMap = {"&":"&", "<":"<", ">":">", '"':'"', "'":''', "/":'/', "\n":'
', " ":' ', }; + +function escapeHtml(string) +{ + string = string.replace(/\\n/g, "\n"); + string = string.replace(/\\"/g, "\""); + return String(string).replace(/[\s\n&<>"'\/]/g, function (s) + { + return entityMap[s]; + }); +}; + +function InsertAfter(elem,refElem) +{ + var parent = refElem.parentNode; + var next = refElem.nextSibling; + if(next) + { + return parent.insertBefore(elem, next); + } + else + { + return parent.appendChild(elem); + } +}; + +function MoveUp(elem) +{ + var parent = elem.parentNode; + for(var i = 0; i < parent.children.length; i++) + { + var item = parent.children[i]; + if(item.id && item.id !== undefined) + { + return parent.insertBefore(elem, item); + } + } +}; + +function ViewGrid(APIName,Params,nameid,bClear,TotalSum) +{ + GetData(APIName, Params, function (Data) + { + if(!Data || !Data.result) + return ; + SetGridData(Data.arr, nameid, TotalSum, bClear); + }); +}; + +function CheckNewSearch(Def) +{ + var Str = $(Def.FilterName).value; + if(Str) + { + $(Def.NumName).value = "0"; + } +}; + +function ViewCurrent(Def,flag,This) +{ + if(Def.BlockName) + { + var element = $(Def.BlockName); + if(flag) + { + var bVisible = IsVisibleBlock(Def.BlockName); + if(!bVisible) + MoveUp(element); + SetVisibleBlock(Def.BlockName, !bVisible); + } + else + { + SetVisibleBlock(Def.BlockName, true); + } + var ResVisible = IsVisibleBlock(Def.BlockName); + if(This && This.className) + { + This.className = This.className.replace("btpress", ""); + if(ResVisible) + This.className += " btpress"; + } + if(!ResVisible) + return ; + } + var item = $(Def.NumName); + var Filter = "", Filter2 = ""; + if(Def.FilterName) + { + Filter = $(Def.FilterName).value; + } + if(Def.FilterName2) + { + Filter2 = $(Def.FilterName2).value; + } + if(!Def.Param3) + Def.Param3 = ""; + ViewGrid(Def.APIName, {StartNum:ParseNum(item.value), CountNum:GetCountViewRows(Def), Param3:Def.Param3, Filter:Filter, Filter2:Filter2, + }, Def.TabName, 1, Def.TotalSum); + SaveValues(); + if(This) + SetImg(This, Def.BlockName); +}; + +function ViewPrev(Def) +{ + var item = document.getElementById(Def.NumName); + var Num = ParseNum(item.value); + Num -= GetCountViewRows(Def); + if(Num < 0) + Num = 0; + item.value = Num; + ViewCurrent(Def); +}; + +function ViewNext(Def,MaxNum) +{ + var item = document.getElementById(Def.NumName); + var Num = ParseNum(item.value); + Num += GetCountViewRows(Def); + if(Def.FilterName) + { + if(document.getElementById(Def.FilterName).value) + { + Num = document.getElementById(Def.TabName).MaxNum + 1; + } + } + if(Num < MaxNum) + { + item.value = Num; + } + else + { + item.value = MaxNum - MaxNum % GetCountViewRows(Def); + } + ViewCurrent(Def); +}; + +function ViewBegin(Def) +{ + document.getElementById(Def.NumName).value = 0; + ViewCurrent(Def); +}; + +function ViewEnd(Def,MaxNum,bInitOnly) +{ + document.getElementById(Def.NumName).value = MaxNum - MaxNum % GetCountViewRows(Def); + if(bInitOnly) + return ; + ViewCurrent(Def); +}; + +function GetCountViewRows(Def) +{ + if(Def.CountViewRows) + return Def.CountViewRows; + else + return CountViewRows; +}; + +function DoStableScroll() +{ + var item = $("idStableScroll"); + if(!item) + return ; + var scrollHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, + document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight); + var itemlHeight = Math.max(item.scrollHeight, item.offsetHeight, item.clientHeight); + scrollHeight = scrollHeight - itemlHeight; + item.style.top = "" + scrollHeight + "px"; +}; +var glEvalMap = {}; + +function CreateEval(formula,StrParams) +{ + var Ret = glEvalMap[formula]; + if(!Ret) + { + eval("function M(" + StrParams + "){return " + formula + "}; Ret=M;"); + glEvalMap[formula] = Ret; + } + return Ret; +}; +var glWorkNum = 0; +var CUR_ROW; + +function SetGridData(arr,id_name,TotalSum,bclear,revert) +{ + var htmlTable = document.getElementById(id_name); + if(!htmlTable) + { + console.log("Error id_name: " + id_name); + return ; + } + if(bclear) + ClearTable(htmlTable); + if(!htmlTable.ItemsMap) + { + htmlTable.ItemsMap = {}; + htmlTable.RowCount = 0; + } + var map = htmlTable.ItemsMap; + glWorkNum++; + var ValueTotal = {SumCOIN:0, SumCENT:0}; + var row0 = htmlTable.rows[0]; + var row0cells = row0.cells; + var colcount = row0cells.length; + for(var i = 0; arr && i < arr.length; i++) + { + var Item = arr[i]; + var ID = Item.Num; + htmlTable.MaxNum = Item.Num; + var row = map[ID]; + if(!row) + { + htmlTable.RowCount++; + if(revert) + row = htmlTable.insertRow(1); + else + row = htmlTable.insertRow( - 1); + map[ID] = row; + for(var n = 0; n < colcount; n++) + { + var cell0 = row0cells[n]; + if(cell0.innerText == "") + continue; + cell0.F = CreateEval(cell0.id, "Item"); + if(cell0.id.substr(0, 1) === "(") + cell0.H = 1; + var cell = row.insertCell(n); + cell.className = cell0.className; + } + } + row.Work = glWorkNum; + CUR_ROW = row; + for(var n = 0; n < colcount; n++) + { + var cell = row.cells[n]; + if(!cell) + continue; + var cell0 = row0cells[n]; + if(cell0.H) + { + var text = "" + cell0.F(Item); + text = toStaticHTML(text.trim()); + if(cell.innerHTML !== text) + cell.innerHTML = text; + } + else + { + var text = "" + cell0.F(Item); + text.trim(); + if(cell.innerText !== text) + cell.innerText = text; + } + } + if(TotalSum && Item.Currency === 0) + ADD(ValueTotal, Item.Value); + } + for(var key in map) + { + var row = map[key]; + if(row.Work !== glWorkNum) + { + htmlTable.deleteRow(row.rowIndex); + delete map[key]; + } + } + if(TotalSum) + { + var id = document.getElementById(TotalSum); + if(id) + { + if(!ISZERO(ValueTotal)) + id.innerText = "Total on page: " + SUM_TO_STRING(ValueTotal, 0, 0, 1); + else + id.innerText = ""; + } + } + DoStableScroll(); +}; + +function ClearTable(htmlTable) +{ + for(var i = htmlTable.rows.length - 1; i > 0; i--) + htmlTable.deleteRow(i); + htmlTable.ItemsMap = {}; + htmlTable.RowCount = 0; +}; + +function RetOpenBlock(BlockNum,bTrDataLen) +{ + if(BlockNum && bTrDataLen) + { + if(bTrDataLen === 2) + { + return '' + BlockNum + ''; + } + else + { + return ''; + } + } + else + return '' + BlockNum + ''; +}; + +function RetBool(Value) +{ + if(Value) + return "✔"; + else + return ""; +}; + +function RetNumDapp(Item) +{ + return Item.Num; +}; + +function RetIconPath(Item,bCurrency) +{ + if(bCurrency && MapCurrencyIcon[Item.Num]) + { + return MapCurrencyIcon[Item.Num]; + } + var StrPath = ""; + if(MainServer) + { + StrPath = GetProtocolServerPath(MainServer); + } + if(Item.IconBlockNum) + { + return StrPath + '/file/' + Item.IconBlockNum + '/' + Item.IconTrNum; + } + else + return StrPath + "/PIC/blank.svg"; +}; + +function RetIconDapp(Item) +{ + if(Item.IconBlockNum) + { + return ' '; + } + else + return ""; +}; + +function RetOpenDapps(Item,bNum,AccountNum) +{ + var Name = escapeHtml(Item.Name); + if(bNum) + Name = "" + Item.Num + "." + Name; + if(Item.HTMLLength > 0) + { + var StrText = RetIconDapp(Item) + Name; + return ''; + } + else + return RetIconDapp(Item) + Name; +}; + +function RetDirect(Value) +{ + if(Value === "-") + { + return "-"; + } + else + if(Value === "+") + { + return "+"; + } + else + return ""; +}; + +function RetCategory(Item) +{ + var Str = ""; + var Num = 0; + if(Item.Category1 && MapCategory[Item.Category1]) + { + Num++; + Str += "" + Num + "." + MapCategory[Item.Category1] + "
"; + } + if(Item.Category2 && MapCategory[Item.Category2]) + { + Num++; + Str += "" + Num + "." + MapCategory[Item.Category2] + "
"; + } + if(Item.Category3 && MapCategory[Item.Category3]) + { + Num++; + Str += "" + Num + "." + MapCategory[Item.Category3] + "
"; + } + Str = Str.substr(0, Str.length - 4); + return Str; +}; + +function RetChangeSmart(Item) +{ + var Name = ""; + var State = ""; + var bOpen = 0; + if(Item.SmartObj) + { + if(Item.SmartObj.HTMLLength) + { + Name = RetOpenDapps(Item.SmartObj, 1, Item.Num); + bOpen = 1; + } + else + Name = "" + Item.SmartObj.Num + "." + escapeHtml(Item.SmartObj.Name) + "
"; + if(window.DEBUG_WALLET) + State = "
State:" + JSON.stringify(Item.SmartState); + } + var Height = 20; + if(bOpen) + Height = 40; + return '
' + Name + '' + State + '
'; +}; + +function RetHistoryAccount(Item,Name) +{ + var Num; + if(Name) + Num = Item[Name]; + else + Num = Item.Num; + if(Num < 1) + return "" + Num; + return "" + Num + ""; +}; + +function RetBaseAccount(Item) +{ + var Str = RetHistoryAccount(Item, "Account"); + if(Item.AccountLength > 1) + Str += "-" + (Item.Account + Item.AccountLength - 1); + return Str; +}; + +function ViewTransaction(BlockNum) +{ + window.Open('./blockviewer.html#' + BlockNum, 'viewer', 800, 800); +}; + +function formatDate(now) +{ + var year = now.getFullYear(); + var month = now.getMonth() + 1; + var date = now.getDate(); + var hour = now.getHours(); + var minute = now.getMinutes(); + var second = now.getSeconds(); + return year + "-" + String(month).padStart(2, "0") + "-" + String(date).padStart(2, "0") + " " + String(hour).padStart(2, + "0") + ":" + String(minute).padStart(2, "0") + ":" + String(second).padStart(2, "0"); +}; + +function DateFromBlock(BlockNum) +{ + var Str; + if(window.FIRST_TIME_BLOCK) + { + var now = new Date(window.FIRST_TIME_BLOCK + BlockNum * 1000); + Str = formatDate(now); + } + else + { + Str = ""; + } + return Str; +}; + +function SetCheckPoint(BlockNum) +{ + if(!BlockNum) + { + SetError("Not set BlockNum"); + return ; + } + GetData("SetCheckPoint", BlockNum, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function AddDiagramToArr(Arr,Item) +{ + var bWas = 0; + for(var i = 0; i < Arr.length; i++) + { + if(Arr[i].name === Item.name) + { + Item.Delete = 0; + Arr[i] = Item; + bWas = 1; + break; + } + } + if(!bWas) + { + Item.num = Arr.length; + Arr.push(Item); + } +}; + +function SetVisibleBlock(name,bSet) +{ + var Item = document.getElementById(name); + if(!Item) + return ; + if(bSet && typeof bSet === "string") + Item.style.display = bSet; + else + if(bSet) + { + Item.style.display = 'block'; + DoStableScroll(); + } + else + { + Item.style.display = 'none'; + } + return Item; +}; + +function IsVisibleBlock(name) +{ + var Item = document.getElementById(name); + if(Item && (Item.style.display === 'block' || Item.style.display === "table-row")) + return true; + else + return false; +}; + +function SetVisibleClass(Arr,Visible) +{ + if(typeof Arr === "string") + Arr = [Arr]; + for(var i = 0; i < Arr.length; i++) + { + var item = document.querySelector(Arr[i]); + if(!item) + { + ToLog("Error class name: " + Arr[i]); + continue; + } + if(!Visible) + item.classList.add("hidden"); + else + item.classList.remove("hidden"); + } +}; + +function IsVisibleClass(name) +{ + var List = document.querySelector(name); + if(List.className.indexOf(" hidden") >= 0) + return 0; + else + return 1; +}; + +function LoadValuesByArr(Arr,DopStr) +{ + if(!DopStr) + DopStr = ""; + if(Storage.getItem("VerSave") !== "3") + return 0; + for(var i = 0; i < Arr.length; i++) + { + var name = Arr[i]; + var Item = document.getElementById(name); + var name2 = DopStr + name; + if(Item.type === "checkbox") + Item.checked = parseInt(Storage.getItem(name2)); + else + Item.value = Storage.getItem(name2); + } + return 1; +}; + +function SaveValuesByArr(Arr,DopStr) +{ + if(!DopStr) + DopStr = ""; + Storage.setItem("VerSave", "3"); + for(var i = 0; i < Arr.length; i++) + { + var name = Arr[i]; + var name2 = DopStr + name; + var Item = $(name); + if(Item.type === "checkbox") + window.Storage.setItem(name2, 0 + Item.checked); + else + window.Storage.setItem(name2, Item.value); + } +}; +var MapCurrency = {}; +MapCurrency[0] = "TERA"; +MapCurrency[16] = "BTC"; +var MapCurrencyIcon = {}; +MapCurrencyIcon[0] = "./PIC/T.svg"; +MapCurrencyIcon[16] = "./PIC/B.svg"; +var MapCategory = {}; +MapCategory[0] = "-"; +MapCategory[1] = "Art & Music"; +MapCategory[2] = "Big Data & AI"; +MapCategory[3] = "Business"; +MapCategory[4] = "Commerce & Advertising"; +MapCategory[5] = "Communications"; +MapCategory[6] = "Content Management"; +MapCategory[7] = "Crowdfunding"; +MapCategory[8] = "Data Storage"; +MapCategory[9] = "Drugs & Healthcare"; +MapCategory[10] = "Education"; +MapCategory[11] = "Energy & Utilities"; +MapCategory[12] = "Events & Entertainment"; +MapCategory[13] = "eСommerce"; +MapCategory[14] = "Finance"; +MapCategory[15] = "Gambling & Betting"; +MapCategory[16] = "Gaming & VR"; +MapCategory[17] = "Healthcare"; +MapCategory[18] = "Identity & Reputation"; +MapCategory[19] = "Industry"; +MapCategory[20] = "Infrastructure"; +MapCategory[21] = "Investment"; +MapCategory[22] = "Live Streaming"; +MapCategory[23] = "Machine Learning & AI"; +MapCategory[24] = "Marketing"; +MapCategory[25] = "Media"; +MapCategory[26] = "Mining"; +MapCategory[27] = "Payments"; +MapCategory[28] = "Platform"; +MapCategory[29] = "Provenance & Notary"; +MapCategory[30] = "Real Estate"; +MapCategory[31] = "Recruitment"; +MapCategory[32] = "Service"; +MapCategory[33] = "Social Network"; +MapCategory[34] = "Social project"; +MapCategory[35] = "Supply & Logistics"; +MapCategory[36] = "Trading & Investing"; +MapCategory[37] = "Transport"; +MapCategory[38] = "Travel & Tourisim"; +MapCategory[39] = "Bounty"; +MapCategory[40] = "Code-library"; +MapCategory[41] = "Development"; +MapCategory[42] = "Exchanges"; +MapCategory[43] = "Security"; +MapCategory[44] = "Governance"; +MapCategory[45] = "Property"; +MapCategory[46] = "Insurance"; + +function GetTokenName(Num,Name) +{ + if(!Name) + Name = "Token"; + return "(" + Num + "." + Name + ")"; + return "{" + Num + "." + Name + "}"; +}; + +function CurrencyNameItem(Item) +{ + var Name = MapCurrency[Item.Currency]; + if(!Name) + { + if(Item.CurrencyObj) + Name = GetTokenName(Item.Currency, Item.CurrencyObj.ShortName); + else + Name = GetTokenName(Item.Currency, ""); + MapCurrency[Item.Currency] = Name; + } + return Name; +}; + +function CurrencyName(Num) +{ + var Name = MapCurrency[Num]; + if(!Name) + { + GetData("GetDappList", {StartNum:Num, CountNum:1}, function (Data) + { + if(Data && Data.result) + { + var Smart = Data.arr[0]; + Name = GetTokenName(Smart.Num, Smart.ShortName); + MapCurrency[Smart.Num] = Name; + } + }); + Name = GetTokenName(Num, ""); + } + return Name; +}; + +function FillCurrencyAsync(IdName,StartNum) +{ + if(!StartNum) + StartNum = 8; + var MaxCountViewRows = 10; + GetData("DappSmartList", {StartNum:StartNum, CountNum:MaxCountViewRows, TokenGenerate:1}, function (Data) + { + if(Data && Data.result && Data.arr) + { + var MaxNum = 0; + for(var i = 0; i < Data.arr.length; i++) + { + var Smart = Data.arr[i]; + if(!MapCurrency[Smart.Num]) + { + Name = GetTokenName(Smart.Num, Smart.ShortName); + MapCurrency[Smart.Num] = Name; + } + if(Smart.Num > MaxNum) + MaxNum = Smart.Num; + } + FillSelect(IdName, MapCurrency, 1); + if(Data.arr.length === MaxCountViewRows && MaxNum) + { + SetStatus("Cet currency in next iteration: " + (MaxNum + 1)); + FillCurrencyAsync(IdName, MaxNum + 1); + } + } + }); +}; + +function FillSelect(IdName,arr,bNatural) +{ + var Select = $(IdName); + var Value = Select.value; + var Options = Select.options; + var strJSON = JSON.stringify(arr); + if(Select.strJSON === strJSON) + return ; + Select.strJSON = strJSON; + var Value = Select.value; + if(bNatural) + { + Options.length = 0; + for(var key in arr) + { + var name; + if(bNatural === "KEY") + name = key; + else + name = arr[key]; + Options[Options.length] = new Option(name, key); + if(key == Value) + Select.value = key; + } + } + else + { + Options.length = 0; + for(var i = 0; i < arr.length; i++) + { + var item = arr[i]; + Options[Options.length] = new Option(item.text, item.value); + if(item.value == Value) + Select.value = item.value; + } + if(!arr.length) + for(var key in arr) + { + var item = arr[key]; + Options[Options.length] = new Option(item.text, item.value); + if(item.value == Value) + Select.value = item.value; + } + } +}; + +function GetArrFromSelect(IdName) +{ + var Select = $(IdName); + var Options = Select.options; + var arr = []; + for(var i = 0; i < Options.length; i++) + { + var item = Options[i]; + arr.push({text:item.text, value:item.value}); + } + return arr; +}; + +function FillCategory(IdName) +{ + var arr = []; + for(var key in MapCategory) + { + arr.push({sort:MapCategory[key].toUpperCase(), text:MapCategory[key], value:key}); + } + FillCategoryAndSort(IdName, arr); +}; + +function FillCategoryAndSort(IdName,arr) +{ + arr.sort(function (a,b) + { + if(a.sort < b.sort) + return - 1; + if(a.sort > b.sort) + return 1; + return 0; + }); + FillSelect(IdName, arr); +}; + +function AddToInvoiceList(Item) +{ + var arr; + var Str = Storage.getItem("InvoiceList"); + if(Str) + { + arr = JSON.parse(Str); + } + else + { + arr = []; + } + arr.unshift(Item); + Storage.setItem("InvoiceList", JSON.stringify(arr)); +}; + +function OpenDapps(Num,AccountNum) +{ + if(!Num) + return ; + var StrPath = '/dapp/' + Num; + if(IsLocalClient()) + { + StrPath = "./dapp-frame.html?dapp=" + Num; + } + if(AccountNum) + StrPath += '#' + AccountNum; + window.Open(StrPath, 'dapp', 1200); +}; + +function ParseFileName(Str) +{ + var Ret = {BlockNum:0, TrNum:0}; + var index1 = Str.indexOf("file/"); + if(index1) + { + var index2 = Str.indexOf("/", index1 + 6); + Ret.BlockNum = parseInt(Str.substr(index1 + 5, index2 - index1 - 5)); + Ret.TrNum = parseInt(Str.substr(index2 + 1)); + } + return Ret; +}; +window.MapSendTransaction = {}; + +function SendTransaction(Body,TR,SumPow,F) +{ + if(Body.length > 16000) + { + if(window.SetStatus) + SetStatus("Error length transaction =" + Body.length + " (max size=16000)"); + if(F) + F(1, TR, Body); + return ; + } + if(window.SetStatus) + SetStatus("Prepare to sending..."); + CreateNonceAndSend(1, 0, 0); + +function CreateNonceAndSend(bCreateNonce,startnonce,NumNext) + { + if(!NumNext) + NumNext = 0; + var nonce = startnonce; + if(bCreateNonce) + nonce = CreateHashBodyPOWInnerMinPower(Body, SumPow, startnonce); + var StrHex = GetHexFromArr(Body); + if(NumNext > 10) + { + SetError("Not sending. Cannt calc pow."); + return ; + } + GetData("SendTransactionHex", {Hex:StrHex}, function (Data) + { + if(Data) + { + var key = GetHexFromArr(sha3(Body)); + if(window.SetStatus) + SetStatus("Send '" + key.substr(0, 16) + "' result:" + Data.text); + if(Data.text === "Not add") + { + CreateNonceAndSend(1, nonce + 1, NumNext + 1); + } + else + if(Data.text === "Bad time") + { + if(window.DELTA_FOR_TIME_TX < 6) + { + window.DELTA_FOR_TIME_TX++; + console.log("New set Delta time: " + window.DELTA_FOR_TIME_TX); + CreateNonceAndSend(1, 0, NumNext + 1); + } + } + else + { + var key = GetHexFromArr(sha3(Body)); + MapSendTransaction[key] = TR; + if(F) + F(0, TR, Body); + } + } + else + { + if(window.SetStatus) + SetStatus("Error Data"); + } + }); + }; +}; +var MapSendID = {}; + +function SendCallMethod(Account,MethodName,Params,FromNum,FromSmartNum) +{ + var TR = {Type:135}; + var Body = [TR.Type]; + WriteUint(Body, Account); + WriteStr(Body, MethodName); + WriteStr(Body, JSON.stringify(Params)); + WriteUint(Body, FromNum); + if(FromNum) + { + GetData("GetAccount", Account, function (Data) + { + if(!Data || Data.result !== 1 || !Data.Item) + { + SetStatus("Error account number: " + Account); + return ; + } + if(Data.Item.Value.Smart !== FromSmartNum) + { + SetStatus("Error - The account:" + Account + " does not belong to a smart contract:" + FromSmartNum + " (have: " + Data.Item.Value.Smart + ")"); + return ; + } + GetData("GetAccount", FromNum, function (Data) + { + if(!Data || Data.result !== 1 || !Data.Item) + { + SetStatus("Error account number: " + FromNum); + return ; + } + if(Data.Item.Num != FromNum) + { + SetStatus("Error read from account number: " + FromNum + " read data=" + Data.Item.Num); + return ; + } + var OperationID; + if(!MapSendID[FromNum]) + { + OperationID = Data.Item.Value.OperationID + 10; + MapSendID[FromNum] = {}; + } + else + { + OperationID = MapSendID[FromNum].OperationID; + if((new Date() - MapSendID[FromNum].Date) > 8 * 1000) + { + OperationID += 20; + } + } + OperationID++; + OperationID++; + MapSendID[FromNum].OperationID = OperationID; + MapSendID[FromNum].Date = Date.now(); + WriteUint(Body, OperationID); + Body.length += 10; + SendTrArrayWithSign(Body, FromNum, TR); + }); + }); + } + else + { + WriteUint(Body, 0); + Body.length += 10; + Body.length += 64; + Body.length += 12; + SendTransaction(Body, TR); + } +}; + +function SendTrArrayWithSign(Body,Account,TR) +{ + if(MainServer || CanClientSign()) + { + var Sign = GetSignFromArr(Body); + var Arr = GetArrFromHex(Sign); + WriteArr(Body, Arr, 64); + Body.length += 12; + SendTransaction(Body, TR); + } + else + { + var StrHex = GetHexFromArr(Body); + GetData("GetSignFromHEX", {Hex:StrHex, Account:Account}, function (Data) + { + if(Data && Data.result) + { + var Arr = GetArrFromHex(Data.Sign); + WriteArr(Body, Arr, 64); + Body.length += 12; + SendTransaction(Body, TR); + } + }); + } +}; + +function GetTrCreateAcc(Currency,PubKey,Description,Adviser,Smart) +{ + var TR = {Type:TYPE_TRANSACTION_CREATE, Currency:Currency, PubKey:PubKey, Name:Description, Adviser:Adviser, Smart:Smart, }; + return TR; +}; + +function GetBodyCreateAcc(TR) +{ + var Body = []; + WriteByte(Body, TR.Type); + WriteUint(Body, TR.Currency); + WriteArr(Body, GetArrFromHex(TR.PubKey), 33); + WriteStr(Body, TR.Name, 40); + WriteUint(Body, TR.Adviser); + WriteUint32(Body, TR.Smart); + Body.length += 3; + Body.length += 12; + return Body; +}; + +function GetArrFromTR(TR) +{ + MaxBlockNum = GetCurrentBlockNumByTime(); + var Body = []; + WriteByte(Body, TR.Type); + WriteByte(Body, TR.Version); + WriteUint(Body, 0); + WriteUint(Body, TR.FromID); + WriteUint32(Body, TR.To.length); + for(var i = 0; i < TR.To.length; i++) + { + var Item = TR.To[i]; + if(TR.Version >= 3) + WriteTr(Body, Item.PubKey); + WriteUint(Body, Item.ID); + WriteUint(Body, Item.SumCOIN); + WriteUint32(Body, Item.SumCENT); + if(MapAccounts && MapAccounts[Item.ID]) + MapAccounts[Item.ID].MustUpdate = MaxBlockNum + 10; + } + WriteStr(Body, TR.Description); + WriteUint(Body, TR.OperationID); + if(TR.Version >= 3) + { + if(TR.Body) + { + WriteTr(Body, TR.Body); + } + else + { + WriteByte(Body, 0); + WriteByte(Body, 0); + } + } + return Body; +}; + +function GetSignTransaction(TR,StrPrivKey,F) +{ + if(window.SignLib) + { + if(TR.Version === 3) + { + var Arr = []; + var GetCount = 0; + for(var i = 0; i < TR.To.length; i++) + { + var Item = TR.To[i]; + GetData("GetAccountList", {StartNum:Item.ID}, function (Data) + { + if(Data && Data.result === 1 && Data.arr.length) + { + GetCount++; + var DataItem = Data.arr[0]; + var DataPubArr = DataItem.PubKey.data; + for(var j = 0; j < 33; j++) + Arr[Arr.length] = DataPubArr[j]; + if(GetCount === TR.To.length) + { + var Body = GetArrFromTR(TR); + for(var j = 0; j < Body.length; j++) + Arr[Arr.length] = Body[j]; + TR.Sign = GetArrFromHex(GetSignFromArr(Arr, StrPrivKey)); + F(TR); + } + } + }); + } + } + else + { + TR.Sign = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + F(TR); + } + } + else + { + GetData("GetSignTransaction", TR, function (Data) + { + if(Data && Data.result === 1) + { + TR.Sign = GetArrFromHex(Data.Sign); + F(TR); + } + }); + } +}; + +function GetSignFromArr(Arr,StrPrivKey) +{ + if(!StrPrivKey) + StrPrivKey = GetPrivKey(); + if(!IsHexStr(StrPrivKey) || StrPrivKey.length !== 64) + return "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + var PrivKey = GetArrFromHex(StrPrivKey); + var sigObj = SignLib.sign(SHA3BUF(Arr), Buffer.from(PrivKey), null, null); + return GetHexFromArr(sigObj.signature); +}; + +function IsHexStr(Str) +{ + if(!Str) + return false; + var arr = GetArrFromHex(Str); + var Str2 = GetHexFromArr(arr); + if(Str2 === Str.toUpperCase()) + return true; + else + return false; +}; + +function RetJSON(Item) +{ + return JSON.stringify(Item); +}; +Number.prototype.toStringF = function () +{ + var data = String(this).split(/[eE]/); + if(data.length == 1) + return data[0]; + var z = '', sign = this < 0 ? '-' : '', str = data[0].replace('.', ''), mag = Number(data[1]) + 1; + if(mag < 0) + { + z = sign + '0.'; + while(mag++) + z += '0'; + return z + str.replace(/^\-/, ''); + } + mag -= str.length; + while(mag--) + z += '0'; + return str + z; +}; + +function CanClientSign() +{ + var StrPrivKey = GetPrivKey(); + if(!IsHexStr(StrPrivKey) || StrPrivKey.length !== 64) + { + return 0; + } + return 1; +}; + +function random(max) +{ + return Math.floor(Math.random() * max); +}; + +function ToLog(Str) +{ + console.log(Str); +}; + +function InitMainServer() +{ + var Str = localStorage["MainServer"]; + if(Str && !localStorage["BIGWALLET"] && Str.substr(0, 1) === "{") + { + MainServer = JSON.parse(Str); + } +}; + +function IsZeroArr(arr) +{ + if(arr) + for(var i = 0; i < arr.length; i++) + { + if(arr[i]) + return false; + } + return true; +}; +var WALLET_PASSWORD; +var KeyPasswordMap = {}; + +function InitWalletKeyName() +{ + if(!localStorage["WALLET_KEY"]) + { + localStorage["WALLET_KEY"] = localStorage["idPrivKey"]; + } + if(!localStorage["WALLET_PUB_KEY"]) + { + localStorage["WALLET_PUB_KEY"] = localStorage["idPubKey"]; + } +}; + +function OpenWalletKey() +{ + var Key = Storage.getItem(WALLET_KEY_NAME); + if(Key && Key.substr(0, 1) === "!" && WALLET_PASSWORD) + { + Key = Key.substr(1); + var StrKey = WALLET_PASSWORD + "-" + Key; + var RetKey = KeyPasswordMap[StrKey]; + if(!RetKey) + { + var Hash = HashProtect(WALLET_PASSWORD); + RetKey = GetHexFromArr(XORHash(GetArrFromHex(Key), Hash, 32)); + KeyPasswordMap[StrKey] = RetKey; + } + } + else + { + RetKey = Key; + } + var PubKeyStr; + if(RetKey && IsHexStr(RetKey) && RetKey.length === 64) + { + var PrivKey = GetArrFromHex(RetKey); + PubKeyStr = GetHexFromArr(SignLib.publicKeyCreate(PrivKey, 1)); + } + else + { + PubKeyStr = ""; + } + sessionStorage[WALLET_KEY_NAME] = RetKey; + sessionStorage[WALLET_PUB_KEY_NAME] = PubKeyStr; + if(!WALLET_PASSWORD) + Storage.setItem(WALLET_PUB_KEY_NAME, PubKeyStr); + return RetKey; +}; + +function IsLockedWallet() +{ + var Key = Storage.getItem(WALLET_KEY_NAME); + if(Key && Key.substr(0, 1) === "!") + return 1; + else + return 0; +}; + +function GetPrivKey() +{ + var Key = sessionStorage[WALLET_KEY_NAME]; + if(!Key) + Key = Storage.getItem(WALLET_KEY_NAME); + return Key; +}; + +function GetPubKey() +{ + var Key = sessionStorage[WALLET_PUB_KEY_NAME]; + if(!Key) + Key = Storage.getItem(WALLET_PUB_KEY_NAME); + return Key; +}; + +function SetPrivKey(StrPrivKey) +{ + var Key; + if(WALLET_PASSWORD) + { + var Hash = HashProtect(WALLET_PASSWORD); + var KeyXOR = GetHexFromArr(XORHash(GetArrFromHex(StrPrivKey), Hash, 32)); + Key = "!" + KeyXOR; + } + else + { + Key = StrPrivKey; + } + var PrivKey = GetArrFromHex(StrPrivKey); + var StrPubKey = GetHexFromArr(SignLib.publicKeyCreate(PrivKey, 1)); + Storage.setItem(WALLET_KEY_NAME, Key); + Storage.setItem(WALLET_PUB_KEY_NAME, StrPubKey); + Storage.setItem("WALLET_PUB_KEY_MAIN", StrPubKey); + sessionStorage[WALLET_KEY_NAME] = StrPrivKey; + sessionStorage[WALLET_PUB_KEY_NAME] = StrPubKey; +}; + +function SetWalletPassword(Str) +{ + WALLET_PASSWORD = Str; + if(localStorage["idPrivKey"]) + delete localStorage["idPrivKey"]; +}; + +function HashProtect(Str) +{ + var arr = sha3(Str); + for(var i = 0; i < 30000; i++) + { + arr = sha3(arr); + } + return arr; +}; + +function XORHash(arr1,arr2,length) +{ + var arr3 = []; + for(var i = 0; i < length; i++) + { + arr3[i] = arr1[i] ^ arr2[i]; + } + return arr3; +}; diff --git a/src/HTML/JS/coinlib.js b/src/HTML/JS/coinlib.js new file mode 100644 index 0000000..2479f46 --- /dev/null +++ b/src/HTML/JS/coinlib.js @@ -0,0 +1,112 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var MAX_SUM_TER = 1e9; +var MAX_SUM_CENT = 1e9; + +function ADD(Coin,Value2) +{ + Coin.SumCOIN += Value2.SumCOIN; + Coin.SumCENT += Value2.SumCENT; + if(Coin.SumCENT >= MAX_SUM_CENT) + { + Coin.SumCENT -= MAX_SUM_CENT; + Coin.SumCOIN++; + } + return true; +}; + +function SUB(Coin,Value2) +{ + Coin.SumCOIN -= Value2.SumCOIN; + if(Coin.SumCENT >= Value2.SumCENT) + { + Coin.SumCENT -= Value2.SumCENT; + } + else + { + Coin.SumCENT = MAX_SUM_CENT + Coin.SumCENT - Value2.SumCENT; + Coin.SumCOIN--; + } + if(Coin.SumCOIN < 0) + { + return false; + } + return true; +}; + +function DIV(Coin,Value) +{ + Coin.SumCOIN = Coin.SumCOIN / Value; + Coin.SumCENT = Math.floor(Coin.SumCENT / Value); + var SumCOIN = Math.floor(Coin.SumCOIN); + var SumCENT = Math.floor((Coin.SumCOIN - SumCOIN) * MAX_SUM_CENT); + Coin.SumCOIN = SumCOIN; + Coin.SumCENT = Coin.SumCENT + SumCENT; + if(Coin.SumCENT >= MAX_SUM_CENT) + { + Coin.SumCENT -= MAX_SUM_CENT; + Coin.SumCOIN++; + } + return true; +}; + +function FLOAT_FROM_COIN(Coin) +{ + var Sum = Coin.SumCOIN + Coin.SumCENT / MAX_SUM_CENT; + return Sum; +}; + +function STRING_FROM_COIN(Coin) +{ + var Sum = FLOAT_FROM_COIN(Coin); + return Sum.toLocaleString(undefined, {useGrouping:true, style:'decimal', maximumFractionDigits:9}); +}; + +function COIN_FROM_FLOAT(Sum) +{ + var SumCOIN = Math.floor(Sum); + var SumCENT = Math.floor((Sum - SumCOIN) * MAX_SUM_CENT); + var Coin = {SumCOIN:SumCOIN, SumCENT:SumCENT}; + return Coin; +}; + +function COIN_FROM_FLOAT2(Sum) +{ + var SumCOIN = Math.floor(Sum); + var SumCENT = Math.floor(Sum * MAX_SUM_CENT - SumCOIN * MAX_SUM_CENT); + var Coin = {SumCOIN:SumCOIN, SumCENT:SumCENT}; + return Coin; +}; +if(typeof window === "object") + window.COIN_FROM_FLOAT = COIN_FROM_FLOAT2; + +function ISZERO(Coin) +{ + if(Coin.SumCOIN === 0 && Coin.SumCENT === 0) + return true; + else + return false; +}; + +function COIN_FROM_STRING(Str) +{ + throw "TODO: COIN_FROM_STRING"; +}; +if(typeof global === "object") +{ + global.ADD = ADD; + global.SUB = SUB; + global.DIV = DIV; + global.ISZERO = ISZERO; + global.FLOAT_FROM_COIN = FLOAT_FROM_COIN; + global.COIN_FROM_FLOAT = COIN_FROM_FLOAT; + global.COIN_FROM_STRING = COIN_FROM_STRING; +} diff --git a/src/HTML/JS/crypto-client.js b/src/HTML/JS/crypto-client.js new file mode 100644 index 0000000..7a467cb --- /dev/null +++ b/src/HTML/JS/crypto-client.js @@ -0,0 +1,372 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var MAX_SUPER_VALUE_POW = (1 << 30) * 2; +window.TYPE_TRANSACTION_CREATE = 100; + +function GetHashWithValues(hash0,value1,value2,bNotCopy) +{ + var hash; + if(bNotCopy) + hash = hash0; + else + hash = hash0.slice(); + hash[0] = value1 & 0xFF; + hash[1] = (value1 >>> 8) & 0xFF; + hash[2] = (value1 >>> 16) & 0xFF; + hash[3] = (value1 >>> 24) & 0xFF; + hash[4] = value2 & 0xFF; + hash[5] = (value2 >>> 8) & 0xFF; + hash[6] = (value2 >>> 16) & 0xFF; + hash[7] = (value2 >>> 24) & 0xFF; + var arrhash = shaarr(hash); + return arrhash; +}; + +function GetPowPower(arrhash) +{ + var SumBit = 0; + for(var i = 0; i < arrhash.length; i++) + { + var byte = arrhash[i]; + for(var b = 7; b >= 0; b--) + { + if((byte >> b) & 1) + { + return SumBit; + } + else + { + SumBit++; + } + } + } + return SumBit; +}; + +function GetPowValue(arrhash) +{ + var value = (arrhash[0] << 23) * 2 + (arrhash[1] << 16) + (arrhash[2] << 8) + arrhash[3]; + value = value * 256 + arrhash[4]; + value = value * 256 + arrhash[5]; + return value; +}; + +function CreateNoncePOWExtern(arr0,BlockNum,count,startnone) +{ + var arr = []; + for(var i = 0; i < arr0.length; i++) + arr[i] = arr0[i]; + if(!startnone) + startnone = 0; + var maxnonce = 0; + var supervalue = MAX_SUPER_VALUE_POW; + for(var nonce = startnone; nonce <= startnone + count; nonce++) + { + var arrhash = GetHashWithValues(arr, nonce, BlockNum, true); + var value = GetPowValue(arrhash); + if(value < supervalue) + { + maxnonce = nonce; + supervalue = value; + } + } + return maxnonce; +}; +window.TR_TICKET_HASH_LENGTH = 10; + +function CreateHashBody(body,Num,Nonce) +{ + var length = body.length - 12; + body[length + 0] = Num & 0xFF; + body[length + 1] = (Num >>> 8) & 0xFF; + body[length + 2] = (Num >>> 16) & 0xFF; + body[length + 3] = (Num >>> 24) & 0xFF; + body[length + 4] = 0; + body[length + 5] = 0; + length = body.length - 6; + body[length + 0] = Nonce & 0xFF; + body[length + 1] = (Nonce >>> 8) & 0xFF; + body[length + 2] = (Nonce >>> 16) & 0xFF; + body[length + 3] = (Nonce >>> 24) & 0xFF; + body[length + 4] = 0; + body[length + 5] = 0; + var HASH = sha3(body); + var FullHashTicket = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for(var i = 0; i < TR_TICKET_HASH_LENGTH; i++) + FullHashTicket[i] = HASH[i]; + WriteUintToArrOnPos(FullHashTicket, Num, TR_TICKET_HASH_LENGTH); + return sha3(FullHashTicket); +}; +window.DELTA_POWER_POW_TR = 0; +window.DELTA_FOR_TIME_TX = 0; +window.MIN_POWER_POW_TR = 0; +window.CONSENSUS_PERIOD_TIME = 1000; +window.FIRST_TIME_BLOCK = 1530446400000; +window.NEW_SIGN_TIME = 25500000; +window.SetBlockChainConstant = function (Data) +{ + var DeltaServerClient = new Date() - Data.CurTime; + if(!Data.DELTA_CURRENT_TIME) + Data.DELTA_CURRENT_TIME = 0; + window.DELTA_CURRENT_TIME2 = Data.DELTA_CURRENT_TIME - DeltaServerClient; + window.MIN_POWER_POW_TR = DELTA_POWER_POW_TR + Data.MIN_POWER_POW_TR; + window.FIRST_TIME_BLOCK = Data.FIRST_TIME_BLOCK; + window.NEW_SIGN_TIME = Data.NEW_SIGN_TIME; + window.CONSENSUS_PERIOD_TIME = Data.CONSENSUS_PERIOD_TIME; + window.GetCurrentBlockNumByTime = function () + { + var CurrentTime = Date.now() + DELTA_CURRENT_TIME2; + var CurTimeNum = CurrentTime - FIRST_TIME_BLOCK; + var StartBlockNum = Math.floor((CurTimeNum + CONSENSUS_PERIOD_TIME) / CONSENSUS_PERIOD_TIME); + return StartBlockNum; + }; + window.NWMODE = Data.NWMODE; +}; +window.GetCurrentBlockNumByTime = function () +{ + return 0; +}; + +function GetBlockNumTr(arr) +{ + var BlockNum = window.DELTA_FOR_TIME_TX + GetCurrentBlockNumByTime(); + if(arr[0] === TYPE_TRANSACTION_CREATE) + { + var BlockNum2 = Math.floor(BlockNum / 10) * 10; + if(BlockNum2 < BlockNum) + BlockNum2 = BlockNum2 + 10; + BlockNum = BlockNum2; + } + return BlockNum; +}; +var LastCreatePOWTrType = 0; +var LastCreatePOWBlockNum = 0; +var LastCreatePOWHash = [255, 255, 255, 255]; + +function CreateHashBodyPOWInnerMinPower(arr,MinPow,startnonce) +{ + var TrType = arr[0]; + var BlockNum = GetBlockNumTr(arr); + if(MinPow === undefined) + { + MinPow = MIN_POWER_POW_TR + Math.log2(arr.length / 128); + } + var nonce = startnonce; + while(1) + { + var arrhash = CreateHashBody(arr, BlockNum, nonce); + var power = GetPowPower(arrhash); + if(power >= MinPow) + { + if(LastCreatePOWBlockNum === BlockNum && LastCreatePOWTrType === TrType && CompareArr(LastCreatePOWHash, arrhash) > 0) + { + } + else + { + LastCreatePOWBlockNum = BlockNum; + LastCreatePOWTrType = TrType; + LastCreatePOWHash = arrhash; + return nonce; + } + } + nonce++; + if(nonce % 2000 === 0) + { + BlockNum = GetBlockNumTr(arr); + } + } +}; + +function CalcHashFromArray(ArrHashes,bOriginalSeq) +{ + if(bOriginalSeq === undefined) + ArrHashes.sort(CompareArr); + var Buf = []; + for(var i = 0; i < ArrHashes.length; i++) + { + var Value = ArrHashes[i]; + for(var n = 0; n < Value.length; n++) + Buf.push(Value[n]); + } + if(Buf.length === 0) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + else + if(Buf.length === 32) + return Buf; + var Hash = shaarr(Buf); + return Hash; +}; + +function GetArrFromValue(Num) +{ + var arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + arr[0] = Num & 0xFF; + arr[1] = (Num >>> 8) & 0xFF; + arr[2] = (Num >>> 16) & 0xFF; + arr[3] = (Num >>> 24) & 0xFF; + var NumH = Math.floor(Num / 4294967296); + arr[4] = NumH & 0xFF; + arr[5] = (NumH >>> 8) & 0xFF; + return arr; +}; + +function LoadLib(Path) +{ + var item = document.createElement('script'); + item.type = "text/javascript"; + item.src = Path; + document.getElementsByTagName('head')[0].appendChild(item); +}; + +function IsMS() +{ + var ua = window.navigator.userAgent; + var msie = ua.indexOf("MSIE "); + if(msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) + { + return 1; + } + else + { + return 0; + } +}; + +function LoadSignLib() +{ + if(window.SignLib) + return ; + LoadLib("./JS/sign-lib-min.js"); +}; + +function ComputeSecretWithCheck(PubKey,StrPrivKey,F) +{ + if(!window.SignLib) + { + SetError("Error - SignLib not installed"); + return ; + } + if(!IsHexStr(StrPrivKey) || StrPrivKey.length !== 64) + { + SetError("Error set PrivKey"); + return ; + } + var PrivKey = Buffer.from(GetArrFromHex(StrPrivKey)); + if(typeof PubKey === "string") + { + if(!IsHexStr(PubKey) || PubKey.length !== 66) + { + SetError("Error PubKey"); + return ; + } + PubKey = Buffer.from(GetArrFromHex(PubKey)); + } + var Result = SignLib.ecdh(PubKey, PrivKey); + F(sha3(Result)); +}; + +function ComputeSecret(Account,PubKey,F) +{ + if(GetPrivKey()) + { + ComputeSecretWithCheck(PubKey, GetPrivKey(), F); + } + else + { + GetData("GetWalletInfo", {Account:Account}, function (Data) + { + if(!Data || !Data.result) + return ; + ComputeSecretWithCheck(PubKey, Data.PrivateKey, F); + }); + } +}; + +function Encrypt(ArrSecret,StartEncrypt,StrName,StrValue) +{ + var arrRnd = sha3arr2(ArrSecret, sha3(StrName + StartEncrypt)); + var Arr = toUTF8Array(StrValue); + return DoSecret(Arr, arrRnd); +}; + +function Decrypt(ArrSecret,StartEncrypt,StrName,Arr) +{ + if(!ArrSecret) + return "".padEnd(Arr.length / 2, "."); + if(typeof Arr === "string") + Arr = GetArrFromHex(Arr); + var arrRnd = sha3arr2(ArrSecret, sha3(StrName + StartEncrypt)); + var Arr2 = DoSecret(Arr, arrRnd); + var Str = Utf8ArrayToStr(Arr2); + return Str; +}; + +function DoSecret(Arr,arrRnd) +{ + var Arr2 = []; + var CryptID = 0; + var Pos = 0; + while(Pos < Arr.length) + { + CryptID++; + WriteUintToArrOnPos(arrRnd, CryptID, 0); + var CurBuf = sha3(arrRnd); + for(var i = 0; i < 32 && Pos < Arr.length; i++, Pos++) + { + Arr2[Pos] = Arr[Pos] ^ CurBuf[i]; + } + } + return Arr2; +}; +var glEncryptInit = 0; + +function EncryptInit() +{ + glEncryptInit++; + var Time = Date.now() - new Date(2019, 0, 1); + return Math.floor(Time * 100 + Math.random() * 100) * 100 + glEncryptInit; +}; + +function EncryptID(ArrSecret,StartEncrypt,id) +{ + var Value = $(id).value; + Value = Value.padEnd(Value.length + random(5), " "); + return GetHexFromArr(Encrypt(ArrSecret, StartEncrypt, id, Value)); +}; + +function EncryptFields(ArrSecret,Params,ArrName) +{ + if(!Params.Crypto) + Params.Crypto = EncryptInit(); + for(var i = 0; i < ArrName.length; i++) + { + var Name = ArrName[i]; + var Value = Params[Name]; + Value = Value.padEnd(Value.length + random(5), " "); + Params[Name] = GetHexFromArr(Encrypt(ArrSecret, Params.Crypto, Name, Value)); + } +}; + +function DecryptFields(ArrSecret,Params,ArrName) +{ + for(var i = 0; i < ArrName.length; i++) + { + var Name = ArrName[i]; + if(Params[Name]) + { + Params[Name] = Decrypt(ArrSecret, Params.Crypto, Name, GetArrFromHex(Params[Name])); + } + else + { + Params[Name] = ""; + } + } +}; diff --git a/src/HTML/JS/dapp-inner.js b/src/HTML/JS/dapp-inner.js new file mode 100644 index 0000000..cc1eb56 --- /dev/null +++ b/src/HTML/JS/dapp-inner.js @@ -0,0 +1,521 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + + +function SendPay(Data) +{ + Data.cmd = "pay"; + SendData(Data); +}; + +function SetStorage(Key,Value) +{ + var Data = {cmd:"setstorage", Key:Key, Value:Value}; + SendData(Data); +}; + +function GetStorage(Key,F) +{ + var Data = {cmd:"getstorage", Key:Key}; + SendData(Data, F); +}; + +function SetCommon(Key,Value) +{ + var Data = {cmd:"setcommon", Key:Key, Value:Value}; + SendData(Data); +}; + +function GetCommon(Key,F) +{ + var Data = {cmd:"getcommon", Key:Key}; + SendData(Data, F); +}; + +function GetInfo(F,bUseCache) +{ + var Data = {cmd:"DappInfo", AllAccounts:ALL_ACCOUNTS, AllData:!bUseCache}; + SendData(Data, F); +}; + +function Call(Account,MethodName,Params,F) +{ + var Data = {cmd:"DappCall", MethodName:MethodName, Params:Params, Account:Account}; + SendData(Data, F); +}; + +function SendCall(Account,MethodName,Params,FromNum) +{ + if(!INFO.WalletCanSign) + { + SetError("Pls, open wallet"); + return 0; + } + var Data = {cmd:"DappSendCall", MethodName:MethodName, Params:Params, Account:Account, FromNum:FromNum}; + SendData(Data); + return 1; +}; + +function GetWalletAccounts(F) +{ + var Data = {cmd:"DappWalletList"}; + SendData(Data, F); +}; + +function GetAccountList(Params,F) +{ + var Data = {cmd:"DappAccountList", Params:Params}; + SendData(Data, F); +}; + +function GetSmartList(Params,F) +{ + var Data = {cmd:"DappSmartList", Params:Params}; + SendData(Data, F); +}; + +function GetBlockList(Params,F) +{ + var Data = {cmd:"DappBlockList", Params:Params}; + SendData(Data, F); +}; + +function GetTransactionList(Params,F) +{ + var Data = {cmd:"DappTransactionList", Params:Params}; + SendData(Data, F); +}; + +function DappSmartHTMLFile(Smart,F) +{ + var Data = {cmd:"DappSmartHTMLFile", Params:{Smart:Smart}}; + SendData(Data, F); +}; + +function DappBlockFile(BlockNum,TrNum,F) +{ + var Data = {cmd:"DappBlockFile", Params:{BlockNum:BlockNum, TrNum:TrNum}}; + SendData(Data, F); +}; + +function SetStatus(Str) +{ + SendData({cmd:"SetStatus", Message:Str}); +}; + +function SetError(Str) +{ + SendData({cmd:"SetError", Message:Str}); +}; + +function SetLocationPath(Str) +{ + SendData({cmd:"SetLocationHash", Message:Str}); +}; + +function CreateNewAccount(Currency) +{ + SendData({cmd:"CreateNewAccount", Currency:Currency}); +}; + +function OpenLink(Str) +{ + SendData({cmd:"OpenLink", Message:Str}); +}; + +function SetMobileMode() +{ + SendData({cmd:"SetMobileMode"}); +}; + +function ComputeSecret(PubKey,F,Account) +{ + if(!INFO.WalletCanSign) + { + SetError("Pls, open wallet"); + return 0; + } + if(!Account && USER_ACCOUNT.length) + Account = USER_ACCOUNT[0].Num; + if(typeof PubKey === "number") + { + var AccNum = PubKey; + GetAccountList({StartNum:AccNum, CountNum:1}, function (Err,Arr) + { + if(Err) + { + SetError(Err); + } + else + { + SendData({cmd:"ComputeSecret", Account:Account, PubKey:Arr[0].PubKey.data}, F); + } + }); + } + else + { + SendData({cmd:"ComputeSecret", Account:Account, PubKey:PubKey}, F); + } +}; + +function CheckInstall() +{ + SendData({cmd:"CheckInstall"}); +}; + +function SendTransaction(Body,TR,SumPow,F) +{ + SetError("Cannt SEND TR: " + JSON.stringify(TR)); +}; + +function CurrencyName(Num) +{ + var Name = MapCurrency[Num]; + if(!Name) + { + GetSmartList({StartNum:Num, CountNum:1, TokenGenerate:1}, function (Err,Arr) + { + if(Err || Arr.length === 0) + return ; + var Smart = Arr[0]; + Name = GetTokenName(Smart.Num, Smart.ShortName); + MapCurrency[Smart.Num] = Name; + }); + Name = GetTokenName(Num, ""); + } + return Name; +}; +var SendCountUpdate = 0; + +function FindAllCurrency() +{ + SendCountUpdate++; + GetSmartList({StartNum:8, CountNum:100, TokenGenerate:1}, function (Err,Arr) + { + SendCountUpdate--; + if(Err) + return ; + for(var i = 0; i < Arr.length; i++) + { + var Smart = Arr[i]; + if(!MapCurrency[Smart.Num]) + { + var Name = GetTokenName(Smart.Num, Smart.ShortName); + MapCurrency[Smart.Num] = Name; + } + } + }); +}; + +function GetFilePath(Path) +{ + if(window.PROTOCOL_SERVER_PATH && Path.indexOf("file/")) + { + if(Path.substr(0, 1) !== "/") + Path = "/" + Path; + Path = window.PROTOCOL_SERVER_PATH + Path; + } + return Path; +}; + +function GetParamsFromPath(Name) +{ + if(!OPEN_PATH) + return undefined; + var arr = OPEN_PATH.split("&"); + for(var i = 0; i < arr.length; i++) + { + if(arr[i].indexOf(Name + "=") === 0) + { + return arr[i].split("=")[1]; + } + } +}; + +function GetState(AccNum,F,FErr) +{ + SendCountUpdate++; + GetAccountList({StartNum:AccNum, CountNum:1}, function (Err,Arr) + { + SendCountUpdate--; + if(!Err && Arr.length) + { + var Item = Arr[0].SmartState; + if(Item) + { + F(Item); + return ; + } + } + if(FErr) + { + FErr(); + return ; + } + }); +}; +var glMapF = {}; +var glKeyF = 0; + +function SendData(Data,F) +{ + if(!window.parent) + return ; + if(F) + { + glKeyF++; + Data.CallID = glKeyF; + glMapF[glKeyF] = F; + } + window.parent.postMessage(Data, "*"); +}; + +function OnMessage(event) +{ + var Data = event.data; + if(!Data || typeof Data !== "object") + return ; + var CallID = Data.CallID; + var cmd = Data.cmd; + if(CallID) + { + var F = glMapF[CallID]; + if(F) + { + delete Data.CallID; + delete Data.cmd; + switch(cmd) + { + case "getstorage": + case "getcommon": + F(Data.Key, Data.Value); + break; + case "DappCall": + F(Data.Err, Data.RetValue); + break; + case "DappInfo": + F(Data.Err, Data); + break; + case "DappWalletList": + case "DappAccountList": + case "DappSmartList": + case "DappBlockList": + case "DappTransactionList": + F(Data.Err, Data.arr); + break; + case "DappBlockFile": + case "DappSmartHTMLFile": + F(Data.Err, Data.Body); + break; + case "ComputeSecret": + F(Data.Result); + break; + default: + console.log("Error cmd: " + cmd); + } + delete glMapF[CallID]; + } + } + else + { + switch(cmd) + { + case "History": + var eventEvent = new CustomEvent("History", {detail:Data}); + window.dispatchEvent(eventEvent); + break; + case "OnEvent": + if(window.OnEvent) + { + window.OnEvent(Data); + } + var eventEvent = new CustomEvent("Event", {detail:Data}); + window.dispatchEvent(eventEvent); + } + } +}; + +function OpenRefFile(Str) +{ + var Param = ParseFileName(Str); + if(Param.BlockNum) + DappBlockFile(Param.BlockNum, Param.TrNum, function (Err,Body) + { + document.write(Body); + }); + else + { + OpenLink(Str); + } +}; + +function SaveToStorageByArr(Arr) +{ + SetStorage("VerSave", "1"); + for(var i = 0; i < Arr.length; i++) + { + var name = Arr[i]; + var Item = $(name); + if(Item) + { + if(Item.type === "checkbox") + SetStorage(name, 0 + Item.checked); + else + SetStorage(name, Item.value); + } + } +}; + +function LoadFromStorageByArr(Arr,F,bAll) +{ + GetStorage("VerSave", function (Key,Value) + { + if(Value === "1") + { + for(var i = 0; i < Arr.length; i++) + { + if(i === Arr.length - 1) + LoadFromStorageById(Arr[i], F); + else + LoadFromStorageById(Arr[i]); + } + } + if(bAll && F) + F(0); + }); +}; + +function LoadFromStorageById(Name,F) +{ + GetStorage(Name, function (Key,Value) + { + var Item = document.getElementById(Name); + if(Item) + { + if(Item.type === "checkbox") + Item.checked = parseInt(Value); + else + Item.value = Value; + } + if(F) + F(Key, Value); + }); +}; +var SendCountDappParams = 0; + +function GetDappParams(BNum,TrNum,F,bAll) +{ + if(!BNum) + { + if(bAll) + F(); + return ; + } + SendCountDappParams++; + DappBlockFile(BNum, TrNum, function (Err,Data) + { + SendCountDappParams--; + if(!Err && Data.Type === 135) + { + try + { + var Params = JSON.parse(Data.Params); + } + catch(e) + { + } + if(Params) + { + F(Params, Data.MethodName, Data.FromNum); + return ; + } + } + if(bAll) + F(); + }); +}; +document.addEventListener("DOMContentLoaded", function () +{ + var refs = document.getElementsByTagName("A"); + for(var i = 0, L = refs.length; i < L; i++) + { + if(refs[i].href.indexOf("/file/") >= 0) + { + refs[i].onclick = function () + { + OpenRefFile(this.href); + }; + } + } +}); +if(window.addEventListener) +{ + window.addEventListener("message", OnMessage); +} +else +{ + window.attachEvent("onmessage", OnMessage); +} +var SMART = {}, BASE_ACCOUNT = {}, INFO = {}, USER_ACCOUNT = [], USER_ACCOUNT_MAP = {}, OPEN_PATH = "", ACCOUNT_OPEN_NUM = 0; +var ALL_ACCOUNTS = 0; +var WasStartInit = 0, WasStartInit2 = 0; +var eventInfo = new Event("UpdateInfo"); + +function UpdateDappInfo() +{ + GetInfo(function (Err,Data) + { + if(Err) + { + return ; + } + INFO = Data; + SMART = Data.Smart; + BASE_ACCOUNT = Data.Account; + OPEN_PATH = Data.OPEN_PATH; + ACCOUNT_OPEN_NUM = ParseNum(OPEN_PATH); + SetBlockChainConstant(Data); + USER_ACCOUNT = Data.ArrWallet; + USER_ACCOUNT_MAP = {}; + for(var i = 0; i < USER_ACCOUNT.length; i++) + USER_ACCOUNT_MAP[USER_ACCOUNT[i].Num] = USER_ACCOUNT[i]; + if(window.OnInit && !WasStartInit) + { + WasStartInit = 1; + window.OnInit(1); + } + else + if(window.OnUpdateInfo) + { + window.OnUpdateInfo(); + } + if(!WasStartInit2) + { + WasStartInit2 = 1; + var eventInit = new Event("Init"); + window.dispatchEvent(eventInit); + } + window.dispatchEvent(eventInfo); + if(Data.ArrEvent) + for(var i = 0; i < Data.ArrEvent.length; i++) + { + var Item = Data.ArrEvent[i]; + Item.cmd = "OnEvent"; + OnMessage({data:Item}); + } + }, 1); +}; +window.addEventListener('load', function () +{ + if(!window.sha3) + LoadLib("./JS/sha3.js"); + UpdateDappInfo(); + setInterval(UpdateDappInfo, 1000); +}); diff --git a/src/HTML/JS/diagram.js b/src/HTML/JS/diagram.js new file mode 100644 index 0000000..6dbe0c3 --- /dev/null +++ b/src/HTML/JS/diagram.js @@ -0,0 +1,455 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var DiagramMap = {}; +var DiagramMapId = {}; +var LMouseOn = false; +if(!window.toStaticHTML) + toStaticHTML = function (Str) + { + return Str; + }; + +function Rigth(Str,Count) +{ + if(Str.length < Count) + return Str; + else + return Str.substr(Str.length - Count); +}; + +function SetHTMLDiagramItem(Item,width) +{ + Item.mouseX = width - 50; + if(Item.Extern || Item.Delete) + return ; + var MinHeight = 80; + if(!Item.id) + Item.id = "DgrmId" + Item.num; + DiagramMap[Item.name] = Item; + DiagramMapId[Item.id] = Item; + if(Item.isLine) + { + if(Item.text) + Str = "
" + Item.text + ''; + else + Str = "
"; + } + else + { + Str = '
' + Item.text + '
\ +
'; + } + var ElBlock = document.getElementById("B" + Item.id); + if(ElBlock) + ElBlock.innerHTML = toStaticHTML(Str); + else + { + var diargams = document.getElementById("diargams"); + diargams.innerHTML = toStaticHTML(diargams.innerHTML + "
" + Str + "
"); + } +}; + +function SetDiagramMouseX(event,mode) +{ + if(event.srcElement && event.srcElement.className && event.srcElement.className.indexOf && event.srcElement.className.indexOf("DIAGRAM") >= 0) + { + if(mode === "down") + LMouseOn = true; + else + if(mode === "up") + LMouseOn = false; + event.preventDefault(); + if(LMouseOn === true) + { + var obj = event.srcElement; + var mouse = getMouse(obj, event); + if(event.ctrlKey === true) + { + for(var key in DiagramMapId) + { + var Item = DiagramMapId[key]; + Item.mouseX = mouse.x; + DrawDiagram(Item); + } + } + else + { + var Item = DiagramMapId[obj.id]; + if(Item) + { + Item.mouseX = mouse.x; + DrawDiagram(Item); + } + } + } + } +}; + +function DrawDiagram(Item) +{ + if(Item.Delete) + return ; + var arr = Item.arr; + if(!arr) + arr = Item.ArrList; + var arrX = Item.arrX; + var GreenValue = Item.value; + var StepTime = Item.steptime; + var StartNumber = Item.startnumber; + var StartServer = Item.starttime; + var mouseX = Item.mouseX; + var KPrecision = Item.KPrecision; + if(!KPrecision) + KPrecision = 1; + if(!arr) + return ; + var obj = document.getElementById(Item.id); + var ctx = obj.getContext('2d'); + var Left = 50; + var Top = 11; + var Button = 15; + var Right = 50; + if(Item.fillStyle) + ctx.fillStyle = Item.fillStyle; + else + ctx.fillStyle = "#FFF"; + ctx.fillRect(0, 0, obj.width, obj.height); + if(arr.length <= 0) + return ; + var Pow2 = 0; + if(Item.name.substr(Item.name.length - 2) === "**") + Pow2 = 1; + var MaxValue = arr[0]; + var MinValue = arr[0]; + var AvgValue = 0; + for(var i = 0; i < arr.length; i++) + { + if(arr[i] > MaxValue) + MaxValue = arr[i]; + if(arr[i] < MinValue) + MinValue = arr[i]; + if(arr[i]) + AvgValue += arr[i]; + } + if(Item.name.substr(0, 4) !== "MAX:" || !Item.AvgValue) + AvgValue = AvgValue / arr.length; + else + AvgValue = Item.AvgValue; + if(Pow2 && AvgValue) + AvgValue = Math.pow(2, AvgValue) / 1000000; + if(AvgValue < 50) + AvgValue = AvgValue.toFixed(2); + else + AvgValue = Math.floor(AvgValue); + if(Item.MaxValue !== undefined) + MaxValue = Item.MaxValue; + if(Pow2 && MaxValue) + MaxValue = Math.pow(2, MaxValue) / 1000000; + var HValue = MaxValue; + if(HValue <= 0) + HValue = 1; + var KX = (obj.width - Left - Right) / arr.length; + var KY = (obj.height - Top - Button) / HValue; + var DeltaY = 0; + var bLine = Item.line; + if(Item.zero) + { + bLine = 1; + DeltaY -= Item.zero * KY; + MaxValue -= Item.zero; + AvgValue -= Item.zero; + } + MaxValue = Math.floor(MaxValue + 0.5); + if(bLine) + ctx.lineWidth = 3; + else + if(KX > 1) + ctx.lineWidth = KX; + else + ctx.lineWidth = 1; + var StartX = Left; + var StartY = obj.height - Button; + var mouseValueX = 0; + var mouseValue = undefined; + var mouseColor = undefined; + +function DrawLines(arr,mode,color) + { + var WasMove0 = 0; + ctx.beginPath(); + ctx.moveTo(Left, obj.height - Button); + ctx.strokeStyle = color; + var PrevX = undefined; + for(var i = 0; i < arr.length; i++) + { + var Value = arr[i]; + if(!Value) + Value = 0; + if(Value) + { + if(Pow2) + Value = Math.pow(2, Value) / 1000000; + } + if(mode === "green") + { + if(Value > GreenValue) + continue; + } + else + if(mode === "red") + { + if(Value <= GreenValue) + continue; + } + var Value1 = Value; + if(Value1 > GreenValue) + Value1 = GreenValue; + var VX1 = Math.floor(Value1 * KY); + var VX2 = Math.floor(Value * KY); + if(VX1 === VX2) + VX1 -= 2; + var x = StartX + ctx.lineWidth / 2 + (i) * KX; + if(bLine) + { + if(!WasMove0) + { + WasMove0 = 1; + ctx.moveTo(x, StartY - VX2); + } + else + { + ctx.lineTo(x, StartY - VX2); + } + } + else + { + ctx.moveTo(x, StartY - VX1); + ctx.lineTo(x, StartY - VX2); + } + if(mouseX) + { + var deltaCur = Math.abs(x - mouseX); + var deltaWas = Math.abs(mouseValueX - mouseX); + if(deltaCur < deltaWas) + { + mouseValueX = x; + mouseValue = Value; + if(Item.zero) + mouseValue -= Item.zero; + mouseColor = color; + } + } + } + ctx.stroke(); + }; + if(!Item.red) + Item.red = "#A00"; + if(bLine) + { + DrawLines(arr, "line", Item.red); + } + else + { + DrawLines(arr, "red", Item.red); + if(GreenValue > 0) + DrawLines(arr, "green", "#0A0"); + } + var MaxValueText = GetValueByItemProperty(MaxValue, Item); + var AvgValueText = GetValueByItemProperty(AvgValue, Item); + ctx.lineWidth = 0.5; + ctx.beginPath(); + ctx.strokeStyle = "#000"; + Left--; + StartX--; + StartY += 2; + ctx.moveTo(Left, Top); + ctx.lineTo(StartX, StartY); + ctx.moveTo(StartX, StartY + DeltaY); + ctx.lineTo(obj.width - 10, StartY + DeltaY); + ctx.stroke(); + if(mouseX !== undefined) + { + ctx.beginPath(); + ctx.lineWidth = 0.5; + ctx.strokeStyle = "#00F"; + ctx.moveTo(mouseX, Top); + ctx.lineTo(mouseX, StartY); + ctx.stroke(); + if(mouseValue !== undefined) + { + ctx.fillStyle = mouseColor; + var Val = GetValueByItemProperty(mouseValue, Item); + var mouseTextX = mouseX; + if(Item.MouseText) + mouseTextX -= 3 * Item.MouseText.length; + else + Item.MouseText = ""; + ctx.fillText("" + Val + Item.MouseText, mouseTextX - 3, Top - 2); + } + } + ctx.fillStyle = "#000"; + if(!Item.NoTextMax) + ctx.fillText(Rigth("          " + MaxValueText, 8), 0, Top - 3); + if(MaxValue > 0 && AvgValue > 0) + { + var heigh = StartY - Top; + var KKY = AvgValue / MaxValue; + var y = (heigh - Math.floor(KKY * heigh)); + var yT = y; + if(yT < 10) + { + yT = 10; + } + ctx.beginPath(); + ctx.moveTo(Left - 2, y + Top); + ctx.lineTo(Left + 2, y + Top); + ctx.stroke(); + ctx.strokeStyle = "#00F"; + ctx.fillText(Rigth("          " + AvgValueText, 8), 0, yT + Top); + } + var CountNameX = 10; + if(arr.length < CountNameX) + CountNameX = arr.length; + var KX3 = (obj.width - Left - Right) / CountNameX; + var KDelitel = 1; + var Step = arr.length / CountNameX; + var StartTime, bNumber; + if(arrX) + { + } + else + if(StartNumber !== undefined) + { + bNumber = 1; + StartTime = StartNumber; + } + else + if(StartServer) + { + bNumber = 1; + StartTime = Math.floor(((Date.now() - StartServer) - StepTime * arr.length * 1000) / 1000); + if(StartTime < 0) + StartTime = 0; + var KDelitel = Math.floor(Step / 10) * 10; + if(KDelitel == 0) + KDelitel = 1; + } + else + { + bNumber = 0; + StartTime = Date.now() - StepTime * arr.length * 1000; + StartX = StartX - 16; + } + for(i = 0; i <= CountNameX; i++) + { + var Val; + if(i === CountNameX) + { + Val = arr.length * StepTime; + KDelitel = 1; + } + else + if(i === 0) + Val = 0; + else + Val = i * Step * StepTime; + var Str; + if(arrX) + { + Val = Math.floor(Val); + Str = arrX[Val]; + if(Str === undefined) + Str = ""; + } + else + if(bNumber) + { + Val = Math.floor((StartTime + Val) / KDelitel) * KDelitel; + Str = Val; + } + else + { + var Time = new Date(StartTime + Val * 1000); + Str = "" + Time.getHours(); + Str += ":" + Rigth("0" + Time.getMinutes(), 2); + Str += ":" + Rigth("0" + Time.getSeconds(), 2); + } + ctx.fillText(Str, StartX + i * KX3, StartY + 10); + } +}; + +function GetValueByItemProperty(Value,Item) +{ + if(Item.MathPow && Item.MathDiv) + { + Value = Math.pow(Item.MathPow, Value) / Item.MathDiv; + } + var KPrecision = Item.KPrecision; + if(!Item.KPrecision) + KPrecision = 1; + Value = Math.floor(Value * KPrecision + 0.5) / KPrecision; + return Value; +}; + +function InitDiagramByArr(Arr,width) +{ + for(var i = 0; i < Arr.length; i++) + { + Arr[i].num = i + 1; + SetHTMLDiagramItem(Arr[i], width); + } + window.addEventListener('mousedown', function (event) + { + SetDiagramMouseX(event, "down"); + }, false); + window.addEventListener('mouseup', function (event) + { + SetDiagramMouseX(event, "up"); + }, false); + window.addEventListener('onmousemove', function (event) + { + SetDiagramMouseX(event, "move"); + }, false); +}; + +function getMouse(canvas,e) +{ + var x = e.clientX - getTrueOffsetLeft(canvas); + if(window.pageXOffset) + x = x + window.pageXOffset; + var y = e.clientY - getTrueOffsetTop(canvas); + if(window.pageYOffset) + y = y + window.pageYOffset; + var coord = {x:x, y:y}; + return coord; +}; + +function getTrueOffsetLeft(ele) +{ + var n = 0; + while(ele) + { + n += ele.offsetLeft || 0; + ele = ele.offsetParent; + } + return n; +}; + +function getTrueOffsetTop(ele) +{ + var n = 0; + while(ele) + { + n += ele.offsetTop || 0; + ele = ele.offsetParent; + } + return n; +}; diff --git a/src/HTML/JS/highlight-html.js b/src/HTML/JS/highlight-html.js new file mode 100644 index 0000000..d519edb --- /dev/null +++ b/src/HTML/JS/highlight-html.js @@ -0,0 +1 @@ +function FLanguage(e){var n={endsWithParent:!0,illegal:/`]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist"],case_insensitive:!0,contains:[{className:"meta",begin:"",relevance:10,contains:[{begin:"\\[",end:"\\]"}]},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[",end:"\\]\\]>",relevance:10},{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{begin:/<\?(php)?/,end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0},e.inherit(e.APOS_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0}),e.inherit(e.QUOTE_STRING_MODE,{illegal:null,className:null,contains:null,skip:!0})]},{className:"tag",begin:"|$)",end:">",keywords:{name:"style"},contains:[n],starts:{end:"",returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:"|$)",end:">",keywords:{name:"script"},contains:[n],starts:{end:"<\/script>",returnEnd:!0,subLanguage:["actionscript","javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},n]}]}}hljs.registerLanguage("html",FLanguage); \ No newline at end of file diff --git a/src/HTML/JS/highlight-js.js b/src/HTML/JS/highlight-js.js new file mode 100644 index 0000000..bac22f9 --- /dev/null +++ b/src/HTML/JS/highlight-js.js @@ -0,0 +1 @@ +function FLanguage(e){var n="[A-Za-z$_][0-9A-Za-z$_]*",a={keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await static import from as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},r={className:"number",variants:[{begin:"\\b(0[bB][01]+)"},{begin:"\\b(0[oO][0-7]+)"},{begin:e.C_NUMBER_RE}],relevance:0},s={className:"subst",begin:"\\$\\{",end:"\\}",keywords:a,contains:[]},i={className:"string",begin:"`",end:"`",contains:[e.BACKSLASH_ESCAPE,s]};s.contains=[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,r,e.REGEXP_MODE];var t=s.contains.concat([e.C_BLOCK_COMMENT_MODE,e.C_LINE_COMMENT_MODE]);return{aliases:["js","jsx"],keywords:a,contains:[{className:"meta",relevance:10,begin:/^\s*['"]use (strict|asm)['"]/},{className:"meta",begin:/^#!/,end:/$/},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,r,{begin:/[{,]\s*/,relevance:0,contains:[{begin:n+"\\s*:",returnBegin:!0,relevance:0,contains:[{className:"attr",begin:n,relevance:0}]}]},{begin:"("+e.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*",keywords:"return throw case",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.REGEXP_MODE,{className:"function",begin:"(\\(.*?\\)|"+n+")\\s*=>",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:n},{begin:/\(\s*\)/},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:a,contains:t}]}]},{begin://,subLanguage:"xml",contains:[{begin:/<\w+\s*\/>/,skip:!0},{begin:/<\w+/,end:/(\/\w+|\w+\/)>/,skip:!0,contains:[{begin:/<\w+\s*\/>/,skip:!0},"self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/\{/,excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{begin:n}),{className:"params",begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,contains:t}],illegal:/\[|%/},{begin:/\$[(.]/},e.METHOD_GUARD,{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{beginKeywords:"extends"},e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"constructor",end:/\{/,excludeEnd:!0}],illegal:/#(?!!)/}}hljs.registerLanguage("javascript",FLanguage),hljs.registerLanguage("js",FLanguage); \ No newline at end of file diff --git a/src/HTML/JS/highlight.js b/src/HTML/JS/highlight.js new file mode 100644 index 0000000..ce22757 --- /dev/null +++ b/src/HTML/JS/highlight.js @@ -0,0 +1 @@ +!function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(r){var f=[],c=Object.keys,b={},d={},n=/^(no-?highlight|plain|text)$/i,E=/\blang(?:uage)?-([\w-]+)\b/i,t=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,h="",R={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0};function _(e){return e.replace(/&/g,"&").replace(//g,">")}function v(e){return e.nodeName.toLowerCase()}function N(e,n){var t=e&&e.exec(n);return t&&0===t.index}function m(e){return n.test(e)}function u(e){var n,t={},a=Array.prototype.slice.call(arguments,1);for(n in e)t[n]=e[n];return a.forEach(function(e){for(n in e)t[n]=e[n]}),t}function p(e){var r=[];return function e(n,t){for(var a=n.firstChild;a;a=a.nextSibling)3===a.nodeType?t+=a.nodeValue.length:1===a.nodeType&&(r.push({event:"start",offset:t,node:a}),t=e(a,t),v(a).match(/br|hr|img|input/)||r.push({event:"stop",offset:t,node:a}));return t}(e,0),r}function w(s){function o(e){return e&&e.source||e}function l(e,n){return new RegExp(o(e),"m"+(s.case_insensitive?"i":"")+(n?"g":""))}!function n(t,e){if(!t.compiled){if(t.compiled=!0,t.keywords=t.keywords||t.beginKeywords,t.keywords){var a={},r=function(t,e){s.case_insensitive&&(e=e.toLowerCase()),e.split(" ").forEach(function(e){var n=e.split("|");a[n[0]]=[t,n[1]?Number(n[1]):1]})};"string"==typeof t.keywords?r("keyword",t.keywords):c(t.keywords).forEach(function(e){r(e,t.keywords[e])}),t.keywords=a}t.lexemesRe=l(t.lexemes||/\w+/,!0),e&&(t.beginKeywords&&(t.begin="\\b("+t.beginKeywords.split(" ").join("|")+")\\b"),t.begin||(t.begin=/\B|\b/),t.beginRe=l(t.begin),t.endSameAsBegin&&(t.end=t.begin),t.end||t.endsWithParent||(t.end=/\B|\b/),t.end&&(t.endRe=l(t.end)),t.terminator_end=o(t.end)||"",t.endsWithParent&&e.terminator_end&&(t.terminator_end+=(t.end?"|":"")+e.terminator_end)),t.illegal&&(t.illegalRe=l(t.illegal)),null==t.relevance&&(t.relevance=1),t.contains||(t.contains=[]),t.contains=Array.prototype.concat.apply([],t.contains.map(function(e){return(n="self"===e?t:e).variants&&!n.cached_variants&&(n.cached_variants=n.variants.map(function(e){return u(n,{variants:null},e)})),n.cached_variants||n.endsWithParent&&[u(n)]||[n];var n})),t.contains.forEach(function(e){n(e,t)}),t.starts&&n(t.starts,e);var i=t.contains.map(function(e){return e.beginKeywords?"\\.?("+e.begin+")\\.?":e.begin}).concat([t.terminator_end,t.illegal]).map(o).filter(Boolean);t.terminators=i.length?l(i.join("|"),!0):{exec:function(){return null}}}}(s)}function M(e,n,o,t){function l(e,n,t,a){var r='')+n+(t?"":h)}function c(){d+=null!=f.subLanguage?function(){var e="string"==typeof f.subLanguage;if(e&&!b[f.subLanguage])return _(E);var n=e?M(f.subLanguage,E,!0,i[f.subLanguage]):x(E,f.subLanguage.length?f.subLanguage:void 0);return 0")+'"');return E+=n,n.length||1}var g=y(e);if(!g)throw new Error('Unknown language: "'+e+'"');w(g);var r,f=t||g,i={},d="";for(r=f;r!==g;r=r.parent)r.className&&(d=l(r.className,"",!0)+d);var E="",v=0;try{for(var s,m,p=0;f.terminators.lastIndex=p,s=f.terminators.exec(n);)m=a(n.substring(p,s.index),s[0]),p=s.index+m;for(a(n.substr(p)),r=f;r.parent;r=r.parent)r.className&&(d+=h);return{relevance:v,value:d,language:e,top:f}}catch(e){if(e.message&&-1!==e.message.indexOf("Illegal"))return{relevance:0,value:_(n)};throw e}}function x(t,e){e=e||R.languages||c(b);var a={relevance:0,value:_(t)},r=a;return e.filter(y).filter(s).forEach(function(e){var n=M(e,t,!1);n.language=e,n.relevance>r.relevance&&(r=n),n.relevance>a.relevance&&(r=a,a=n)}),r.language&&(a.second_best=r),a}function O(e){return R.tabReplace||R.useBR?e.replace(t,function(e,n){return R.useBR&&"\n"===e?"
":R.tabReplace?n.replace(/\t/g,R.tabReplace):""}):e}function a(e){var n,t,a,r,i,s,o,l,c,u,g=function(e){var n,t,a,r,i=e.className+" ";if(i+=e.parentNode?e.parentNode.className:"",t=E.exec(i))return y(t[1])?t[1]:"no-highlight";for(n=0,a=(i=i.split(/\s+/)).length;n/g,"\n"):n=e,i=n.textContent,a=g?M(g,i,!0):x(i),(t=p(n)).length&&((r=document.createElementNS("http://www.w3.org/1999/xhtml","div")).innerHTML=a.value,a.value=function(e,n,t){var a=0,r="",i=[];function s(){return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function l(e){r+=""}function c(e){("start"===e.event?o:l)(e.node)}for(;e.length||n.length;){var u=s();if(r+=_(t.substring(a,u[0].offset)),a=u[0].offset,u===e){for(i.reverse().forEach(l);c(u.splice(0,1)[0]),(u=s())===e&&u.length&&u[0].offset===a;);i.reverse().forEach(o)}else"start"===u[0].event?i.push(u[0].node):i.pop(),c(u.splice(0,1)[0])}return r+_(t.substr(a))}(t,p(r),i)),a.value=O(a.value),e.innerHTML=a.value,e.className=(s=e.className,o=g,l=a.language,c=o?d[o]:l,u=[s.trim()],s.match(/\bhljs\b/)||u.push("hljs"),-1===s.indexOf(c)&&u.push(c),u.join(" ").trim()),e.result={language:a.language,re:a.relevance},a.second_best&&(e.second_best={language:a.second_best.language,re:a.second_best.relevance}))}function i(){if(!i.called){i.called=!0;var e=document.querySelectorAll("pre code");f.forEach.call(e,a)}}function y(e){return e=(e||"").toLowerCase(),b[e]||b[d[e]]}function s(e){var n=y(e);return n&&!n.disableAutodetect}return r.highlight=M,r.highlightAuto=x,r.fixMarkup=O,r.highlightBlock=a,r.configure=function(e){R=u(R,e)},r.initHighlighting=i,r.initHighlightingOnLoad=function(){addEventListener("DOMContentLoaded",i,!1),addEventListener("load",i,!1)},r.registerLanguage=function(n,e){var t=b[n]=e(r);t.aliases&&t.aliases.forEach(function(e){d[e]=n})},r.listLanguages=function(){return c(b)},r.getLanguage=y,r.autoDetection=s,r.inherit=u,r.IDENT_RE="[a-zA-Z]\\w*",r.UNDERSCORE_IDENT_RE="[a-zA-Z_]\\w*",r.NUMBER_RE="\\b\\d+(\\.\\d+)?",r.C_NUMBER_RE="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",r.BINARY_NUMBER_RE="\\b(0b[01]+)",r.RE_STARTERS_RE="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",r.BACKSLASH_ESCAPE={begin:"\\\\[\\s\\S]",relevance:0},r.APOS_STRING_MODE={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[r.BACKSLASH_ESCAPE]},r.QUOTE_STRING_MODE={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[r.BACKSLASH_ESCAPE]},r.PHRASAL_WORDS_MODE={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},r.COMMENT=function(e,n,t){var a=r.inherit({className:"comment",begin:e,end:n,contains:[]},t||{});return a.contains.push(r.PHRASAL_WORDS_MODE),a.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|XXX):",relevance:0}),a},r.C_LINE_COMMENT_MODE=r.COMMENT("//","$"),r.C_BLOCK_COMMENT_MODE=r.COMMENT("/\\*","\\*/"),r.HASH_COMMENT_MODE=r.COMMENT("#","$"),r.NUMBER_MODE={className:"number",begin:r.NUMBER_RE,relevance:0},r.C_NUMBER_MODE={className:"number",begin:r.C_NUMBER_RE,relevance:0},r.BINARY_NUMBER_MODE={className:"number",begin:r.BINARY_NUMBER_RE,relevance:0},r.CSS_NUMBER_MODE={className:"number",begin:r.NUMBER_RE+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},r.REGEXP_MODE={className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[r.BACKSLASH_ESCAPE,{begin:/\[/,end:/\]/,relevance:0,contains:[r.BACKSLASH_ESCAPE]}]},r.TITLE_MODE={className:"title",begin:r.IDENT_RE,relevance:0},r.UNDERSCORE_TITLE_MODE={className:"title",begin:r.UNDERSCORE_IDENT_RE,relevance:0},r.METHOD_GUARD={begin:"\\.\\s*"+r.UNDERSCORE_IDENT_RE,relevance:0},r}); \ No newline at end of file diff --git a/src/HTML/JS/lexer.js b/src/HTML/JS/lexer.js new file mode 100644 index 0000000..ac78a0e --- /dev/null +++ b/src/HTML/JS/lexer.js @@ -0,0 +1,1686 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +const LOC_ADD_NAME = "$"; +module.exports = function () +{ + 'use strict'; + this.ErrorIgnore = false; + this.ErrorOne = true; + this.CommentIgnore = true; + this.PrintMargin = 120; + this.FileNumber = 0; + this.InjectCheck = true; + this.SideMode = "client"; + this.Clear = function () + { + this.ExternMap = {}; + this.FunctionMap = {}; + this.WasPlus = 0; + this.buf = ""; + this.stream = ""; + this.bWasBackSlash = false; + this.pos = 0; + this.start = 0; + this.beforeRegExp = 0; + this.value = ""; + this.type = ""; + this.BlockLevel = 0; + this.LastStreamValue = ""; + this.CountCol = 0; + this.ErrCount = 0; + this.WasEnter = false; + this.lastComment = 0; + this.lastAddCode = - 1; + this.LineNumber = 0; + this.posLineNumber = 0; + this.IgnoreCodeLevel = false; + this.AddToStream = this.AddToStreamAddTab; + }; + this.AllowedWords = {true:1, false:1, undefined:1, Infinity:1, NaN:1, null:1, context:5, this:5, arguments:5, }; + this.KeyWords = {break:1, return:1, case:1, do:1, if:1, switch:1, var:1, throw:1, while:1, default:1, for:1, try:1, continue:1, + with:1, function:3, void:3, new:3, delete:3, typeof:3, finally:5, catch:5, else:5, instanceof:4, in:4, }; + this.ProcessWords = {break:"break", return:"return", case:"case", do:"do", if:"if", switch:"switch", var:"var", throw:"throw", + with:"with", while:"while", default:"default", for:"for", try:"try", continue:"continue", function:"function", void:"void", + new:"new", delete:"delete", typeof:"typeof", finally:"finally", catch:"catch", else:"else", }; + this.enIndenifier = "1"; + this.enString = "2"; + this.enNumber = "3"; + this.enSpaces = "4"; + this.enNewLine = "5"; + this.enComments = "6"; + this.enRegular = "7"; + this.enOperator = "O"; + this.enEndFile = "EoF"; + this.lexTypeAll = new Array(0x10000); + this.lexTypeIdentifier = new Array(0x10000); + this.lexTypeNumbers = new Array(0x10000); + this.lexTypeNumbers16 = new Array(0x10000); + this.lexTypeSpaces = new Array(0x10000); + this.lexTypeNewLines = new Array(0x10000); + this.lexTypeRegStart = new Array(0x10000); + this.SpacesArray = new Array(100); + this.Init = function () + { + var BufNumbers = "0123456789"; + var BufNumbers16 = "0123456789ABCDEFabcdef"; + var BufChars = "~!%^&*-+/<>`@#()=\\|{}[];':\"?,."; + var BufSpaces = " \t\b\f\v\u00A0\u2028\u2029\u000C"; + var BufNewLine = "\n\r"; + var BufRegStart = "`~!#%^&*(+|-=\\[{};:,?<>"; + SetType("N", BufNumbers, this.lexTypeAll); + SetType("C", BufChars, this.lexTypeAll); + SetType("S", BufSpaces, this.lexTypeAll); + SetType("M", BufNewLine, this.lexTypeAll); + SetLetterType("L", this.lexTypeAll, this.lexTypeAll); + SetType("N", BufNumbers, this.lexTypeNumbers); + SetType("N", BufNumbers16, this.lexTypeNumbers16); + SetType("S", BufSpaces, this.lexTypeSpaces); + SetType("M", BufNewLine, this.lexTypeNewLines); + SetType("R", BufRegStart, this.lexTypeRegStart); + SetLetterType("L", this.lexTypeAll, this.lexTypeIdentifier); + SetType("N", BufNumbers, this.lexTypeIdentifier); + Normalize(this.lexTypeAll); + Normalize(this.lexTypeNumbers); + Normalize(this.lexTypeNumbers16); + Normalize(this.lexTypeSpaces); + Normalize(this.lexTypeNewLines); + Normalize(this.lexTypeRegStart); + Normalize(this.lexTypeIdentifier); + this.SpacesArray[0] = ""; + this.SpacesArray[1] = ""; + for(var i = 2; i < 100; i++) + this.SpacesArray[i] = this.SpacesArray[i - 1] + " "; + +function SetType(type,buf,TypeArray) + { + for(var pos = 0; pos < buf.length; pos++) + { + var c = buf.charCodeAt(pos); + TypeArray[c] = type; + } + }; + +function SetLetterType(type,lexTypeAll,TypeArray) + { + for(var i = 32; i < 0x10000; i++) + { + if(!lexTypeAll[i] || lexTypeAll[i] == "L") + TypeArray[i] = "L"; + } + TypeArray[92] = "L"; + }; + +function Normalize(TypeArray) + { + for(var i = 0; i < 0x10000; i++) + { + TypeArray[i] = TypeArray[i] || false; + } + }; + +function SetVeryQuickly(TypeArray) + { + var Ret = 0; + for(var i = 0; i < 0x10000; i++) + { + if(TypeArray[i]) + Ret = 1; + else + Ret = 0; + } + return Ret; + }; + }; + this.Init(); + +function LANG(Str) + { + for(var i = 1; i < arguments.length; i++) + Str = Str.replace("%" + i, arguments[i]); + return Str; + }; + this.Error = function () + { + var Str1 = LANG.apply(this, arguments); + var begin = 0; + for(var i = this.start; i >= 0; i--) + if(this.buf[i] == "\n" || this.buf[i] == "\r") + { + begin = i + 1; + break; + } + var end = this.buf.length - 1; + for(var i = this.pos; i < this.buf.length; i++) + if(this.buf[i] == "\n" || this.buf[i] == "\r") + { + end = i; + break; + } + var line = 1; + for(var i = 0; i < this.start; i++) + if(this.buf[i] == "\n") + { + line++; + } + var col = this.start + 1 - begin; + var Dots1 = ""; + var Dots2 = ""; + if(this.start - begin > 100) + { + begin = this.start - 100; + Dots1 = "..."; + } + if(end - this.start > 100) + { + end = this.start + 100; + Dots2 = "..."; + } + this.ErrCount++; + var ErrLabel; + if(!this.ErrorOne && this.ErrorIgnore) + ErrLabel = " <> "; + else + ErrLabel = " <> "; + var StrLine = this.buf.substring(begin, this.start) + ErrLabel + this.buf.substring(this.start, end); + var Str2 = LANG("At line: %1 col: %2", line - 1, col - 1); + var Str = "SyntaxError: " + Str1 + ". " + Str2 + "\n" + Dots1 + StrLine + Dots2; + if(this.ErrorIgnore) + { + console.log(Str); + this.stream += ErrLabel; + this.stream += this.value + " "; + if(this.ErrorOne) + { + this.stream += "\n\n" + Str; + } + else + { + this.NotBackPos(); + return ; + } + } + throw Str; + }; + this.code_base = '\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f'; + this.FromBackSlashString = function (str) + { + var Ret = ""; + for(var i = 0; i < str.length; i++) + { + var s = str[i]; + if(s == "\\") + { + var s2 = str[i + 1]; + switch(s2) + { + case "r": + i = i + 1; + Ret = Ret + "\r"; + break; + case "n": + i = i + 1; + Ret = Ret + "\n"; + break; + case "t": + i = i + 1; + Ret = Ret + "\t"; + break; + case "b": + i = i + 1; + Ret = Ret + "\b"; + break; + case "f": + i = i + 1; + Ret = Ret + "\f"; + break; + case "u": + var s = str.substring(i + 2, i + 6); + var code = parseInt(s); + if(isNaN(code)) + this.Error("Unrecognize unicode symbol: '%1'", "\\u" + s); + else + Ret = Ret + String.fromCharCode(code); + i = i + 5; + break; + case "x": + var s = str.substring(i + 2, i + 4); + var code = parseInt(s, 16); + if(isNaN(code)) + this.Error("Unrecognize Latin symbol: '%1'", "\\x" + s); + else + Ret = Ret + this.code_base.charAt(code); + i = i + 3; + break; + default: + var c = str.charCodeAt(i + 1); + if(this.lexTypeNumbers[c] == "N") + { + var s = str.substring(i + 1, i + 4); + var code = parseInt(s, 8); + if(isNaN(code)) + this.Error("Unrecognize Latin symbol: '%1'", "\\" + s); + else + Ret = Ret + this.code_base.charAt(code); + i = i + 3; + } + break; + } + } + else + { + Ret = Ret + s; + } + } + return Ret; + }; + this.PosString = function () + { + var separator = this.buf[this.pos]; + this.pos++; + while(this.pos < this.buf.length) + { + var s = this.buf[this.pos]; + if(s == separator) + { + this.pos++; + return ; + } + else + if(s == "\\") + { + this.pos++; + this.bWasBackSlash = true; + } + else + if(s == "\n") + { + this.Error("Found end of line during calculate string"); + return ; + } + this.pos++; + } + this.Error("Found end of file during calculate string"); + }; + this.PosRegExp = function () + { + this.Error("RegExp not support"); + return ; + var separator = "/"; + this.pos++; + while(this.pos < this.buf.length) + { + var s = this.buf[this.pos]; + if(s == separator) + { + this.pos++; + return ; + } + else + if(s == "[") + { + separator = ""; + } + else + if(s == "]" && separator == "") + { + separator = "/"; + } + else + if(s == "\\") + { + this.pos++; + this.bWasBackSlash = true; + } + else + if(s == "\n") + { + this.Error("Found end of line during calculate regexp"); + return ; + } + this.pos++; + } + this.Error("Found end of file during calculate regexp"); + }; + this.PosCurrentType = function (TypeArray) + { + while(this.pos < this.buf.length) + { + var c = this.buf.charCodeAt(this.pos); + if(!TypeArray[c]) + break; + if(c == 92) + this.bWasBackSlash = true; + this.pos++; + } + }; + this.PosIdentifier = function () + { + this.PosCurrentType(this.lexTypeIdentifier); + }; + this.PosSpaces = function () + { + this.PosCurrentType(this.lexTypeSpaces); + }; + this.PosNewLines = function () + { + this.PosCurrentType(this.lexTypeNewLines); + }; + this.PosNumber = function () + { + if(this.buf[this.pos] == "0") + { + this.pos++; + var s = this.buf[this.pos]; + if(s == "x" || s == "X") + { + this.pos++; + this.PosCurrentType(this.lexTypeNumbers16); + } + else + if(s == ".") + { + this.pos++; + this.PosCurrentType(this.lexTypeNumbers); + } + else + { + this.PosCurrentType(this.lexTypeNumbers); + } + return ; + } + this.PosCurrentType(this.lexTypeNumbers); + if(this.buf[this.pos] == ".") + { + this.pos++; + this.PosCurrentType(this.lexTypeNumbers); + } + if(this.buf[this.pos] == "e" || this.buf[this.pos] == "E") + { + this.pos++; + var s2 = this.buf[this.pos]; + if(s2 == "+" || s2 == "-") + this.pos++; + var posstart = this.pos; + this.PosCurrentType(this.lexTypeNumbers); + if(posstart == this.pos) + this.Error("Unrecognize exponent number"); + } + var c = this.buf.charCodeAt(this.pos); + var type = this.lexTypeAll[c]; + if(type == "L") + this.Error("Unrecognize number"); + }; + this.PosCommentsOneLine = function () + { + while(this.pos < this.buf.length) + { + var s = this.buf[this.pos]; + if(s == '\n') + break; + else + if(s == '\r') + break; + this.pos++; + } + }; + this.PosCommentsMultiLine = function () + { + while(this.pos < this.buf.length) + { + var s = this.buf[this.pos] + this.buf[this.pos + 1]; + if(s == '*/') + { + this.pos += 2; + break; + } + this.pos++; + } + }; + this.BackPos = function () + { + if(this.type != this.enEndFile) + this.pos = this.start; + }; + this.NotBackPos = function () + { + if(this.pos == this.start) + this.PosNextItem(); + }; + this.PosNextToken = function () + { + this.WasEnter = false; + while(true) + { + this.PosNextItem(); + switch(this.type) + { + case this.enNewLine: + this.WasEnter = true; + break; + case this.enSpaces: + case this.enComments: + break; + default: + return this.type; + } + } + }; + this.PosNextItem = function () + { + this.start = this.pos; + if(this.pos >= this.buf.length) + { + this.type = this.enEndFile; + return this.enEndFile; + } + var c = this.buf.charCodeAt(this.pos); + var lex = this.lexTypeAll[c]; + switch(lex) + { + case "L": + this.bWasBackSlash = false; + this.PosIdentifier(); + this.value = this.buf.substring(this.start, this.pos); + if(this.bWasBackSlash) + this.value = this.FromBackSlashString(this.value); + this.beforeRegExp = 65; + this.type = this.enIndenifier; + if(this.value == "in" || this.value == "of" || this.value == "instanceof") + { + return this.value; + } + return this.enIndenifier; + case "N": + this.PosNumber(); + this.value = this.buf.substring(this.start, this.pos); + this.beforeRegExp = 48; + this.type = this.enNumber; + return this.enNumber; + case "S": + this.PosSpaces(); + this.type = this.enSpaces; + return this.enSpaces; + case "M": + this.PosNewLines(); + this.type = this.enNewLine; + return this.enNewLine; + case "C": + var s = this.buf[this.pos]; + switch(s) + { + case '"': + case "'": + this.bWasBackSlash = false; + this.PosString(); + this.value = this.buf.substring(this.start, this.pos); + this.beforeRegExp = 65; + this.type = this.enString; + return this.enString; + case "/": + var s2 = this.buf[this.pos + 1]; + if(s2 == '/') + { + this.PosCommentsOneLine(); + if(!this.CommentIgnore && this.lastComment <= this.start) + { + this.lastComment = this.start + 1; + this.value = this.buf.substring(this.start, this.pos); + this.AddToStream(this.value); + this.AddToStream("\n"); + } + this.type = this.enComments; + return this.enComments; + } + else + if(s2 == '*') + { + this.PosCommentsMultiLine(); + if(!this.CommentIgnore && this.lastComment <= this.start) + { + this.lastComment = this.start + 1; + this.value = this.buf.substring(this.start, this.pos); + this.AddToStream(this.value); + if(this.buf[this.pos] == "\n") + { + this.AddToStream("\n"); + this.pos++; + } + } + this.type = this.enComments; + return this.enComments; + } + else + if(this.lexTypeRegStart[this.beforeRegExp] == "R") + { + this.PosRegExp(); + this.beforeRegExp = 65; + while("gmi".indexOf(this.buf[this.pos]) >= 0) + { + this.pos++; + } + this.value = this.buf.substring(this.start, this.pos); + this.type = this.enRegular; + return this.enRegular; + } + s += this.AddNextOperator("="); + break; + case "/": + this.beforeRegExp = 0; + s += this.AddNextOperator("="); + break; + case "=": + s += this.AddNextOperator("="); + s += this.AddNextOperator("="); + break; + case ">": + s += this.AddNextOperator(">"); + s += this.AddNextOperator("="); + if(s == ">>=") + break; + s += this.AddNextOperator(">"); + s += this.AddNextOperator("="); + break; + case "<": + s += this.AddNextOperator("<"); + s += this.AddNextOperator("="); + break; + case "!": + s += this.AddNextOperator("="); + s += this.AddNextOperator("="); + break; + case "~": + break; + case "+": + s += this.AddNextOperator("+"); + if(s == "++") + break; + s += this.AddNextOperator("="); + break; + case "-": + s += this.AddNextOperator("-"); + if(s == "--") + break; + s += this.AddNextOperator("="); + break; + case "*": + s += this.AddNextOperator("="); + break; + case "&": + s += this.AddNextOperator("&"); + if(s == "&&") + break; + s += this.AddNextOperator("="); + break; + case "|": + s += this.AddNextOperator("|"); + if(s == "||") + break; + s += this.AddNextOperator("="); + break; + case "^": + s += this.AddNextOperator("="); + break; + case "%": + s += this.AddNextOperator("="); + break; + case ".": + var c2 = this.buf.charCodeAt(this.pos + 1); + if(this.lexTypeNumbers[c2]) + { + this.pos++; + this.PosNumber(); + this.value = this.buf.substring(this.start, this.pos); + this.beforeRegExp = 48; + this.type = this.enNumber; + return this.enNumber; + } + break; + } + this.beforeRegExp = c; + this.value = s; + this.pos++; + this.type = s; + return s; + default: + this.Error("Unrecognize symbol: '%1'", c); + } + this.type = this.enNewLine; + return this.enNewLine; + }; + this.AddNextOperator = function (find) + { + var s2 = this.buf[this.pos + 1]; + if(s2 == find) + { + this.pos++; + return s2; + } + else + { + return ""; + } + }; + this.ParseLexem = function (Code,bWrite) + { + this.Clear(); + this.buf = Code; + this.beforeRegExp = 61; + var AllStr = ""; + while(true) + { + var type = this.PosNextItem(); + if(type == this.enEndFile) + break; + if(bWrite) + { + AllStr = AllStr + this.value + "\n"; + } + } + if(AllStr) + { + console.log(AllStr); + } + return AllStr; + }; + this.ParseLexem2 = function (Code) + { + this.Clear(); + this.buf = Code; + this.beforeRegExp = 61; + var n = 0; + var Value1 = new Uint32Array(Code.length); + var Value2 = new Uint32Array(Code.length); + while(true) + { + var type = this.PosNextItem(); + if(type == this.enEndFile) + break; + Value1[n] = this.start; + Value2[n] = this.pos; + n++; + } + return {Value1:Value1, Value2:Value2}; + }; + this.ParseCode = function (Code) + { + this.Clear(); + this.buf = Code; + this.ParseSmart(); + }; + this.ParseSmart = function () + { + var bPublic = 0; + while(true) + { + var type = this.PosNextToken(); + if(type === this.enEndFile) + break; + if(type === this.enString && this.value === '"public"') + { + bPublic = 1; + continue; + } + if(this.value === "function") + { + var FuncName = this.Parse_function(0, 1); + if(bPublic) + this.ExternMap[FuncName] = bPublic; + bPublic = 0; + this.AddNewLineToStream(";\n"); + } + else + { + this.Error("Require 'function' indenifier"); + } + } + }; + this.ParseBlock = function (sConditions,bOneIteration,bSimpleMode,bNotCheck) + { + if(!bOneIteration) + this.BlockLevel++; + var WasIgnoreCodeLevel = this.IgnoreCodeLevel; + var bWasLabel = false; + this.beforeRegExp = 61; + Main: + while(true) + { + var posSave = this.pos; + var type = this.PosNextToken(); + if(!bNotCheck && !bSimpleMode && !bWasLabel) + { + switch(type) + { + case ";": + case ":": + case "{": + case "}": + case this.enEndFile: + break; + case this.enIndenifier: + default: + this.AddCheckLineToStream(); + } + } + switch(type) + { + case ";": + bWasLabel = false; + break; + case ":": + this.Error("Unexpected token: '%1'", this.GetTokenName(type)); + bWasLabel = false; + break; + case "{": + this.AddNewLineToStream("{\n", true); + this.ParseBlock("}"); + this.AddNewLineToStream("}\n", true); + bWasLabel = false; + break; + case "}": + break Main; + case this.enEndFile: + break Main; + case this.enIndenifier: + bNotCheck = false; + var Name = this.value; + var key = this.KeyWords[Name]; + if(key == 1 || Name == "function") + { + this["Parse_" + this.ProcessWords[Name]](); + if(!bSimpleMode) + { + this.AddNewLineToStream(";\n"); + } + type = this.type; + break; + } + default: + this.pos = posSave; + type = this.ParseExpressionWithComma(false, false, true); + if(type === ":") + { + bWasLabel = true; + } + else + { + bWasLabel = false; + if(!bSimpleMode) + { + this.AddNewLineToStream(";\n"); + } + } + } + if(bOneIteration && type != ":") + break; + } + if(sConditions) + { + if(sConditions.indexOf(type) == - 1) + { + this.Error("Error block closing. Unexpected token: '%1'", this.GetTokenName(type)); + } + } + this.IgnoreCodeLevel = WasIgnoreCodeLevel; + if(!bOneIteration) + this.BlockLevel--; + return type; + }; + this.ParseOneBlock = function () + { + var type = this.PosNextToken(); + if(type == "{") + { + this.AddNewLineToStream("\n"); + this.AddNewLineToStream("{\n", true); + var type = this.ParseBlock("}"); + this.AddNewLineToStream("}\n", true); + } + else + if(type == ";") + { + if(this.InjectCheck) + { + this.AddCheckLineToStream(); + this.AddNewLineToStream("\n"); + } + else + this.AddNewLineToStream(";\n"); + } + else + { + if(this.InjectCheck) + { + this.AddNewLineToStream("\n"); + this.AddNewLineToStream("{\n", true); + this.BackPos(); + var type = this.ParseBlock(false, true); + this.AddNewLineToStream("}\n", true); + } + else + { + this.AddNewLineToStream("\n"); + this.BackPos(); + this.BlockLevel++; + type = this.ParseBlock(false, true); + this.BlockLevel--; + } + } + if(type == ";") + { + this.NotBackPos(); + } + return type; + }; + this.ParseExpressionWithComma = function (sConditions,bCanEmpty,bCanLabel) + { + var sConditions2; + if(sConditions) + sConditions2 = "," + sConditions; + while(true) + { + var prev = this.pos; + var type = this.ParseExpression(sConditions2, bCanEmpty, bCanLabel); + if(type != ",") + break; + if(prev == this.pos || !sConditions2) + this.PosNextItem(); + bCanLabel = false; + if(this.CountCol <= this.PrintMargin) + this.AddToStream(", "); + else + this.AddNewLineToStream(",\n", true); + } + return type; + }; + this.ParseExpression = function (sConditions,bCanEmpty,bCanLabel) + { + var WasPlus2 = this.WasPlus; + var stream2 = this.stream; + this.WasPlus = 0; + this.stream = ""; + var type = this.ParseExpression0(sConditions, bCanEmpty, bCanLabel); + if(this.WasPlus) + this.stream = stream2 + "CHKL(" + this.stream + ")"; + else + this.stream = stream2 + this.stream; + this.WasPlus = WasPlus2; + return type; + }; + this.ParseExpression0 = function (sConditions,bCanEmpty,bCanLabel) + { + var bWasExpr = false; + var bCanDot = false; + var bCanLeftSide = false; + this.beforeRegExp = 61; + Main: + while(true) + { + var type = this.PosNextItem(); + switch(type) + { + case this.enSpaces: + case this.enComments: + continue; + case this.enNewLine: + bCanLeftSide = false; + this.WasEnter = true; + continue; + case this.enNumber: + case this.enIndenifier: + case this.enString: + case this.enRegular: + case "{": + if(bWasExpr) + break Main; + } + switch(type) + { + case this.enIndenifier: + var Name = this.value; + var key = this.KeyWords[Name]; + if(key == 3) + { + this["Parse_" + this.ProcessWords[Name]](); + } + else + if(key == 1 || key == 5) + { + type = this.enOperator; + this.BackPos(); + break Main; + } + else + { + if(!this.AllowedWords[Name]) + Name = LOC_ADD_NAME + Name; + this.AddToStream(Name); + if(bCanLabel) + { + var posSave2 = this.pos; + var type2 = this.PosNextToken(); + if(type2 == ":") + { + type = type2; + bWasExpr = true; + this.AddNewLineToStream(":\n", true); + return ":"; + } + else + { + this.pos = posSave2; + } + } + } + bCanLeftSide = true; + bCanDot = true; + bWasExpr = true; + break; + case this.enNumber: + this.AddToStream(this.value); + bCanLeftSide = false; + bCanDot = true; + bWasExpr = true; + break; + case this.enString: + this.AddToStream(this.value); + bCanLeftSide = false; + bCanDot = true; + bWasExpr = true; + break; + case this.enRegular: + this.AddToStream(this.value); + bCanLeftSide = false; + bCanDot = true; + bWasExpr = true; + break; + case "{": + this.ParseDefObject(); + bCanLeftSide = false; + bCanDot = true; + bWasExpr = true; + break; + case "[": + this.ParseDefArray(); + bCanLeftSide = true; + bCanDot = true; + bWasExpr = true; + break; + case "(": + this.ParseFunctionCall(bCanDot); + bCanLeftSide = true; + bCanDot = true; + bWasExpr = true; + break; + case ".": + if(!bCanDot) + this.Error("Unexpected token: '%1'", type); + this.AddToStream("."); + this.RequireIndenifier(); + bCanLeftSide = true; + bCanDot = true; + bWasExpr = true; + break; + case "?": + if(!bWasExpr) + this.Error("Require expression before token: '%1'", type); + this.ParseIfCondition(); + bCanLeftSide = false; + bCanDot = false; + bWasExpr = true; + break; + case "=": + case "+=": + if(type === "+=") + this.WasPlus = 1; + if(!bCanLeftSide) + this.Error("Unexpected token: '%1'", type); + this.AddToStream(" " + type + " "); + var type2 = this.ParseExpression(undefined, false, false); + bCanLeftSide = false; + bCanDot = false; + bWasExpr = true; + break; + case "-=": + case "*=": + case "/=": + case ">>=": + case "<<=": + case ">>>=": + case "&=": + case "|=": + case "^=": + case "%=": + if(!bCanLeftSide) + this.Error("Unexpected token: '%1'", type); + this.AddToStream(" " + type + " "); + bCanLeftSide = false; + bCanDot = false; + bWasExpr = false; + break; + case "!": + this.AddToStream(type); + bCanLeftSide = false; + bCanDot = false; + break; + case "~": + this.AddToStream(type); + bCanLeftSide = false; + bCanDot = false; + break; + case "==": + case "===": + case "!=": + case "!==": + case ">=": + case "<=": + case ">": + case "<": + case "~": + case "^": + case "&": + case "|": + case "<<": + case ">>": + case ">>>": + case "%": + case "*": + case "/": + case "&&": + case "||": + if(!bWasExpr) + this.Error("Require expression before token: '%1'", type); + bWasExpr = false; + this.AddToStream(" " + type + " "); + bCanLeftSide = false; + bCanDot = false; + break; + case "-": + case "+": + if(type === "+") + this.WasPlus = 1; + bWasExpr = false; + this.AddToStream(" " + type + " "); + bCanLeftSide = false; + bCanDot = false; + break; + case "++": + case "--": + if(this.WasEnter) + if(bWasExpr) + { + type = ";"; + break Main; + } + if(bWasExpr) + if(!bCanDot) + this.Error("Invalid left-side argument before token: '%1'", type); + this.AddToStream(type); + bCanLeftSide = false; + bCanDot = false; + break; + case "in": + case "of": + case "instanceof": + if(!bWasExpr) + this.Error("Invalid argument before: '%1'", type); + this.AddToStream(" " + type + " "); + this.ParseExpressionWithComma(false, false); + bWasExpr = true; + bCanLeftSide = false; + bCanDot = false; + break; + case ",": + case ";": + case ")": + case "]": + case "}": + case ":": + case this.enEndFile: + break Main; + default: + this.Error("Unexpected token: '%1'", type); + } + this.WasEnter = false; + } + if(sConditions) + { + if(sConditions.indexOf(type) == - 1) + { + if(type == this.enOperator) + this.Error("Unexpected keywords: '%1'", Name); + else + { + var str = this.GetTokenName(type); + if(str == type) + this.Error("Error expression closing. Unexpected token: '%1'", str); + else + this.Error("Error expression closing. Unexpected %1", str); + } + } + } + else + { + this.BackPos(); + } + if(!bCanEmpty && !bWasExpr) + { + var str; + if(type == this.enOperator) + str = Name; + else + { + str = this.GetTokenName(type); + } + if(str == type) + this.Error("Require expression before token: '%1'", str); + else + this.Error("Require expression before: %1", str); + } + return type; + }; + this.GetTokenName = function (type) + { + switch(type) + { + case this.enNumber: + return "number"; + case this.enIndenifier: + return "indenifier"; + case this.enString: + return "string"; + case this.enRegular: + return "regular"; + case this.enEndFile: + return "End of file"; + default: + return type; + } + }; + this.RequireChar = function (sFind) + { + var type = this.PosNextToken(); + if(type != sFind) + this.Error("Require token: '%1'", sFind); + }; + this.RequireIndenifier = function (Name,DopStr) + { + var type = this.PosNextToken(); + if(type != this.enIndenifier || (Name && this.value != Name)) + { + if(Name) + this.Error("Require indenifier: '%1'", Name); + else + this.Error("Require indenifier"); + } + if(DopStr) + this.AddToStream(DopStr + this.value); + else + this.AddToStream(this.value); + return this.value; + }; + this.RequireIndenifierOptional = function () + { + var type = this.PosNextToken(); + if(type != this.enIndenifier) + { + this.BackPos(); + } + else + { + this.AddToStream(" " + this.value); + } + }; + this.HasEnter = function () + { + this.PosNextToken(); + this.BackPos(); + return this.WasEnter; + }; + this.Parse_var = function () + { + this.AddToStream("var "); + while(true) + { + this.RequireIndenifier(undefined, LOC_ADD_NAME); + var type = this.PosNextToken(); + this.AddToStream(type); + if(type === "=") + this.ParseExpressionWithComma(false, false); + if(type !== ",") + { + break; + } + } + }; + this.Parse_function = function (bGetSet,bFindExternal) + { + if(!bGetSet) + { + this.AddToStream("function "); + } + var FuncName; + var type = this.PosNextToken(); + if(type == this.enIndenifier) + { + FuncName = this.value; + if(bGetSet) + this.AddToStream(FuncName); + else + this.AddToStream(LOC_ADD_NAME + FuncName); + type = this.PosNextToken(); + } + else + if(bGetSet) + { + this.Error("Require name before: '%1'", type); + } + if(type != "(") + this.Error("Require token: '%1'", "("); + this.AddToStream("("); + var bMustIdentifier = false; + while(true) + { + type = this.PosNextToken(); + if(type == this.enIndenifier) + { + var Name = this.value; + this.AddToStream(LOC_ADD_NAME + Name); + type = this.PosNextToken(); + if(type == ",") + { + this.AddToStream(","); + bMustIdentifier = true; + continue; + } + bMustIdentifier = false; + } + else + if(bMustIdentifier) + { + this.Error("Require indenifier"); + break; + } + if(type == ")") + break; + this.Error("Require indenifier"); + } + if(FuncName && bFindExternal) + { + this.FunctionMap[FuncName] = 1; + type = this.PosNextToken(); + if(this.value === 'public') + { + this.ExternMap[FuncName] = 1; + } + else + { + this.BackPos(); + } + } + this.RequireChar("{"); + this.AddNewLineToStream(")\n", true); + this.AddNewLineToStream("{\n", true); + if(this.InjectCheck) + { + this.AddCheckLineToStream(30); + } + this.ParseBlock("}", false, false, false); + this.AddNewLineToStream("\n"); + this.AddToStream("}", "} "); + return FuncName; + }; + this.ParseFunctionCall = function (bCanEmpty) + { + this.AddToStream("("); + this.ParseExpressionWithComma(")", true); + this.AddToStream(")"); + }; + this.Parse_void = function () + { + this.AddToStream("void "); + var type = this.ParseExpression(); + }; + this.Parse_new = function () + { + this.AddToStream("new "); + var type = this.ParseExpression(); + }; + this.Parse_delete = function () + { + this.AddToStream("delete "); + this.ParseExpression(); + }; + this.ParseIfCondition = function () + { + this.AddToStream(" ? "); + this.ParseExpression(":"); + this.AddToStream(" : "); + this.ParseExpression(); + }; + this.ParseDefArray = function () + { + this.AddToStream("["); + this.ParseExpressionWithComma("]", true); + this.AddToStream("]"); + }; + this.ParseDefObject = function () + { + this.BlockLevel++; + this.AddToStream("{"); + while(true) + { + var type = this.PosNextToken(); + if(type == this.enIndenifier || type == this.enString || type == this.enNumber) + { + var Name = this.value; + if(Name === "get" || Name === "set") + { + type = this.PosNextToken(); + if(type == ":") + { + this.AddToStream(Name + ":"); + type = this.ParseExpression(",}"); + } + else + { + this.AddToStream(Name + " "); + this.BackPos(); + this.Parse_function(true); + type = this.PosNextToken(); + } + } + else + { + this.RequireChar(":"); + this.AddToStream(Name + ":"); + type = this.ParseExpression(",}"); + } + } + if(type == "}") + break; + else + if(type == ",") + { + if(this.CountCol <= this.PrintMargin) + this.AddToStream(", "); + else + this.AddNewLineToStream(",\n", true); + continue; + } + else + { + this.Error("Unexpected token: '%1'", this.GetTokenName(type)); + break; + } + } + this.BlockLevel--; + this.AddToStream("}", "} "); + }; + this.Parse_break = function () + { + this.AddToStream("break"); + if(this.HasEnter()) + return ; + this.RequireIndenifierOptional(); + }; + this.Parse_continue = function () + { + this.AddToStream("continue"); + if(this.HasEnter()) + return ; + this.RequireIndenifierOptional(); + }; + this.Parse_return = function () + { + this.AddToStream("return "); + if(this.HasEnter()) + return ; + this.ParseExpressionWithComma(false, true); + }; + this.Parse_typeof = function () + { + this.AddToStream("typeof "); + this.ParseExpression(); + }; + this.Parse_for = function () + { + this.AddToStream("for("); + this.RequireChar("("); + var bForInMode = false; + var bWasVar = false; + var bWasName; + var posSave = this.pos; + var type = this.PosNextToken(); + if(type == this.enIndenifier) + { + if(this.value == "var") + { + type = this.PosNextToken(); + bWasVar = true; + } + if(type == this.enIndenifier) + { + bWasName = this.value; + type = this.PosNextToken(); + if(type == this.enIndenifier && (this.value == "in" || this.value == "of")) + bForInMode = true; + } + } + if(bForInMode) + { + if(bWasVar) + this.AddToStream("var "); + this.AddToStream(LOC_ADD_NAME + bWasName + " " + this.value + " "); + } + else + { + this.pos = posSave; + var type = this.ParseBlock(";", true, true); + if(type == ";") + this.NotBackPos(); + this.AddToStream("; "); + this.ParseExpressionWithComma(";", true); + this.AddToStream("; "); + } + this.ParseExpressionWithComma(")", true); + this.AddToStream(")"); + this.ParseOneBlock(); + }; + this.Parse_while = function () + { + this.RequireChar("("); + this.AddToStream("while("); + this.ParseExpressionWithComma(")"); + this.AddToStream(")"); + this.ParseOneBlock(); + }; + this.Parse_do = function () + { + this.AddToStream("do"); + this.ParseOneBlock(); + this.RequireIndenifier("while"); + this.RequireChar("("); + this.AddToStream("("); + this.ParseExpressionWithComma(")"); + this.AddToStream(")"); + }; + this.Parse_if = function () + { + this.AddToStream("if("); + this.RequireChar("("); + this.ParseExpressionWithComma(")"); + this.AddToStream(")"); + this.ParseOneBlock(); + var type = this.PosNextToken(); + if(type == this.enIndenifier && this.ProcessWords[this.value] == "else") + { + this.AddToStream("else"); + this.ParseOneBlock(); + } + else + { + this.BackPos(); + } + }; + this.Parse_switch = function () + { + this.RequireChar("("); + this.AddToStream("switch("); + this.ParseExpressionWithComma(")"); + this.RequireChar("{"); + this.AddNewLineToStream(")\n", true); + this.AddNewLineToStream("{\n", true); + this.BlockLevel++; + this.ParseBlock("}", false, false, true); + this.BlockLevel--; + this.AddNewLineToStream("}\n", true); + }; + this.Parse_case = function () + { + this.BlockLevel--; + this.AddToStream("case "); + this.ParseExpressionWithComma(":"); + this.AddNewLineToStream(":\n", true); + this.BlockLevel++; + }; + this.Parse_default = function () + { + this.RequireChar(":"); + this.BlockLevel--; + this.AddNewLineToStream("default:\n", true); + this.BlockLevel++; + }; + this.Parse_with = function () + { + this.RequireChar("("); + this.AddToStream("with("); + this.ParseExpressionWithComma(")"); + this.AddToStream(")"); + this.ParseOneBlock(); + }; + this.Parse_try = function () + { + this.Error("try-catch not support"); + return ; + this.RequireChar("{"); + this.AddToStream("try\n"); + this.AddNewLineToStream("{\n", true); + this.ParseBlock("}"); + this.AddNewLineToStream("}\n", true); + var type = this.PosNextToken(); + if(type == this.enIndenifier && this.ProcessWords[this.value] == "catch") + { + this.AddToStream("catch("); + this.RequireChar("("); + this.RequireIndenifier(); + this.RequireChar(")"); + this.AddNewLineToStream(")\n", true); + this.AddNewLineToStream("{\n", true); + this.RequireChar("{"); + this.ParseBlock("}"); + this.AddToStream("}"); + type = this.PosNextToken(); + } + if(type == this.enIndenifier && this.ProcessWords[this.value] == "finally") + { + this.RequireChar("{"); + this.AddNewLineToStream("\n"); + this.AddNewLineToStream("finally\n", true); + this.AddNewLineToStream("{\n", true); + this.ParseBlock("}"); + this.AddToStream("}"); + } + else + { + this.BackPos(); + } + }; + this.Parse_throw = function () + { + this.AddToStream("throw "); + if(this.HasEnter()) + return ; + var type = this.ParseExpressionWithComma(); + }; + this.AddCheckLineToStream = function (Count) + { + if(this.InjectCheck) + { + if(!Count) + Count = 1; + this.CalculateLineNumber(); + this.AddToStream("DO(" + Count + ");"); + } + }; + this.CalculateLineNumber = function () + { + for(var i = this.posLineNumber; i < this.pos; i++) + if(this.buf[i] == "\n") + this.LineNumber++; + this.posLineNumber = this.pos; + }; + this.CalculateLineNumber0 = function (str) + { + for(var i = 0; i < str.length; i++) + if(str[i] == "\n") + this.LineNumber++; + }; + this.AddCheckToStream = function (str) + { + if(this.InjectCheck) + { + this.AddToStream(str); + } + }; + this.AddToStreamSimple = function (str,strMustLast) + { + if(strMustLast) + this.LastStreamValue = strMustLast; + else + this.LastStreamValue = str; + if(!this.IgnoreCodeLevel) + this.stream += str; + }; + this.AddToStreamAddTab = function (str,strMustLast) + { + if(this.LastStreamValue[this.LastStreamValue.length - 1] == "\n") + { + this.CountCol = 0; + if(!this.IgnoreCodeLevel) + this.stream += this.SpacesArray[this.BlockLevel >= 100 ? 99 : this.BlockLevel]; + } + if(str[str.length - 1] == "\n") + { + this.CountCol = 0; + } + else + { + this.CountCol += str.length; + } + this.AddToStreamSimple(str, strMustLast); + }; + this.AddNewLineToStream = function (str,bAlways) + { + var sLast = this.LastStreamValue[this.LastStreamValue.length - 1]; + if(bAlways || sLast != "\n") + { + if(str == ";\n" && (sLast == "}" || sLast == ";")) + { + this.AddToStream("\n"); + } + else + { + this.AddToStream(str); + } + } + }; +}; +global.LexerJS = new module.exports(); diff --git a/src/HTML/JS/marked.js b/src/HTML/JS/marked.js new file mode 100644 index 0000000..9d82b6e --- /dev/null +++ b/src/HTML/JS/marked.js @@ -0,0 +1 @@ +!function(e){"use strict";var k={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:g,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:g,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:g,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function a(e){this.tokens=[],this.tokens.links=Object.create(null),this.options=e||d.defaults,this.rules=k.normal,this.options.pedantic?this.rules=k.pedantic:this.options.gfm&&(this.options.tables?this.rules=k.tables:this.rules=k.gfm)}k._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,k._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,k.def=t(k.def).replace("label",k._label).replace("title",k._title).getRegex(),k.bullet=/(?:[*+-]|\d+\.)/,k.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,k.item=t(k.item,"gm").replace(/bull/g,k.bullet).getRegex(),k.list=t(k.list).replace(/bull/g,k.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+k.def.source+")").getRegex(),k._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",k._comment=//,k.html=t(k.html,"i").replace("comment",k._comment).replace("tag",k._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),k.paragraph=t(k.paragraph).replace("hr",k.hr).replace("heading",k.heading).replace("lheading",k.lheading).replace("tag",k._tag).getRegex(),k.blockquote=t(k.blockquote).replace("paragraph",k.paragraph).getRegex(),k.normal=f({},k),k.gfm=f({},k.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/}),k.gfm.paragraph=t(k.paragraph).replace("(?!","(?!"+k.gfm.fences.source.replace("\\1","\\2")+"|"+k.list.source.replace("\\1","\\3")+"|").getRegex(),k.tables=f({},k.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),k.pedantic=f({},k.normal,{html:t("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",k._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),a.rules=k,a.lex=function(e,t){return new a(t).lex(e)},a.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},a.prototype.token=function(e,t){var n,r,s,i,l,o,a,h,p,c,u,g,f,d,b,m;for(e=e.replace(/^ +$/gm,"");e;)if((s=this.rules.newline.exec(e))&&(e=e.substring(s[0].length),1 ?/gm,""),this.token(s,t),this.tokens.push({type:"blockquote_end"});else if(s=this.rules.list.exec(e)){for(e=e.substring(s[0].length),a={type:"list_start",ordered:d=1<(i=s[2]).length,start:d?+i:"",loose:!1},this.tokens.push(a),n=!(h=[]),f=(s=s[0].match(this.rules.item)).length,u=0;u?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:g,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)|^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)/,em:/^_([^\s_])_(?!_)|^\*([^\s*"<\[])\*(?!\*)|^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s"<\[][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*"<\[][\s\S]*?[^\s])\*(?!\*)/,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:g,text:/^(`+|[^`])[\s\S]*?(?=[\\?@\[\]\\^_`{|}~])/g,n._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,n._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,n.autolink=t(n.autolink).replace("scheme",n._scheme).replace("email",n._email).getRegex(),n._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,n.tag=t(n.tag).replace("comment",k._comment).replace("attribute",n._attribute).getRegex(),n._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,n._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f\\]*\)|[^\s\x00-\x1f()\\])*?)/,n._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,n.link=t(n.link).replace("label",n._label).replace("href",n._href).replace("title",n._title).getRegex(),n.reflink=t(n.reflink).replace("label",n._label).getRegex(),n.normal=f({},n),n.pedantic=f({},n.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:t(/^!?\[(label)\]\((.*?)\)/).replace("label",n._label).getRegex(),reflink:t(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",n._label).getRegex()}),n.gfm=f({},n.normal,{escape:t(n.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~+(?=\S)([\s\S]*?\S)~+/,text:t(n.text).replace("]|","~]|").replace("|$","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|$").getRegex()}),n.gfm.url=t(n.gfm.url).replace("email",n.gfm._extended_email).getRegex(),n.breaks=f({},n.gfm,{br:t(n.br).replace("{2,}","*").getRegex(),text:t(n.gfm.text).replace("{2,}","*").getRegex()}),h.rules=n,h.output=function(e,t,n){return new h(t,n).output(e)},h.prototype.output=function(e){for(var t,n,r,s,i,l,o="";e;)if(i=this.rules.escape.exec(e))e=e.substring(i[0].length),o+=i[1];else if(i=this.rules.autolink.exec(e))e=e.substring(i[0].length),r="@"===i[2]?"mailto:"+(n=c(this.mangle(i[1]))):n=c(i[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(i=this.rules.url.exec(e))){if(i=this.rules.tag.exec(e))!this.inLink&&/^/i.test(i[0])&&(this.inLink=!1),!this.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(i[0])?this.inRawBlock=!0:this.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(i[0])&&(this.inRawBlock=!1),e=e.substring(i[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(i[0]):c(i[0]):i[0];else if(i=this.rules.link.exec(e))e=e.substring(i[0].length),this.inLink=!0,r=i[2],s=this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],t[3]):"":i[3]?i[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),o+=this.outputLink(i,{href:h.escapes(r),title:h.escapes(s)}),this.inLink=!1;else if((i=this.rules.reflink.exec(e))||(i=this.rules.nolink.exec(e))){if(e=e.substring(i[0].length),t=(i[2]||i[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=i[0].charAt(0),e=i[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(i,t),this.inLink=!1}else if(i=this.rules.strong.exec(e))e=e.substring(i[0].length),o+=this.renderer.strong(this.output(i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.em.exec(e))e=e.substring(i[0].length),o+=this.renderer.em(this.output(i[6]||i[5]||i[4]||i[3]||i[2]||i[1]));else if(i=this.rules.code.exec(e))e=e.substring(i[0].length),o+=this.renderer.codespan(c(i[2].trim(),!0));else if(i=this.rules.br.exec(e))e=e.substring(i[0].length),o+=this.renderer.br();else if(i=this.rules.del.exec(e))e=e.substring(i[0].length),o+=this.renderer.del(this.output(i[1]));else if(i=this.rules.text.exec(e))e=e.substring(i[0].length),this.inRawBlock?o+=this.renderer.text(i[0]):o+=this.renderer.text(c(this.smartypants(i[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else{if("@"===i[2])r="mailto:"+(n=c(i[0]));else{for(;l=i[0],i[0]=this.rules._backpedal.exec(i[0])[0],l!==i[0];);n=c(i[0]),r="www."===i[1]?"http://"+n:n}e=e.substring(i[0].length),o+=this.renderer.link(r,null,n)}return o},h.escapes=function(e){return e?e.replace(h.rules._escapes,"$1"):e},h.prototype.outputLink=function(e,t){var n=t.href,r=t.title?c(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,c(e[1]))},h.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"â€").replace(/\.{3}/g,"…"):e},h.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;s'+(n?e:c(e,!0))+"\n":"
"+(n?e:c(e,!0))+"
"},r.prototype.blockquote=function(e){return"
\n"+e+"
\n"},r.prototype.html=function(e){return e},r.prototype.heading=function(e,t,n){return this.options.headerIds?"'+e+"\n":""+e+"\n"},r.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},r.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},r.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},r.prototype.checkbox=function(e){return" "},r.prototype.paragraph=function(e){return"

    "+e+"

    \n"},r.prototype.table=function(e,t){return t&&(t="
    "+t+""),"
    \n\n"+e+"\n"+t+"
    \n"},r.prototype.tablerow=function(e){return"\n"+e+"\n"},r.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},r.prototype.strong=function(e){return""+e+""},r.prototype.em=function(e){return""+e+""},r.prototype.codespan=function(e){return""+e+""},r.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},r.prototype.del=function(e){return""+e+""},r.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(u(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!o.test(e)&&(e=i(this.options.baseUrl,e));try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return n}var s='
    "},r.prototype.image=function(e,t,n){this.options.baseUrl&&!o.test(e)&&(e=i(this.options.baseUrl,e));var r=''+n+'":">"},r.prototype.text=function(e){return e},s.prototype.strong=s.prototype.em=s.prototype.codespan=s.prototype.del=s.prototype.text=function(e){return e},s.prototype.link=s.prototype.image=function(e,t,n){return""+n},s.prototype.br=function(){return""},p.parse=function(e,t){return new p(t).parse(e)},p.prototype.parse=function(e){this.inline=new h(e.links,this.options),this.inlineText=new h(e.links,f({},this.options,{renderer:new s})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},p.prototype.next=function(){return this.token=this.tokens.pop()},p.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},p.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},p.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,u(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s="",i="";for(n="",e=0;e"']/,c.escapeReplace=/[&<>"']/g,c.replacements={"&":"&","<":"<",">":">",'"':""","'":"'"},c.escapeTestNoEncode=/[<>"']|&(?!#?\w+;)/,c.escapeReplaceNoEncode=/[<>"']|&(?!#?\w+;)/g;var l={},o=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;function g(){}function f(e){for(var t,n,r=1;rt)n.splice(t);else for(;n.lengthAn error occurred:

    "+c(e.message+"",!0)+"
    ";throw e}}g.exec=g,d.options=d.setOptions=function(e){return f(d.defaults,e),d},d.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new r,sanitize:!0,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},d.defaults=d.getDefaults(),d.Parser=p,d.parser=p.parse,d.Renderer=r,d.TextRenderer=s,d.Lexer=a,d.lexer=a.lex,d.InlineLexer=h,d.inlineLexer=h.output,d.parse=d,"undefined"!=typeof module&&"object"==typeof exports?module.exports=d:"function"==typeof define&&define.amd?define(function(){return d}):e.marked=d}(this||("undefined"!=typeof window?window:global)); \ No newline at end of file diff --git a/src/HTML/JS/mobile-wallet.js b/src/HTML/JS/mobile-wallet.js new file mode 100644 index 0000000..ce2ed6b --- /dev/null +++ b/src/HTML/JS/mobile-wallet.js @@ -0,0 +1,1099 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var SaveIdArr = ["idAccount", "idTo", "idSumSend", "idDescription", "idCurTabName", "idViewBlockNum", "idViewAccountNum", "idViewDappNum", +"idLang"]; +var CONFIG_DATA = {PRICE_DAO:{NewAccount:10}, MaxNumBlockDB:0, MaxAccID:0, MaxDappsID:0}; +var CountViewRows = 20; +var DefAccounts = {BlockName:"idPaginationAccount", NumName:"idViewAccountNum", TabName:"explorer_accounts", APIName:"GetAccountList"}; +var DefBlock = {BlockName:"idPaginationBlock", NumName:"idViewBlockNum", TabName:"explorer_blocks", APIName:"GetBlockList"}; +var DefDapps = {BlockName:"idPaginationDapps", NumName:"idViewDappNum", TabName:"dapps_list", APIName:"GetDappList", CountViewRows:10, + FilterName:"idCategory"}; + +function SetImg() +{ +}; +var CONNECT_STATUS = 0; +var NotModalClose = 0; +window.onload = function () +{ + InitAccountsCard(); + DoLangScript(); + InitWalletKeyName(); + if(Storage.getItem("NETWORK") || IsLocalClient()) + { + OnLoad(); + } + else + { + GetData("/GetCurrentInfo", {}, function (Data) + { + if(Data && Data.result) + { + Storage.setItem("NETWORK", Data.NETWORK); + console.log("Default network: " + Data.NETWORK); + OnLoad(); + } + }); + } + var HasPassword = IsLockedWallet(); + if(HasPassword) + { + NotModalClose = 1; + openModal('password-modal-enter'); + } + else + { + OpenWalletKey(); + } + SetUsePassword(HasPassword); + window.onkeydown = function (e) + { + if(e.keyCode === 27) + { + if(IsVisibleBlock("overlay")) + closeModal(); + } + }; + $("idAccountsList").addEventListener("click", MyToggleList); +}; + +function OnLoad() +{ + if(Storage.getItem("NETWORK")) + { + NETWORK = Storage.getItem("NETWORK"); + } + $("idCurNetwork").value = NETWORK; + LoadValues(); + InitDappsCard(); + StartWebWallet(); + UpdatesExplorerData(); + UpdatesAccountsData(); + setInterval(UpdatesExplorerData, 1000); + setInterval(UpdatesAccountsData, 1000); + DoStableScroll(); + window.onmousemove = function (event) + { + SetDiagramMouseX(event); + }; + if(window.location.hash) + { + var LocationPath = window.location.hash.substr(1); + if(LocationPath) + { + SelectTab(LocationPath); + } + } +}; + +function ChangeNetwork() +{ + CONNECT_STATUS = 0; + NETWORK = $("idCurNetwork").value; + Storage.setItem("NETWORK", NETWORK); + StartWebWallet(); + UpdatesExplorerData(); + UpdatesAccountsData(); +}; + +function OnFindServer() +{ + if(!MainServer) + { + CONNECT_STATUS = - 1; + SetStatus("Server not found"); + Storage.setItem("MainServer", undefined); + return ; + } + CONNECT_STATUS = 2; + Storage.setItem("MainServer", JSON.stringify({ip:MainServer.ip, port:MainServer.port})); + FillCurrencyAsync("idAccountCur"); +}; + +function LoadValues() +{ + var StrDelList = localStorage["DelList"]; + if(StrDelList) + DelList = JSON.parse(StrDelList); + if(LoadValuesByArr(SaveIdArr)) + { + ChangeLang(); + } + InitPrivKey(); +}; + +function SaveValues() +{ + SaveValuesByArr(SaveIdArr); + localStorage["DelList"] = JSON.stringify(DelList); +}; +var TabArr = [{name:"TabWelcome"}, {name:"TabWalletSet"}, {name:"TabKeySet"}, {name:"TabAccounts"}, {name:"TabSend"}, {name:"TabDapps"}, + {name:"TabExplorer"}, {name:"TabLogo"}]; + +function SelectTab(name) +{ + SetStatus(""); + $("idCurTabName").value = name; + SetVisibleTab(); + SaveValues(); + OnSelectTab(name); + if(name && history.pushState) + history.pushState(null, null, "#" + name); +}; + +function OnSelectTab(name) +{ + if(!GetPrivKey()) + { + GenerateKeyNew(); + SetPrivKey($("idPrivKeyEdit").value.trim()); + InitPrivKey(); + } + if(name === "TabDapps") + { + ViewDapps(); + } +}; + +function SetVisibleTab() +{ + var CurTabName = $("idCurTabName").value; + if(!CurTabName || CurTabName === "undefined") + CurTabName = TabArr[0].name; + var str; + for(var i = 0; i < TabArr.length; i++) + { + var name = TabArr[i].name; + var Item = $(name); + if(!Item) + continue; + if(CurTabName === name) + { + Item.style.display = 'block'; + str = "active"; + } + else + { + Item.style.display = 'none'; + str = ""; + } + var ItemM = $("M" + name); + if(ItemM) + { + if(str) + { + ItemM.classList.add(str); + } + else + { + ItemM.classList.remove("active"); + } + } + } +}; + +function IsPrivateMode() +{ + var PrivKeyStr = GetPrivKey(); + if(PrivKeyStr && PrivKeyStr.length === 64) + return 1; + else + return 0; +}; + +function SetVisiblePrivKey() +{ + if(bShowPrivKey) + $("idPrivKeyStatic").innerText = GetPrivKey(); + else + $("idPrivKeyStatic").innerText = "••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••"; +}; +var bShowPrivKey = 0; + +function OnVisiblePrivKey() +{ + bShowPrivKey = !bShowPrivKey; + SetVisiblePrivKey(); +}; + +function SetPubKeyHTML() +{ + $("idPubKeyStatic").innerText = GetPubKey(); +}; + +function GenerateKeyNew() +{ + var arr = new Uint8Array(32); + window.crypto.getRandomValues(arr); + var Str = GetHexFromArr(sha3(arr)); + $("idPrivKeyEdit").value = Str; +}; + +function OnGenerateKeyNew() +{ + GenerateKeyNew(); +}; + +function OnEditPrivKey() +{ +}; + +function OnPrivKeyOK() +{ + SetPrivKey($("idPrivKeyEdit").value.trim()); + InitPrivKey(); + SelectTab('TabKeySet'); + ClearSend(); +}; + +function OnPrivKeyCancel() +{ + InitPrivKey(); + SelectTab('TabKeySet'); +}; +var FirstAccountsData = 1; +var AccountsCount = - 1; + +function UpdatesAccountsData() +{ + if(IsVisibleClass(".accounts-info__add")) + return ; + if(!CONNECT_STATUS) + return ; + var Str = GetPubKey(); + if(!Str) + { + return ; + } + GetData("/GetAccountListByKey", {Key:Str, AllData:FirstAccountsData}, function (Data,responseText) + { + if(!Data || !Data.result || !Data.arr) + return ; + if(AccountsCount === Data.arr.length) + { + if(IsVisibleClass(".accounts-info__add2")) + return ; + } + AccountsCount = Data.arr.length; + SetVisibleClass(".accounts-info__acc-list", AccountsCount); + SetVisibleClass(".accounts-info__empty", !AccountsCount); + SetVisibleClass(".accounts-info__add2", 0); + if(AccountsCount) + { + SetAccountsCard(Data, responseText); + } + else + { + if(FirstAccountsData && !Data.arr.length) + { + SelectTab('TabAccounts'); + } + } + FirstAccountsData = 0; + }); +}; + +function ViewAddAccount(Visible) +{ + SetVisibleClass(".accounts-info__add", Visible); + SetVisibleClass(".accounts-info__acc-list", !Visible); + SetVisibleClass(".accounts-info__empty", 0); +}; + +function OnViewAddAccount() +{ + OnChangeAccName(); + ViewAddAccount(1); + $("idAccountName").focus(); +}; + +function CancelAddAccount() +{ + ViewAddAccount(0); +}; + +function OnChangeAccName() +{ + $("idBtAddAccount").disabled = !($("idAccountName").value.length); +}; + +function CancelCreateAccount() +{ +}; + +function OnAddAccount() +{ + var Name = $("idAccountName").value; + if(!Name) + { + SetError("Enter the account name"); + return ; + } + var Smart = 0; + var Currency = ParseNum($("idAccountCur").value); + SetStatus("Calculate Tx, wait pls ..."); + SendTrCreateAccWait(Currency, GetPubKey(), Name, Smart); + SetVisibleClass(".accounts-info__add", 0); + SetVisibleClass(".accounts-info__add2", 1); +}; +var WasAccountsDataStr; +var StrAccCardTemplate; + +function InitAccountsCard() +{ + if($("AccCardTemplate")) + { + StrAccCardTemplate = $("AccCardTemplate").outerHTML; + $("AccCardTemplate").outerHTML = ""; + } +}; + +function SetAccountsCard(Data,AccountsDataStr) +{ + if(!Data || !Data.result) + { + return ; + } + if(AccountsDataStr === WasAccountsDataStr) + return ; + WasAccountsDataStr = AccountsDataStr; + var arr = []; + for(var i = 0; Data.arr && i < Data.arr.length; i++) + { + var Item = Data.arr[i]; + if(!DelList[Item.Num]) + { + arr.push(Item); + } + } + var Select = $("idAccount"); + if(arr.length !== Select.options.length) + { + var options = Select.options; + options.length = arr.length; + } + MaxBlockNum = GetCurrentBlockNumByTime(); + $("idListCount").innerText = arr.length; + var StrList = ""; + var ListTotal = {}; + for(var i = 0; arr && i < arr.length; i++) + { + var Item = arr[i]; + Item.MyAccount = true; + var Num = ParseNum(Item.Num); + if(!MapAccounts[Num]) + MapAccounts[Num] = {}; + CopyObjKeys(MapAccounts[Num], Item); + var option = Select.options[i]; + var StrText = GetAccountText(Item, Num, 1); + if(option.text !== StrText) + CheckNameAccTo(); + option.value = Num; + option.text = StrText; + var Str = StrAccCardTemplate; + Str = Str.replace("AccCardTemplate", "idCard" + Item.Num); + Str = Str.replace(/{Item.Num}/g, Item.Num); + Str = Str.replace("{Value.SumCOIN}", Item.Value.SumCOIN); + Str = Str.replace("{Value.SumCENT}", Item.Value.SumCENT); + Str = Str.replace("{Value.CurrencyName}", CurrencyName(Item.Currency)); + var CurrencyObj = Item.CurrencyObj; + if(!CurrencyObj) + CurrencyObj = {IconBlockNum:0, Num:0}; + Str = Str.replace("{Value.CurrencyIconPath}", RetIconPath(CurrencyObj, 1)); + var CurrencyPath = RetIconPath(CurrencyObj); + if(CurrencyPath.substr(0, 6) !== "/file/") + Str = Str.replace("prod-card__currency--with-dot", ""); + Str = Str.replace("{Item.Name}", escapeHtml(Item.Name)); + var SmartObj = Item.SmartObj; + if(!SmartObj) + SmartObj = {Name:"", Num:0}; + SmartObj.IconPath = RetIconPath(SmartObj, 0); + Str = Str.replace("{SmartObj.IconPath}", SmartObj.IconPath); + Str = Str.replace("{SmartObj.Name}", escapeHtml(SmartObj.Name)); + Str = Str.replace(/{SmartObj.Num}/g, SmartObj.Num); + if(SmartObj.Num) + { + Str = Str.replace("prod-card__link--connect", "myhidden"); + } + else + { + Str = Str.replace("prod-card__link--dapp", "myhidden"); + Str = Str.replace("prod-card__dropdown", "prod-card__dropdown nodapp"); + } + StrList += Str; + Str = ""; + var Total = ListTotal[Item.Currency]; + if(!Total) + { + Total = {SumCOIN:0, SumCENT:0, Name:CurrencyName(Item.Currency)}; + ListTotal[Item.Currency] = Total; + } + ADD(Total, Item.Value); + } + $("idAccountsList").innerHTML = StrList; + StrList = ""; + var StrTotal = ""; + for(var key in ListTotal) + { + var Total = ListTotal[key]; + StrTotal += '
    ' + Total.Name + '
    ' + STRING_FROM_COIN(Total) + '
    '; + } + $("idTotalList").innerHTML = StrTotal; + var CurentValue = LoadMapAfter["idAccount"]; + if(CurentValue) + { + Select.value = CurentValue; + delete LoadMapAfter["idAccount"]; + } +}; + +function ConnectSmart(NumAccount) +{ + ChangeSmart(NumAccount, 0); +}; + +function SetSmart(NumAccount,WasSmart) +{ + ChangeSmart(NumAccount, WasSmart); +}; + +function DelSmart(NumAccount,WasSmart) +{ + SetSmartToAccount(NumAccount, 0); +}; + +function DelAccount(NumAccount) +{ + DelList[NumAccount] = 1; + AccountsCount = 0; + WasAccountsDataStr = ""; + SaveValues(); +}; + +function RestoreAllAccounts() +{ + DelList = {}; + DelAccount(0); +}; + +function UpdatesExplorerData() +{ + var WasSendTr = 0; + for(var key in MapSendTransaction) + { + var Item = MapSendTransaction[key]; + if(!Item.WasProcess && !Item.final) + { + WasSendTr = 1; + break; + } + } + GetData("GetCurrentInfo", {Diagram:IsVisibleBlock("idStatBlock") ? 1 : 0, ArrLog:WasSendTr}, function (Data) + { + if(!Data || !Data.result) + return ; + SetExplorerData(Data); + SetBlockChainConstant(Data); + var arr = Data.arr; + for(var i = 0; arr && i < arr.length; i++) + { + var ItemServer = arr[i]; + var ItemClient = DiagramMap[ItemServer.name]; + if(!ItemClient || ItemClient.Extern) + continue; + ItemClient.arr = ItemServer.arr; + ItemClient.AvgValue = ItemServer.AvgValue; + ItemClient.steptime = ItemServer.steptime; + ItemClient.fillStyle = "white"; + DrawDiagram(ItemClient); + } + }); +}; +var FirstCallDiagram = 1; + +function SetExplorerData(Data) +{ + if(!Data || !Data.result) + return ; + CONFIG_DATA = Data; + window.FIRST_TIME_BLOCK = Data.FIRST_TIME_BLOCK; + if(FirstCallDiagram) + { + ViewEnd(DefAccounts, CONFIG_DATA.MaxAccID, 1); + ViewEnd(DefBlock, CONFIG_DATA.MaxNumBlockDB, 1); + InitDiagram(); + } + FirstCallDiagram = 0; + var StrVersion = " 0." + Data.VersionNum; + $("idBHeight").innerText = Data.MaxNumBlockDB; + $("idBCurrent").innerText = Data.CurBlockNum; + $("idBVersion").innerText = StrVersion; + SetArrLog(Data.ArrLog); +}; + +function SetArrLog(arr) +{ + if(!arr) + return ; + for(var i = 0; i < arr.length; i++) + { + var Item = arr[i]; + if(!Item.final) + continue; + var TR = MapSendTransaction[Item.key]; + if(TR && !TR.WasProcess && Item.final) + { + TR.WasProcess = 1; + SetStatus(Item.text); + if(Item.text.indexOf("Add to blockchain") >= 0) + { + if(TR.Run) + { + TR.Run(TR); + TR.Run = undefined; + } + } + var Account = MapCheckTransaction[Item.key]; + if(Account) + { + delete MapCheckTransaction[Item.key]; + Account.NextSendTime = 0; + } + } + } + CheckSending(); +}; +var DiagramArr = [{name:"MAX:ALL_NODES", text:"All nodes count", value:0, red:"#1d506b", MouseText:" nodes"}, {name:"MAX:HASH_RATE_B", + text:"HashRate, Tera hash/s", value:0, red:"#286b16", MathPow:2, MathDiv:1024 * 1024 * 1024 * 1024, KPrecision:10, NoTextMax:1, + MouseText:" T h/s"}, ]; + +function InitDiagram() +{ + InitDiagramByArr(DiagramArr, 1120); +}; + +function ViewCounters(This) +{ + var BlockName = "idStatBlock"; + var element = $(BlockName); + var bVisible = IsVisibleBlock(BlockName); + if(!bVisible) + MoveUp(element); + SetVisibleBlock(BlockName, !bVisible); + var ResVisible = IsVisibleBlock(BlockName); + if(This && This.className) + { + This.className = This.className.replace("btpress", ""); + if(ResVisible) + This.className += " btpress"; + } +}; +setInterval(CheckSending, 1000); + +function OpenAddressBook() +{ + return ; + var bVisible = IsVisibleBlock("idAddressBook"); + SetVisibleBlock("idAddressBook", !bVisible); +}; + +function CloaseAddressBook() +{ + OpenAddressBook(); +}; + +function ClearSend() +{ + $("idAccount").value = ""; + $("idTo").value = ""; + $("idSumSend").value = ""; + $("idDescription").value = ""; + $("idNameTo2").innerText = ""; +}; + +function downloadKey(fieldID) +{ + var text = document.getElementById(fieldID).value; + var blob = new Blob([text], {type:"text/plain"}); + var anchor = document.createElement("a"); + anchor.download = "tera-key.txt"; + anchor.href = window.URL.createObjectURL(blob); + anchor.target = "_blank"; + anchor.style.display = "none"; + document.body.appendChild(anchor); + anchor.click(); + document.body.removeChild(anchor); +}; + +function openModal(id) +{ + var modal = document.querySelector("#" + id); + var overlay = document.querySelector("#overlay"); + modal.style.display = "block"; + overlay.style.display = "block"; +}; + +function closeModal() +{ + if(NotModalClose) + return ; + var modals = document.querySelectorAll(".modal"); + var overlay = document.querySelector("#overlay"); + modals.forEach(function (item) + { + item.style.display = "none"; + }); + overlay.style.display = "none"; +}; + +function showMenu(Num) +{ + var menu = document.querySelector("#idBt" + Num); + if(menu.style.display === "none") + { + menu.style.display = "block"; + } + else + { + menu.style.display = "none"; + } +}; + +function closeMenu(Num) +{ + var menu = document.querySelector("#idBt" + Num); + setTimeout(function () + { + menu.style.display = "none"; + }, 115); +}; + +function UploadKey(id) +{ + var file = $(id).files[0]; + var reader = new FileReader(); + reader.onload = function () + { + if(reader.result.byteLength !== 64) + SetError("Error file length (" + reader.result.byteLength + ")"); + else + { + var view = new Uint8Array(reader.result); + var Key = Utf8ArrayToStr(view); + SetStatus("OK"); + ToLog("Result: " + Key); + SetPrivKey(Key); + InitPrivKey(); + $(id).value = ""; + } + }; + reader.readAsArrayBuffer(file); +}; + +function InitPrivKey() +{ + $("idPrivKeyEdit").value = GetPrivKey(); + SetPubKeyHTML(); + SetVisiblePrivKey(); + $("idSave2").disabled = !IsPrivateMode(); +}; + +function SendMobileBefore() +{ + if($("idSendButton").disabled) + return ; + var FromID = ParseNum($("idAccount").value); + var Item = MapAccounts[FromID]; + if(!Item) + { + SetError("Error FROM ID"); + return ; + } + $("idConfirmFromID").innerText = Item.Num; + $("idConfirmFromName").innerText = Item.Name + " (" + STRING_FROM_COIN(Item.Value) + " " + CurrencyNameItem(Item) + ")"; + var ToID = ParseNum($("idTo").value); + var Item2 = MapAccounts[ToID]; + if(!Item2) + { + SetError("Error TO ID"); + return ; + } + $("idConfirmToID").innerText = Item2.Num; + $("idConfirmToName").innerText = Item2.Name + " (" + STRING_FROM_COIN(Item2.Value) + " " + CurrencyNameItem(Item2) + ")"; + var CoinAmount = COIN_FROM_FLOAT($("idSumSend").value); + $("idConfirmAmount").innerText = STRING_FROM_COIN(CoinAmount); + $("idConfirmCurrency").innerText = CurrencyNameItem(Item); + $("idConfirmDescription").innerText = $("idDescription").value; + SetVisibleClass(".send-page__setting", 0); + SetVisibleClass(".send-page__confirm", 1); + SetStatus(""); +}; + +function OKSend() +{ + SendMoney(); + $("idSumSend").value = 0; + CancelSend(); +}; + +function CancelSend() +{ + SetVisibleClass(".send-page__setting", 1); + SetVisibleClass(".send-page__confirm", 0); +}; + +function SetNewPassword() +{ + var Str1 = $("Password1").value.trim(); + var Str2 = $("Password2").value.trim(); + if(Str1 !== Str2) + { + SetError("Wrong passwords"); + return ; + } + var Key = GetPrivKey(); + SetWalletPassword(Str1); + SetPrivKey(Key); + SetPubKeyHTML(); + closeModal(); + $("Password1").value = ""; + $("Password2").value = ""; + if(Str1) + SetStatus("Password changed successfully"); + else + SetStatus("Password has been reset successfully"); + SetUsePassword(Str1); +}; +var MultipleMode = 0; + +function MyOpenWallet(bCheck) +{ + var Str = $("Password").value.trim(); + if(!Str) + { + SetError("Type password, pls"); + return ; + } + $("Password").value = ""; + if(Str.substr(0, 11) === "--subwallet") + { + Str = Str.substr(11); + if(Str === " off") + { + Storage.setItem("USESUBWALLET", 0); + SetStatus("Set off subwallet mode"); + } + else + { + Storage.setItem("USESUBWALLET", 1); + SetStatus("Set subwallet mode"); + } + SetUsePassword(1); + return ; + } + if(Str === "--reset") + { + SetWalletPassword(""); + OpenWalletKey(); + SetUsePassword(0); + NotModalClose = 0; + closeModal(); + return ; + } + SetWalletPassword(Str); + OpenWalletKey(); + SetStatus(""); + if(bCheck) + { + var WasPubKey = Storage.getItem("WALLET_PUB_KEY_MAIN"); + var PrivKey = GetArrFromHex(GetPrivKey()); + var TestPubKey = GetHexFromArr(SignLib.publicKeyCreate(PrivKey, 1)); + if(WasPubKey !== TestPubKey) + { + SetWalletPassword(""); + SetError("Wrong password"); + return ; + } + SetStatus("Password ok"); + MultipleMode = 0; + SetVisibleBlock("idKeyEdit", 1); + SetVisibleBlock("idLoad2", 1); + SetVisibleBlock("idPasswordEdit", 1); + } + else + { + MultipleMode = 1; + SetVisibleBlock("idKeyEdit", 0); + SetVisibleBlock("idLoad2", 0); + SetVisibleBlock("idPasswordEdit", 0); + } + NotModalClose = 0; + closeModal(); + InitPrivKey(); + SetPubKeyHTML(); + SetUsePassword(1); +}; + +function SetUsePassword(bUse) +{ + document.documentElement.style.setProperty('--fill--password', bUse ? 'blue' : 'black'); + SetVisibleBlock("idWalletExit", !!bUse); + SetVisibleBlock("idEntrance", Storage.getItem("USESUBWALLET") === "1"); +}; + +function DoExitWallet() +{ + ClearSend(); + NotModalClose = 1; + $("Password").value = ""; + SetWalletPassword(""); + OpenWalletKey(); + openModal('password-modal-enter'); +}; +var StrDappCardTemplate; +var StrDappRowCardTemplate; +var CardMapList = {}; + +function InitDappsCard() +{ + if($("DappRowCardTemplate")) + { + StrDappRowCardTemplate = $("DappRowCardTemplate").outerHTML; + $("DappRowCardTemplate").outerHTML = ""; + } + if($("DappCardTemplate")) + { + StrDappCardTemplate = $("DappCardTemplate").outerHTML; + } +}; + +function ViewDapps() +{ + ViewCurrent(DefDapps); + GetData("/GetDappCategory", {}, function (Data) + { + if(Data && Data.result && Data.arr) + { + var arr = Data.arr; + for(var i = 0; i < arr.length; i++) + { + var key = arr[i]; + arr[i] = {sort:MapCategory[key].toUpperCase(), text:MapCategory[key], value:key}; + } + arr.push({sort:"-", text:"Choose the category", value:0}); + FillCategoryAndSort("idCategory", arr); + } + }); +}; + +function FillDappCard(Str,Item) +{ + CardMapList[Item.Num] = Item; + Str = Str.replace(/{Item.Num}/g, Item.Num); + Str = Str.replace("{Item.Name}", escapeHtml(Item.Name)); + Str = Str.replace("{Item.Description}", escapeHtml(Item.Description)); + Str = Str.replace("{Item.Owner}", Item.Owner); + if(!Item.TokenGenerate) + Str = Str.replace("dapp-modal__ok-token", "myhidden"); + Str = Str.replace("{Item.IconPath}", RetIconPath(Item, 0)); + return Str; +}; + +function RetDappCard(Item) +{ + var Str = FillDappCard(StrDappRowCardTemplate, Item); + Str = Str.replace("DappRowCardTemplate", "idCard" + Item.Num); + return Str; +}; + +function OpenDappCard(Num) +{ + var Item = CardMapList[Num]; + if(!Item) + return ; + var Str = FillDappCard(StrDappCardTemplate, Item); + Str = Str.replace("{Item.Account}", RetBaseAccount(Item)); + Str = Str.replace("{Item.BlockNum}", RetOpenBlock(Item.BlockNum, 2)); + Str = FillDappCategory(Str, Item, 1); + Str = FillDappCategory(Str, Item, 2); + Str = FillDappCategory(Str, Item, 3); + $("DappCardTemplate").outerHTML = Str; + openModal('DappCardTemplate'); +}; + +function OpenDapp(Num) +{ + OpenDapps(Num); + closeModal(); +}; + +function FillDappCategory(Str,Item,Num) +{ + var Value = Item["Category" + Num]; + if(Value && MapCategory[Value]) + { + Str = Str.replace("{Item.Category" + Num + "}", MapCategory[Value]); + } + else + { + Str = Str.replace("dappcategory" + Num, "myhidden"); + } + return Str; +}; + +function MyToggleList(e) +{ + var item = e.target; + while(true) + { + if(!item) + break; + if(!item.classList) + break; + if(item.onclick && item.onclick !== MyToggleList) + break; + if(item.classList.contains("find--switch")) + { + if(item.classList.contains("prod-card--switch")) + { + item.classList.add("prod-card--active"); + item.classList.add("prod-card--toggle"); + item.classList.remove("prod-card--switch"); + } + else + { + item.classList.remove("prod-card--active"); + item.classList.remove("prod-card--toggle"); + item.classList.add("prod-card--switch"); + } + break; + } + item = item.parentNode; + } +}; +var LangItems = []; + +function InitLangItems() +{ + var tags = ["TITLE", "BUTTON", "DIV", "INPUT", "TH", "TD", "SPAN", "A", "H1", "H2", "H3", "H4", "H5", "P", "DT"]; + var Map2 = {}; + for(var n = 0; n < tags.length; n++) + { + var tagname = tags[n]; + var elems = document.getElementsByTagName(tagname); + for(var elem, i = 0; elem = elems[i++]; ) + { + var Text = elem.innerText; + if(elem.innerHTML !== Text) + continue; + if(!Text) + continue; + if(Text.substr(0, 1) === "{") + continue; + if(Text.toUpperCase() == Text.toLowerCase()) + continue; + LangItems.push({key:Text, elem:elem}); + } + } +}; + +function DoLangItems(Map) +{ + var Map2 = {}; + for(var n = 0; n < LangItems.length; n++) + { + var key = LangItems[n].key; + var elem = LangItems[n].elem; + if(Map) + { + var TextNew = Map[key]; + if(TextNew === undefined) + { + ToLog("Not found translate for key: " + key); + Map[key] = key; + TextNew = key; + } + if(elem.innerText !== TextNew) + { + elem.innerText = TextNew; + } + } + else + { + Map2[key] = key; + } + } + return Map2; +}; + +function DoLangScript() +{ + InitLangItems(); + LangMap["ENG"] = DoLangItems(); + FillSelect("idLang", LangMap, "KEY"); +}; + +function ChangeLang() +{ + var key = $("idLang").value; + if(!key) + { + key = "ENG"; + $("idLang").value = key; + } + DoLangItems(LangMap[key]); + SaveValues(); +}; + +function GetNewLangItem() +{ + ToLog(JSON.stringify(LangMap["ENG"])); +}; +var LangMap = {}; +LangMap["ENG"] = {}; +LangMap["RUS"] = {"TERA WALLET":"TERA КОШЕЛЕК", "Generate key":"Сгенерировать ключ", "OK":"OK", "Cancel":"Отмена", "Edit":"Редактирование", + "Save key":"Сохран.", "+ CREATE A NEW ACCOUNT":"+ СОЗДÐТЬ ÐОВЫЙ СЧЕТ", "Create account":"Создать Ñчет", "Send":"Отправить", + "CONFIRM":"Подтверждение", "Accounts":"Счета", "Account(s)":"Счет(а,ов)", "Blocks and Tx":"Блоки и Транзакции", "Counters":"Показатели", + "Open DApp":"Открыть Дапп", "Back":"Ðазад", "Delete":"Удалить", "Save to book":"Сохранить в книгу", "Choose":"Выбрать", "RECONNECT":"КОÐÐЕКТ", + "DApps":"ДÐппÑ", "ID":"ИД", "Amount":"Величина", "Cur":"Вал", "Name":"ИмÑ", "PubKey":"Пуб.ключ", "Operation":"ОперациÑ", "Smart":"Смарт", + "Block Num":"Ðом блока", "Num":"Ðом", "Date":"Дата", "Data Hash":"Хеш данных", "PowHash":"Хеш ÑложноÑти", "Block Hash":"Хеш блока", + "Bytes":"Байт", "Pow":"Сложн", "Miner":"Майнер", "(secret)":"(Ñекрет)", "Show":"Показать", "TERA":"TERA", "Blockchain height:":"Ð’Ñ‹Ñота блокчейна:", + "Current create:":"Текущий блок:", "Protocol ver:":"ВерÑÐ¸Ñ Ð¿Ñ€Ð¾Ñ‚Ð¾ÐºÐ¾Ð»Ð°:", "ID: {Item.Num}":"ИД: {Item.Num}", "Token generate":"Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñ‚Ð¾ÐºÐµÐ½Ð¾Ð²", + "ACCOUNTS":"СЧЕТÐ", "SEND":"ПОСЛÐТЬ", "DAPPS":"ДÐППС", "EXPLORER":"ПРОСМ", "ATTENTION: Before using the wallet, save the private key.":"Ð’ÐИМÐÐИЕ: Перед иÑпользованием кошелька Ñохраните приватный ключ", + "Web-site":"Веб-Ñайт", "Bitcointalk":"Bitcointalk", "Twitter":"Твиттер", "Telegram":"Телеграм", "Discord":"ДиÑкорд", "QQchat":"QQchat", + "Buy/sell/mine TERA":"Купить/Продать", "+ CREATE NEW":"+ СОЗДÐТЬ ÐОВЫЙ", "Confirm Transaction":"Подтверждение транзакции", + "CREATE DAPPS":"СОЗДÐТЬ", "Set pass":"УÑтановить пароль", "Unlock":"Разблокировать", "Entrance to sub-wallet":"Войти в под-кошелек", + "Public name":"Публичное имÑ", "Currency":"Валюта", "Pay to:":"Получатель:", "Amount:":"Сумма:", "Description:":"ОпиÑание:", + "Welcome to TERA Wallet":"Добропожаловать в кошелек TERA", "Edit your wallet":"Редактирование вашего кошелька", "Key settings":"Задание ключей", + "KEY SETTINGS":"ЗÐДÐÐИЕ КЛЮЧЕЙ", "Create an account":"Создание Ñчета", "Sending coins":"Отправка монет", "Decentralized applications (dApps)":"Децентрализованные Ð¿Ñ€Ð¸Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ (ДаппÑ)", + "Secure your wallet":"БезопаÑноÑÑ‚ÑŒ вашего кошелька", "Wallet is secured":"УÑтановлен пароль", "Total":"Ð’Ñего", "Item.Name":"Item.Name", + "You have no accounts yet":"У Ð²Ð°Ñ Ð½ÐµÑ‚ ни одного Ñчета", "Wait 10-15 sec":"Ждите 10-15 Ñек", "Creating your account":"Идет Ñоздание вашего Ñчета", + "From:":"Отправитель:", "Set a password for protect entry":"УÑтановите пароль Ð´Ð»Ñ Ð±ÐµÐ·Ð¾Ð¿Ð°ÑноÑти", "Enter password to unlock wallet":"Введите пароль Ð´Ð»Ñ Ñ€Ð°Ð·Ð±Ð»Ð¾ÐºÐ¸Ñ€Ð¾Ð²ÐºÐ¸ кошелька", + "From ID:":"Отправитель:", "Pay to ID:":"Получатель:", "Account":"Счет", "Owner":"Владелец", "Block num":"Ðом блока", "Private key (secret)":"Приватный ключ (Ñекретно)", + "Load key":"Загруз.", "Create your first account and start using TERA":"Создайте Ñвой первый Ñчет и начните иÑпользовать TERA", + "0 Accounts":"0 Счетов", "OWNER: {Item.Owner}":"Владелец: {Item.Owner}", "More info":"ИнформациÑ", "Public key":"Публичный ключ"}; +LangMap["简体中文"] = {"TERA WALLET":"TERA 钱包", "Generate key":"生æˆç§é’¥", "OK":"OK", "Cancel":"å–消", "Edit":"编辑", "Save key":"ä¿å­˜ç§é’¥", + "+ CREATE A NEW ACCOUNT":"+ 新建账å·", "Create account":"创建账å·", "Send":"å‘é€", "SEND":"转账", "CONFIRM":"确认", "Accounts":"è´¦å·", "Account(s)":"è´¦å·", + "Blocks and Tx":"区å—和交易", "Counters":"状æ€ç»Ÿè®¡", "Open DApp":"打开DApp", "Back":"返回", "Delete":"删除", "Save to book":"ä¿å­˜åˆ°åœ°å€æœ¬", "Choose":"选择", + "RECONNECT":"é‡è¿ž", "DApps":"DApps", "ID":"ID", "Amount":"ä½™é¢", "Cur":"å¸ç§", "Name":"å称", "PubKey":"公钥", "Operation":"æ“作次数", "Smart":"DApp", + "Block Num":"区å—ç¼–å·", "Num":"ç¼–å·", "Date":"日期", "Data Hash":"æ•°æ®å“ˆå¸Œ", "PowHash":"Pow哈希", "Block Hash":"区å—哈希", "Bytes":"字节", "Pow":"Pow", + "Miner":"矿工", "(secret)":"(机密)", "Show":"显示", "TERA":"TERA", "Blockchain height:":"区å—高度:", "Current create:":"最近区å—:", "Protocol ver:":"å议版本:", + "ID: {Item.Num}":"ID: {Item.Num}", "Token generate":"生æˆä»£å¸", "ACCOUNTS":"è´¦å·", "DAPPS":"DAPPS", "EXPLORER":"æµè§ˆå™¨", "ATTENTION: Before using the wallet, save the private key.":"注æ„: 使用钱包å‰ï¼ŒåŠ¡å¿…ä¿å­˜å¥½ç§é’¥ã€‚", + "Web-site":"官网", "Bitcointalk":"创世贴", "Twitter":"推特", "Telegram":"电报", "Discord":"Discord", "QQchat":"QQ群", "Buy/sell/mine TERA":"TERA 交易/挖矿", + "+ CREATE NEW":"+ 新建", "Confirm Transaction":"确认交易", "CREATE DAPPS":"创建DAPPS", "Set pass":"设置密ç ", "Unlock":"解é”", "Entrance to sub-wallet":"进入å­é’±åŒ…", + "Public name":"å称", "Currency":"å¸ç§", "Pay to:":"收款:", "Amount:":"金é¢:", "Description:":"æè¿°:", "Welcome to TERA Wallet":"欢迎使用TERA钱包", + "Edit your wallet":"编辑钱包", "Key settings":"设置ç§é’¥", "KEY SETTINGS":"设置ç§é’¥", "Create an account":"创建账å·", "Sending coins":"转账", + "Decentralized applications (dApps)":"去中心化应用 (DApps)", "Secure your wallet":"设置钱包密ç ", "Wallet is secured":"钱包密ç å·²è®¾ç½®", "Total":"总计", + "Item.Name":"Item.Name", "You have no accounts yet":"你还没有账å·", "Wait 10-15 sec":"等待10-15秒", "Creating your account":"创建你的账å·", + "From:":"付款:", "Set a password for protect entry":"设置密ç ä¿æŠ¤é’±åŒ…", "Enter password to unlock wallet":"输入密ç è§£é”钱包", "From ID:":"付款ID:", + "Pay to ID:":"收款ID:", "Account":"è´¦å·", "Owner":"拥有者", "Block num":"区å—ç¼–å·", "Private key (secret)":"ç§é’¥ (机密)", "Load key":"载入ç§é’¥", + "Create your first account and start using TERA":"创建你的第一个账å·ï¼Œå¼€å¯TERA之旅", "0 Accounts":"0 è´¦å·", "OWNER: {Item.Owner}":"拥有者: {Item.Owner}", + "More info":"详情", "Public key":"公钥"}; diff --git a/src/HTML/JS/sec256k1.js b/src/HTML/JS/sec256k1.js new file mode 100644 index 0000000..4053c2d --- /dev/null +++ b/src/HTML/JS/sec256k1.js @@ -0,0 +1,190 @@ +/* + * @project: TERA + * @version: Development (beta) + * @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com] + * @license: MIT (not for evil) + * Web: http://terafoundation.org + * GitHub: https://github.com/terafoundation/wallet + * Twitter: https://twitter.com/terafoundation + * Telegram: https://web.telegram.org/#/im?p=@terafoundation +*/ + +"use strict"; +var der = require("./der"), toString = Object.prototype.toString, exports = {}, assert = exports; +exports.isArray = function (e,s) +{ + if(!Array.isArray(e)) + throw TypeError(s); +}, exports.isBoolean = function (e,s) +{ + if("[object Boolean]" !== toString.call(e)) + throw TypeError(s); +}, exports.isBuffer = function (e,s) +{ + if(!Buffer.isBuffer(e)) + throw TypeError(s); +}, exports.isFunction = function (e,s) +{ + if("[object Function]" !== toString.call(e)) + throw TypeError(s); +}, exports.isNumber = function (e,s) +{ + if("[object Number]" !== toString.call(e)) + throw TypeError(s); +}, exports.isObject = function (e,s) +{ + if("[object Object]" !== toString.call(e)) + throw TypeError(s); +}, exports.isBufferLength = function (e,s,r) +{ + if(e.length !== s) + throw RangeError(r); +}, exports.isBufferLength2 = function (e,s,r,_) +{ + if(e.length !== s && e.length !== r) + throw RangeError(_); +}, exports.isLengthGTZero = function (e,s) +{ + if(0 === e.length) + throw RangeError(s); +}, exports.isNumberInInterval = function (e,s,r,_) +{ + if(e <= s || r <= e) + throw RangeError(_); +}; +var messages = {COMPRESSED_TYPE_INVALID:"compressed should be a boolean", EC_PRIVATE_KEY_TYPE_INVALID:"private key should be a Buffer", + EC_PRIVATE_KEY_LENGTH_INVALID:"private key length is invalid", EC_PRIVATE_KEY_RANGE_INVALID:"private key range is invalid", + EC_PRIVATE_KEY_TWEAK_ADD_FAIL:"tweak out of range or resulting private key is invalid", EC_PRIVATE_KEY_TWEAK_MUL_FAIL:"tweak out of range", + EC_PRIVATE_KEY_EXPORT_DER_FAIL:"couldn't export to DER format", EC_PRIVATE_KEY_IMPORT_DER_FAIL:"couldn't import from DER format", + EC_PUBLIC_KEYS_TYPE_INVALID:"public keys should be an Array", EC_PUBLIC_KEYS_LENGTH_INVALID:"public keys Array should have at least 1 element", + EC_PUBLIC_KEY_TYPE_INVALID:"public key should be a Buffer", EC_PUBLIC_KEY_LENGTH_INVALID:"public key length is invalid", EC_PUBLIC_KEY_PARSE_FAIL:"the public key could not be parsed or is invalid", + EC_PUBLIC_KEY_CREATE_FAIL:"private was invalid, try again", EC_PUBLIC_KEY_TWEAK_ADD_FAIL:"tweak out of range or resulting public key is invalid", + EC_PUBLIC_KEY_TWEAK_MUL_FAIL:"tweak out of range", EC_PUBLIC_KEY_COMBINE_FAIL:"the sum of the public keys is not valid", ECDH_FAIL:"scalar was invalid (zero or overflow)", + ECDSA_SIGNATURE_TYPE_INVALID:"signature should be a Buffer", ECDSA_SIGNATURE_LENGTH_INVALID:"signature length is invalid", + ECDSA_SIGNATURE_PARSE_FAIL:"couldn't parse signature", ECDSA_SIGNATURE_PARSE_DER_FAIL:"couldn't parse DER signature", ECDSA_SIGNATURE_SERIALIZE_DER_FAIL:"couldn't serialize signature to DER format", + ECDSA_SIGN_FAIL:"nonce generation function failed or private key is invalid", ECDSA_RECOVER_FAIL:"couldn't recover public key from signature", + MSG32_TYPE_INVALID:"message should be a Buffer", MSG32_LENGTH_INVALID:"message length is invalid", OPTIONS_TYPE_INVALID:"options should be an Object", + OPTIONS_DATA_TYPE_INVALID:"options.data should be a Buffer", OPTIONS_DATA_LENGTH_INVALID:"options.data length is invalid", + OPTIONS_NONCEFN_TYPE_INVALID:"options.noncefn should be a Function", RECOVERY_ID_TYPE_INVALID:"recovery should be a Number", + RECOVERY_ID_VALUE_INVALID:"recovery should have value between -1 and 4", TWEAK_TYPE_INVALID:"tweak should be a Buffer", TWEAK_LENGTH_INVALID:"tweak length is invalid"}; + +function initCompressedValue(e,s) +{ + return void 0 === e ? s : (assert.isBoolean(e, messages.COMPRESSED_TYPE_INVALID), e); +}; +module.exports = function (E) +{ + return {privateKeyVerify:function (e) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), 32 === e.length && E.privateKeyVerify(e); + }, privateKeyExport:function (e,s) + { + assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + s = initCompressedValue(s, !0); + var r = E.privateKeyExport(e, s); + return der.privateKeyExport(e, r, s); + }, privateKeyImport:function (e) + { + if(assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), (e = der.privateKeyImport(e)) && 32 === e.length && E.privateKeyVerify(e)) + return e; + throw new Error(messages.EC_PRIVATE_KEY_IMPORT_DER_FAIL); + }, privateKeyNegate:function (e) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + E.privateKeyNegate(e); + }, privateKeyModInverse:function (e) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + E.privateKeyModInverse(e); + }, privateKeyTweakAdd:function (e,s) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.TWEAK_TYPE_INVALID), assert.isBufferLength(s, 32, messages.TWEAK_LENGTH_INVALID), E.privateKeyTweakAdd(e, + s); + }, privateKeyTweakMul:function (e,s) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.TWEAK_TYPE_INVALID), assert.isBufferLength(s, 32, messages.TWEAK_LENGTH_INVALID), E.privateKeyTweakMul(e, + s); + }, publicKeyCreate:function (e,s) + { + return assert.isBuffer(e, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(e, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + s = initCompressedValue(s, !0), E.publicKeyCreate(e, s); + }, publicKeyConvert:function (e,s) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), + s = initCompressedValue(s, !0), E.publicKeyConvert(e, s); + }, publicKeyVerify:function (e) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), E.publicKeyVerify(e); + }, publicKeyTweakAdd:function (e,s,r) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.TWEAK_TYPE_INVALID), assert.isBufferLength(s, 32, messages.TWEAK_LENGTH_INVALID), r = initCompressedValue(r, + !0), E.publicKeyTweakAdd(e, s, r); + }, publicKeyTweakMul:function (e,s,r) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.TWEAK_TYPE_INVALID), assert.isBufferLength(s, 32, messages.TWEAK_LENGTH_INVALID), r = initCompressedValue(r, + !0), E.publicKeyTweakMul(e, s, r); + }, publicKeyCombine:function (e,s) + { + assert.isArray(e, messages.EC_PUBLIC_KEYS_TYPE_INVALID), assert.isLengthGTZero(e, messages.EC_PUBLIC_KEYS_LENGTH_INVALID); + for(var r = 0; r < e.length; ++r) + assert.isBuffer(e[r], messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e[r], 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID); + return s = initCompressedValue(s, !0), E.publicKeyCombine(e, s); + }, signatureNormalize:function (e) + { + return assert.isBuffer(e, messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isBufferLength(e, 64, messages.ECDSA_SIGNATURE_LENGTH_INVALID), + E.signatureNormalize(e); + }, signatureExport:function (e) + { + assert.isBuffer(e, messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isBufferLength(e, 64, messages.ECDSA_SIGNATURE_LENGTH_INVALID); + var s = E.signatureExport(e); + return der.signatureExport(s); + }, signatureImport:function (e) + { + assert.isBuffer(e, messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isLengthGTZero(e, messages.ECDSA_SIGNATURE_LENGTH_INVALID); + var s = der.signatureImport(e); + if(s) + return E.signatureImport(s); + throw new Error(messages.ECDSA_SIGNATURE_PARSE_DER_FAIL); + }, signatureImportLax:function (e) + { + assert.isBuffer(e, messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isLengthGTZero(e, messages.ECDSA_SIGNATURE_LENGTH_INVALID); + var s = der.signatureImportLax(e); + if(s) + return E.signatureImport(s); + throw new Error(messages.ECDSA_SIGNATURE_PARSE_DER_FAIL); + }, sign:function (e,s,r) + { + assert.isBuffer(e, messages.MSG32_TYPE_INVALID), assert.isBufferLength(e, 32, messages.MSG32_LENGTH_INVALID), assert.isBuffer(s, + messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(s, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID); + var _ = null, t = null; + return void 0 !== r && (assert.isObject(r, messages.OPTIONS_TYPE_INVALID), void 0 !== r.data && (assert.isBuffer(r.data, messages.OPTIONS_DATA_TYPE_INVALID), + assert.isBufferLength(r.data, 32, messages.OPTIONS_DATA_LENGTH_INVALID), _ = r.data), void 0 !== r.noncefn && (assert.isFunction(r.noncefn, + messages.OPTIONS_NONCEFN_TYPE_INVALID), t = r.noncefn)), E.sign(e, s, t, _); + }, verify:function (e,s,r) + { + return assert.isBuffer(e, messages.MSG32_TYPE_INVALID), assert.isBufferLength(e, 32, messages.MSG32_LENGTH_INVALID), assert.isBuffer(s, + messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isBufferLength(s, 64, messages.ECDSA_SIGNATURE_LENGTH_INVALID), assert.isBuffer(r, + messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(r, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), E.verify(e, + s, r); + }, recover:function (e,s,r,_) + { + return assert.isBuffer(e, messages.MSG32_TYPE_INVALID), assert.isBufferLength(e, 32, messages.MSG32_LENGTH_INVALID), assert.isBuffer(s, + messages.ECDSA_SIGNATURE_TYPE_INVALID), assert.isBufferLength(s, 64, messages.ECDSA_SIGNATURE_LENGTH_INVALID), assert.isNumber(r, + messages.RECOVERY_ID_TYPE_INVALID), assert.isNumberInInterval(r, - 1, 4, messages.RECOVERY_ID_VALUE_INVALID), _ = initCompressedValue(_, + !0), E.recover(e, s, r, _); + }, ecdh:function (e,s) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(s, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + E.ecdh(e, s); + }, ecdhUnsafe:function (e,s,r) + { + return assert.isBuffer(e, messages.EC_PUBLIC_KEY_TYPE_INVALID), assert.isBufferLength2(e, 33, 65, messages.EC_PUBLIC_KEY_LENGTH_INVALID), + assert.isBuffer(s, messages.EC_PRIVATE_KEY_TYPE_INVALID), assert.isBufferLength(s, 32, messages.EC_PRIVATE_KEY_LENGTH_INVALID), + r = initCompressedValue(r, !0), E.ecdhUnsafe(e, s, r); + }}; +}, global.SIGN_LIB = module.exports; diff --git a/src/HTML/JS/sha3.js b/src/HTML/JS/sha3.js new file mode 100644 index 0000000..255d5df --- /dev/null +++ b/src/HTML/JS/sha3.js @@ -0,0 +1,803 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +(function () +{ + 'use strict'; + var root = typeof window === 'object' ? window : {}; + var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; + if(NODE_JS && !root.RUN_NW_CLIENT) + { + root = global; + } + if(root.RUN_CLIENT) + { + root = window; + } + var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && typeof module === 'object' && module.exports; + var ARRAY_BUFFER = !root.JS_SHA3_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; + var HEX_CHARS = '0123456789abcdef'.split(''); + var SHAKE_PADDING = [31, 7936, 2031616, 520093696]; + var CSHAKE_PADDING = [4, 1024, 262144, 67108864]; + var KECCAK_PADDING = [1, 256, 65536, 16777216]; + var PADDING = [6, 1536, 393216, 100663296]; + var SHIFT = [0, 8, 16, 24]; + var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649, 0, 2147516545, 2147483648, 32777, + 2147483648, 138, 0, 136, 0, 2147516425, 0, 2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771, 2147483648, + 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648, 2147516545, 2147483648, 32896, 2147483648, 2147483649, + 0, 2147516424, 2147483648]; + var BITS = [224, 256, 384, 512]; + var SHAKE_BITS = [128, 256]; + var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array']; + var CSHAKE_BYTEPAD = {'128':168, '256':136}; + if(root.JS_SHA3_NO_NODE_JS || !Array.isArray) + { + Array.isArray = function (obj) + { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + } + var createOutputMethod = function (bits,padding,outputType) + { + return function (message) + { + return new Keccak(bits, padding, bits).update(message)[outputType](); + }; + }; + var createShakeOutputMethod = function (bits,padding,outputType) + { + return function (message,outputBits) + { + return new Keccak(bits, padding, outputBits).update(message)[outputType](); + }; + }; + var createCshakeOutputMethod = function (bits,padding,outputType) + { + return function (message,outputBits,n,s) + { + return methods['cshake' + bits].update(message, outputBits, n, s)[outputType](); + }; + }; + var createKmacOutputMethod = function (bits,padding,outputType) + { + return function (key,message,outputBits,s) + { + return methods['kmac' + bits].update(key, message, outputBits, s)[outputType](); + }; + }; + var createOutputMethods = function (method,createMethod,bits,padding) + { + for(var i = 0; i < OUTPUT_TYPES.length; ++i) + { + var type = OUTPUT_TYPES[i]; + method[type] = createMethod(bits, padding, type); + } + return method; + }; + var createMethod = function (bits,padding,outputs) + { + var method = createOutputMethod(bits, padding, outputs); + method.create = function () + { + return new Keccak(bits, padding, bits); + }; + method.update = function (message) + { + return method.create().update(message); + }; + return createOutputMethods(method, createOutputMethod, bits, padding); + }; + var createMethodArray = function (bits,padding) + { + var method = createOutputMethod(bits, padding, 'array'); + method.create = function () + { + return new Keccak(bits, padding, bits); + }; + method.update = function (message) + { + return method.create().update(message); + }; + return createOutputMethods(method, createOutputMethod, bits, padding); + }; + var createShakeMethod = function (bits,padding) + { + var method = createShakeOutputMethod(bits, padding, 'hex'); + method.create = function (outputBits) + { + return new Keccak(bits, padding, outputBits); + }; + method.update = function (message,outputBits) + { + return method.create(outputBits).update(message); + }; + return createOutputMethods(method, createShakeOutputMethod, bits, padding); + }; + var createCshakeMethod = function (bits,padding) + { + var w = CSHAKE_BYTEPAD[bits]; + var method = createCshakeOutputMethod(bits, padding, 'hex'); + method.create = function (outputBits,n,s) + { + if(!n && !s) + { + return methods['shake' + bits].create(outputBits); + } + else + { + return new Keccak(bits, padding, outputBits).bytepad([n, s], w); + } + }; + method.update = function (message,outputBits,n,s) + { + return method.create(outputBits, n, s).update(message); + }; + return createOutputMethods(method, createCshakeOutputMethod, bits, padding); + }; + var createKmacMethod = function (bits,padding) + { + var w = CSHAKE_BYTEPAD[bits]; + var method = createKmacOutputMethod(bits, padding, 'hex'); + method.create = function (key,outputBits,s) + { + return new Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w); + }; + method.update = function (key,message,outputBits,s) + { + return method.create(key, outputBits, s).update(message); + }; + return createOutputMethods(method, createKmacOutputMethod, bits, padding); + }; + var algorithms = [{name:'keccak', padding:KECCAK_PADDING, bits:BITS, createMethod:createMethod}, {name:'sha3', padding:PADDING, + bits:BITS, createMethod:createMethod, outputs:'hex'}, {name:'sha3_array', padding:PADDING, bits:BITS, createMethod:createMethod, + outputs:'array'}, {name:'sha3_buf', padding:PADDING, bits:BITS, createMethod:createMethod, outputs:'buffer'}, {name:'shake', + padding:SHAKE_PADDING, bits:SHAKE_BITS, createMethod:createShakeMethod}, {name:'cshake', padding:CSHAKE_PADDING, bits:SHAKE_BITS, + createMethod:createCshakeMethod}, {name:'kmac', padding:CSHAKE_PADDING, bits:SHAKE_BITS, createMethod:createKmacMethod}]; + var methods = {}, methodNames = []; + for(var i = 0; i < algorithms.length; ++i) + { + var algorithm = algorithms[i]; + var bits = algorithm.bits; + for(var j = 0; j < bits.length; ++j) + { + var methodName = algorithm.name + '_' + bits[j]; + methodNames.push(methodName); + methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding, algorithm.outputs); + if(algorithm.name !== 'sha3') + { + var newMethodName = algorithm.name + bits[j]; + methodNames.push(newMethodName); + methods[newMethodName] = methods[methodName]; + } + } + } + +function Keccak(bits,padding,outputBits) + { + this.blocks = []; + this.s = []; + this.padding = padding; + this.outputBits = outputBits; + this.reset = true; + this.block = 0; + this.start = 0; + this.blockCount = (1600 - (bits << 1)) >> 5; + this.byteCount = this.blockCount << 2; + this.outputBlocks = outputBits >> 5; + this.extraBytes = (outputBits & 31) >> 3; + for(var i = 0; i < 50; ++i) + { + this.s[i] = 0; + } + }; + Keccak.prototype.update = function (message) + { + var notString = typeof message !== 'string'; + if(notString && message.constructor === root.ArrayBuffer) + { + TO_ERROR_LOG("SHA3", 10, 'ERROR: Error type ArrayBuffer, use Uint8Array instead!'); + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + var length = message.length; + if(notString) + { + if(typeof length !== 'number' || !Array.isArray(message) && !(ARRAY_BUFFER && ArrayBuffer.isView(message))) + { + TO_ERROR_LOG("SHA3", 20, 'ERROR: Input is invalid type, message=' + JSON.stringify(message)); + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + } + var blocks = this.blocks, byteCount = this.byteCount, blockCount = this.blockCount, index = 0, s = this.s, i, code; + while(index < length) + { + if(this.reset) + { + this.reset = false; + blocks[0] = this.block; + for(i = 1; i < blockCount + 1; ++i) + { + blocks[i] = 0; + } + } + if(notString) + { + for(i = this.start; index < length && i < byteCount; ++index) + { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } + else + { + for(i = this.start; index < length && i < byteCount; ++index) + { + code = message.charCodeAt(index); + if(code < 0x80) + { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } + else + if(code < 0x800) + { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + else + if(code < 0xd800 || code >= 0xe000) + { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + else + { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + this.lastByteIndex = i; + if(i >= byteCount) + { + this.start = i - byteCount; + this.block = blocks[blockCount]; + for(i = 0; i < blockCount; ++i) + { + s[i] ^= blocks[i]; + } + f(s); + this.reset = true; + } + else + { + this.start = i; + } + } + return this; + }; + Keccak.prototype.encode = function (x,right) + { + var o = x & 255, n = 1; + var bytes = [o]; + x = x >> 8; + o = x & 255; + while(o > 0) + { + bytes.unshift(o); + x = x >> 8; + o = x & 255; + ++n; + } + if(right) + { + bytes.push(n); + } + else + { + bytes.unshift(n); + } + this.update(bytes); + return bytes.length; + }; + Keccak.prototype.encodeString = function (str) + { + str = str || ''; + var notString = typeof str !== 'string'; + if(notString && str.constructor === root.ArrayBuffer) + { + str = new Uint8Array(str); + } + var length = str.length; + if(notString) + { + if(typeof length !== 'number' || !Array.isArray(str) && !(ARRAY_BUFFER && ArrayBuffer.isView(str))) + { + TO_ERROR_LOG("SHA3", 30, 'ERROR: Input is invalid type, str=' + JSON.stringify(str)); + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + } + var bytes = 0; + if(notString) + { + bytes = length; + } + else + { + for(var i = 0; i < str.length; ++i) + { + var code = str.charCodeAt(i); + if(code < 0x80) + { + bytes += 1; + } + else + if(code < 0x800) + { + bytes += 2; + } + else + if(code < 0xd800 || code >= 0xe000) + { + bytes += 3; + } + else + { + code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff)); + bytes += 4; + } + } + } + bytes += this.encode(bytes * 8); + this.update(str); + return bytes; + }; + Keccak.prototype.bytepad = function (strs,w) + { + var bytes = this.encode(w); + for(var i = 0; i < strs.length; ++i) + { + bytes += this.encodeString(strs[i]); + } + var paddingBytes = w - bytes % w; + var zeros = []; + zeros.length = paddingBytes; + this.update(zeros); + return this; + }; + Keccak.prototype.finalize = function () + { + var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s; + blocks[i >> 2] |= this.padding[i & 3]; + if(this.lastByteIndex === this.byteCount) + { + blocks[0] = blocks[blockCount]; + for(i = 1; i < blockCount + 1; ++i) + { + blocks[i] = 0; + } + } + blocks[blockCount - 1] |= 0x80000000; + for(i = 0; i < blockCount; ++i) + { + s[i] ^= blocks[i]; + } + f(s); + }; + Keccak.prototype.toString = Keccak.prototype.hex = function () + { + this.finalize(); + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; + var hex = '', block; + while(j < outputBlocks) + { + for(i = 0; i < blockCount && j < outputBlocks; ++i, ++j) + { + block = s[i]; + hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] + HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] + HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] + HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F]; + } + if(j % blockCount === 0) + { + f(s); + i = 0; + } + } + if(extraBytes) + { + block = s[i]; + if(extraBytes > 0) + { + hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F]; + } + if(extraBytes > 1) + { + hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F]; + } + if(extraBytes > 2) + { + hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F]; + } + } + return hex; + }; + Keccak.prototype.arrayBuffer = function () + { + this.finalize(); + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; + var bytes = this.outputBits >> 3; + var buffer; + if(extraBytes) + { + buffer = new ArrayBuffer((outputBlocks + 1) << 2); + } + else + { + buffer = new ArrayBuffer(bytes); + } + var array = new Uint32Array(buffer); + while(j < outputBlocks) + { + for(i = 0; i < blockCount && j < outputBlocks; ++i, ++j) + { + array[j] = s[i]; + } + if(j % blockCount === 0) + { + f(s); + } + } + if(extraBytes) + { + array[i] = s[i]; + buffer = buffer.slice(0, bytes); + } + return buffer; + }; + Keccak.prototype.buffer = Keccak.prototype.arrayBuffer; + Keccak.prototype.digest = Keccak.prototype.array = function () + { + this.finalize(); + var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks, extraBytes = this.extraBytes, i = 0, j = 0; + var array = [], offset, block; + while(j < outputBlocks) + { + for(i = 0; i < blockCount && j < outputBlocks; ++i, ++j) + { + offset = j << 2; + block = s[i]; + array[offset] = block & 0xFF; + array[offset + 1] = (block >> 8) & 0xFF; + array[offset + 2] = (block >> 16) & 0xFF; + array[offset + 3] = (block >> 24) & 0xFF; + } + if(j % blockCount === 0) + { + f(s); + } + } + if(extraBytes) + { + offset = j << 2; + block = s[i]; + if(extraBytes > 0) + { + array[offset] = block & 0xFF; + } + if(extraBytes > 1) + { + array[offset + 1] = (block >> 8) & 0xFF; + } + if(extraBytes > 2) + { + array[offset + 2] = (block >> 16) & 0xFF; + } + } + return array; + }; + +function Kmac(bits,padding,outputBits) + { + Keccak.call(this, bits, padding, outputBits); + }; + Kmac.prototype = new Keccak(); + Kmac.prototype.finalize = function () + { + this.encode(this.outputBits, true); + return Keccak.prototype.finalize.call(this); + }; + var f = function (s) + { + var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, + b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, b34, b35, b36, b37, b38, b39, b40, + b41, b42, b43, b44, b45, b46, b47, b48, b49; + for(n = 0; n < 48; n += 2) + { + c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40]; + c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41]; + c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42]; + c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43]; + c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44]; + c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45]; + c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46]; + c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47]; + c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48]; + c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49]; + h = c8 ^ ((c2 << 1) | (c3 >>> 31)); + l = c9 ^ ((c3 << 1) | (c2 >>> 31)); + s[0] ^= h; + s[1] ^= l; + s[10] ^= h; + s[11] ^= l; + s[20] ^= h; + s[21] ^= l; + s[30] ^= h; + s[31] ^= l; + s[40] ^= h; + s[41] ^= l; + h = c0 ^ ((c4 << 1) | (c5 >>> 31)); + l = c1 ^ ((c5 << 1) | (c4 >>> 31)); + s[2] ^= h; + s[3] ^= l; + s[12] ^= h; + s[13] ^= l; + s[22] ^= h; + s[23] ^= l; + s[32] ^= h; + s[33] ^= l; + s[42] ^= h; + s[43] ^= l; + h = c2 ^ ((c6 << 1) | (c7 >>> 31)); + l = c3 ^ ((c7 << 1) | (c6 >>> 31)); + s[4] ^= h; + s[5] ^= l; + s[14] ^= h; + s[15] ^= l; + s[24] ^= h; + s[25] ^= l; + s[34] ^= h; + s[35] ^= l; + s[44] ^= h; + s[45] ^= l; + h = c4 ^ ((c8 << 1) | (c9 >>> 31)); + l = c5 ^ ((c9 << 1) | (c8 >>> 31)); + s[6] ^= h; + s[7] ^= l; + s[16] ^= h; + s[17] ^= l; + s[26] ^= h; + s[27] ^= l; + s[36] ^= h; + s[37] ^= l; + s[46] ^= h; + s[47] ^= l; + h = c6 ^ ((c0 << 1) | (c1 >>> 31)); + l = c7 ^ ((c1 << 1) | (c0 >>> 31)); + s[8] ^= h; + s[9] ^= l; + s[18] ^= h; + s[19] ^= l; + s[28] ^= h; + s[29] ^= l; + s[38] ^= h; + s[39] ^= l; + s[48] ^= h; + s[49] ^= l; + b0 = s[0]; + b1 = s[1]; + b32 = (s[11] << 4) | (s[10] >>> 28); + b33 = (s[10] << 4) | (s[11] >>> 28); + b14 = (s[20] << 3) | (s[21] >>> 29); + b15 = (s[21] << 3) | (s[20] >>> 29); + b46 = (s[31] << 9) | (s[30] >>> 23); + b47 = (s[30] << 9) | (s[31] >>> 23); + b28 = (s[40] << 18) | (s[41] >>> 14); + b29 = (s[41] << 18) | (s[40] >>> 14); + b20 = (s[2] << 1) | (s[3] >>> 31); + b21 = (s[3] << 1) | (s[2] >>> 31); + b2 = (s[13] << 12) | (s[12] >>> 20); + b3 = (s[12] << 12) | (s[13] >>> 20); + b34 = (s[22] << 10) | (s[23] >>> 22); + b35 = (s[23] << 10) | (s[22] >>> 22); + b16 = (s[33] << 13) | (s[32] >>> 19); + b17 = (s[32] << 13) | (s[33] >>> 19); + b48 = (s[42] << 2) | (s[43] >>> 30); + b49 = (s[43] << 2) | (s[42] >>> 30); + b40 = (s[5] << 30) | (s[4] >>> 2); + b41 = (s[4] << 30) | (s[5] >>> 2); + b22 = (s[14] << 6) | (s[15] >>> 26); + b23 = (s[15] << 6) | (s[14] >>> 26); + b4 = (s[25] << 11) | (s[24] >>> 21); + b5 = (s[24] << 11) | (s[25] >>> 21); + b36 = (s[34] << 15) | (s[35] >>> 17); + b37 = (s[35] << 15) | (s[34] >>> 17); + b18 = (s[45] << 29) | (s[44] >>> 3); + b19 = (s[44] << 29) | (s[45] >>> 3); + b10 = (s[6] << 28) | (s[7] >>> 4); + b11 = (s[7] << 28) | (s[6] >>> 4); + b42 = (s[17] << 23) | (s[16] >>> 9); + b43 = (s[16] << 23) | (s[17] >>> 9); + b24 = (s[26] << 25) | (s[27] >>> 7); + b25 = (s[27] << 25) | (s[26] >>> 7); + b6 = (s[36] << 21) | (s[37] >>> 11); + b7 = (s[37] << 21) | (s[36] >>> 11); + b38 = (s[47] << 24) | (s[46] >>> 8); + b39 = (s[46] << 24) | (s[47] >>> 8); + b30 = (s[8] << 27) | (s[9] >>> 5); + b31 = (s[9] << 27) | (s[8] >>> 5); + b12 = (s[18] << 20) | (s[19] >>> 12); + b13 = (s[19] << 20) | (s[18] >>> 12); + b44 = (s[29] << 7) | (s[28] >>> 25); + b45 = (s[28] << 7) | (s[29] >>> 25); + b26 = (s[38] << 8) | (s[39] >>> 24); + b27 = (s[39] << 8) | (s[38] >>> 24); + b8 = (s[48] << 14) | (s[49] >>> 18); + b9 = (s[49] << 14) | (s[48] >>> 18); + s[0] = b0 ^ (~b2 & b4); + s[1] = b1 ^ (~b3 & b5); + s[10] = b10 ^ (~b12 & b14); + s[11] = b11 ^ (~b13 & b15); + s[20] = b20 ^ (~b22 & b24); + s[21] = b21 ^ (~b23 & b25); + s[30] = b30 ^ (~b32 & b34); + s[31] = b31 ^ (~b33 & b35); + s[40] = b40 ^ (~b42 & b44); + s[41] = b41 ^ (~b43 & b45); + s[2] = b2 ^ (~b4 & b6); + s[3] = b3 ^ (~b5 & b7); + s[12] = b12 ^ (~b14 & b16); + s[13] = b13 ^ (~b15 & b17); + s[22] = b22 ^ (~b24 & b26); + s[23] = b23 ^ (~b25 & b27); + s[32] = b32 ^ (~b34 & b36); + s[33] = b33 ^ (~b35 & b37); + s[42] = b42 ^ (~b44 & b46); + s[43] = b43 ^ (~b45 & b47); + s[4] = b4 ^ (~b6 & b8); + s[5] = b5 ^ (~b7 & b9); + s[14] = b14 ^ (~b16 & b18); + s[15] = b15 ^ (~b17 & b19); + s[24] = b24 ^ (~b26 & b28); + s[25] = b25 ^ (~b27 & b29); + s[34] = b34 ^ (~b36 & b38); + s[35] = b35 ^ (~b37 & b39); + s[44] = b44 ^ (~b46 & b48); + s[45] = b45 ^ (~b47 & b49); + s[6] = b6 ^ (~b8 & b0); + s[7] = b7 ^ (~b9 & b1); + s[16] = b16 ^ (~b18 & b10); + s[17] = b17 ^ (~b19 & b11); + s[26] = b26 ^ (~b28 & b20); + s[27] = b27 ^ (~b29 & b21); + s[36] = b36 ^ (~b38 & b30); + s[37] = b37 ^ (~b39 & b31); + s[46] = b46 ^ (~b48 & b40); + s[47] = b47 ^ (~b49 & b41); + s[8] = b8 ^ (~b0 & b2); + s[9] = b9 ^ (~b1 & b3); + s[18] = b18 ^ (~b10 & b12); + s[19] = b19 ^ (~b11 & b13); + s[28] = b28 ^ (~b20 & b22); + s[29] = b29 ^ (~b21 & b23); + s[38] = b38 ^ (~b30 & b32); + s[39] = b39 ^ (~b31 & b33); + s[48] = b48 ^ (~b40 & b42); + s[49] = b49 ^ (~b41 & b43); + s[0] ^= RC[n]; + s[1] ^= RC[n + 1]; + } + }; + root.sha3_str = methods.sha3_256; + root.sha3_array_256 = methods.sha3_array_256; + root.sha3 = methods.sha3_array_256; + root.sha = function (data) + { + return meshhash(methods.sha3_256(data)); + }; + root.shaarr = function (data) + { + return meshhash(methods.sha3_array_256(data)); + }; + root.shabuf = function (data) + { + return Buffer.from(shaarr(data)); + }; + root.shabuf = function (data) + { + return Buffer.from(shaarr(data)); + }; + root.SHA3BUF = function (data,num) + { + return Buffer.from(SHA3ARR(data, num)); + }; + root.SHA3ARR = function (data,num) + { + if(!NEW_SIGN_TIME || !num || num >= NEW_SIGN_TIME) + return sha3(data); + else + return meshhash(methods.sha3_array_256(data)); + }; + root.shaarrblock = function (data,num) + { + return meshhash(methods.sha3_array_256(data), num); + }; +})(); + +function meshhash(hash,num) +{ + var regs = [hash[3], hash[2], hash[1], hash[0]]; + var mem = []; + for(var i = 0; i < 16; i++) + { + mem[i] = hash[i * 2] + (hash[i * 2 + 1] << 8); + } + var WasGoto = 0; + var L = 0; + for(var i = 0; i < 64; i++) + { + var c = hash[L & 31]; + L++; + var a = (c >> 4) & 0xF; + var b = c & 0xF; + var r = c & 0x3; + switch(a) + { + case 0: + regs[0] = regs[0] + regs[r]; + break; + case 1: + regs[0] = regs[0] * regs[r]; + break; + case 2: + regs[0] = regs[0] | regs[r]; + break; + case 3: + regs[0] = regs[0] & regs[r]; + break; + case 4: + case 5: + case 6: + case 7: + regs[0] = regs[0] + regs[1] + regs[2] + regs[3]; + break; + case 8: + if((regs[0] & 0xFFFF) < 32768 && !WasGoto) + { + L = 32 + L - b; + WasGoto = 1; + } + break; + case 9: + if((regs[0] & 0xFFFF) > 32768 && !WasGoto) + { + L += b; + WasGoto = 1; + } + break; + default: + regs[a % 4] = mem[b]; + } + var index1 = regs[0] & 0xF; + var index2 = (regs[0] >> 8) & 0xF; + if(index1 !== index2) + { + var temp = mem[index1]; + mem[index1] = mem[index2]; + mem[index2] = temp; + } + } + var ret = []; + for(var i = 0; i < 16; i++) + { + ret[i * 2] = mem[i] & 0xFF; + ret[i * 2 + 1] = mem[i] >> 8; + } + return sha3_array_256(ret); +}; diff --git a/src/HTML/JS/sign-lib-min.js b/src/HTML/JS/sign-lib-min.js new file mode 100644 index 0000000..b2dd307 --- /dev/null +++ b/src/HTML/JS/sign-lib-min.js @@ -0,0 +1,4140 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var $jscomp = $jscomp || {}; +$jscomp.scope = {}, $jscomp.arrayIteratorImpl = function (t) +{ + var e = 0; + return function () + { + return e < t.length ? {done:!1, value:t[e++]} : {done:!0}; + }; +}, $jscomp.arrayIterator = function (t) +{ + return {next:$jscomp.arrayIteratorImpl(t)}; +}, $jscomp.ASSUME_ES5 = !1, $jscomp.ASSUME_NO_NATIVE_MAP = !1, $jscomp.ASSUME_NO_NATIVE_SET = !1, $jscomp.defineProperty = $jscomp.ASSUME_ES5 || "function" == typeof Object.defineProperties ? Object.defineProperty : function (t,e,r) +{ + t != Array.prototype && t != Object.prototype && (t[e] = r.value); +}, $jscomp.getGlobal = function (t) +{ + return "undefined" != typeof window && window === t ? t : "undefined" != typeof global && null != global ? global : t; +}, $jscomp.global = $jscomp.getGlobal(this), $jscomp.SYMBOL_PREFIX = "jscomp_symbol_", $jscomp.initSymbol = function () +{ + $jscomp.initSymbol = function () + { + }, $jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol); +}, $jscomp.Symbol = function () +{ + var e = 0; + return function (t) + { + return $jscomp.SYMBOL_PREFIX + (t || "") + e++; + }; +}(), $jscomp.initSymbolIterator = function () +{ + $jscomp.initSymbol(); + var t = $jscomp.global.Symbol.iterator; + t || (t = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator")), "function" != typeof Array.prototype[t] && $jscomp.defineProperty(Array.prototype, + t, {configurable:!0, writable:!0, value:function () + { + return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this)); + }}), $jscomp.initSymbolIterator = function () + { + }; +}, $jscomp.initSymbolAsyncIterator = function () +{ + $jscomp.initSymbol(); + var t = $jscomp.global.Symbol.asyncIterator; + t || (t = $jscomp.global.Symbol.asyncIterator = $jscomp.global.Symbol("asyncIterator")), $jscomp.initSymbolAsyncIterator = function () + { + }; +}, $jscomp.iteratorPrototype = function (t) +{ + return $jscomp.initSymbolIterator(), (t = {next:t})[$jscomp.global.Symbol.iterator] = function () + { + return this; + }, t; +}, function i(n,s,o) +{ + +function a(e,t) + { + if(!s[e]) + { + if(!n[e]) + { + var r = "function" == typeof require && require; + if(!t && r) + return r(e, !0); + if(h) + return h(e, !0); + throw (r = Error("Cannot find module '" + e + "'")).code = "MODULE_NOT_FOUND", r; + } + r = s[e] = {exports:{}}, n[e][0].call(r.exports, function (t) + { + return a(n[e][1][t] || t); + }, r, r.exports, i, n, s, o); + } + return s[e].exports; + }; + for(var h = "function" == typeof require && require, t = 0; t < o.length; t++) + a(o[t]); + return a; +}({1:[function (t,e,r) + { + +function a(t) + { + var e = t.length; + if(0 < e % 4) + throw Error("Invalid string. Length must be a multiple of 4"); + return - 1 === (t = t.indexOf("=")) && (t = e), [t, t === e ? 0 : 4 - t % 4]; + }; + +function o(t,e,r) + { + for(var i = [], n = e; n < r; n += 3) + e = (t[n] << 16 & 16711680) + (t[n + 1] << 8 & 65280) + (255 & t[n + 2]), i.push(h[e >> 18 & 63] + h[e >> 12 & 63] + h[e >> 6 & 63] + h[63 & e]); + return i.join(""); + }; + r.byteLength = function (t) + { + var e = (t = a(t))[1]; + return 3 * (t[0] + e) / 4 - e; + }, r.toByteArray = function (t) + { + var e = a(t), r = e[0]; + e = e[1]; + for(var i = new l(3 * (r + e) / 4 - e), n = 0, s = 0 < e ? r - 4 : r, o = 0; o < s; o += 4) + r = u[t.charCodeAt(o)] << 18 | u[t.charCodeAt(o + 1)] << 12 | u[t.charCodeAt(o + 2)] << 6 | u[t.charCodeAt(o + 3)], i[n++] = r >> 16 & 255, + i[n++] = r >> 8 & 255, i[n++] = 255 & r; + return 2 === e && (r = u[t.charCodeAt(o)] << 2 | u[t.charCodeAt(o + 1)] >> 4, i[n++] = 255 & r), 1 === e && (r = u[t.charCodeAt(o)] << 10 | u[t.charCodeAt(o + 1)] << 4 | u[t.charCodeAt(o + 2)] >> 2, + i[n++] = r >> 8 & 255, i[n++] = 255 & r), i; + }, r.fromByteArray = function (t) + { + for(var e = t.length, r = e % 3, i = [], n = 0, s = e - r; n < s; n += 16383) + i.push(o(t, n, s < n + 16383 ? s : n + 16383)); + return 1 === r ? (t = t[e - 1], i.push(h[t >> 2] + h[t << 4 & 63] + "==")) : 2 === r && (t = (t[e - 2] << 8) + t[e - 1], i.push(h[t >> 10] + h[t >> 4 & 63] + h[t << 2 & 63] + "=")), + i.join(""); + }; + var h = [], u = [], l = "undefined" != typeof Uint8Array ? Uint8Array : Array; + for(t = 0; t < 64; ++t) + h[t] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[t], u["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(t)] = t; + u[45] = 62, u[95] = 63; + }, {}], 2:[function (t,e,r) + { + }, {}], 3:[function (t,e,r) + { + +function n(t) + { + if(B < t) + throw new RangeError("Invalid typed array length"); + return (t = new Uint8Array(t)).__proto__ = h.prototype, t; + }; + +function h(t,e,r) + { + if("number" != typeof t) + return i(t, e, r); + if("string" == typeof e) + throw Error("If encoding is specified then the first argument must be a string"); + return o(t); + }; + +function i(t,e,r) + { + if("number" == typeof t) + throw new TypeError('"value" argument must not be a number'); + if(S(t) || t && S(t.buffer)) + { + if(e < 0 || t.byteLength < e) + throw new RangeError('"offset" is outside of buffer bounds'); + if(t.byteLength < e + (r || 0)) + throw new RangeError('"length" is outside of buffer bounds'); + return (t = void 0 === e && void 0 === r ? new Uint8Array(t) : void 0 === r ? new Uint8Array(t, e) : new Uint8Array(t, e, r)).__proto__ = h.prototype, + t; + } + if("string" != typeof t) + return function (t) + { + if(h.isBuffer(t)) + { + var e = 0 | u(t.length), r = n(e); + return 0 === r.length || t.copy(r, 0, 0, e), r; + } + if(t) + { + if(ArrayBuffer.isView(t) || "length" in t) + return (e = "number" != typeof t.length) || (e = (e = t.length) != e), e ? n(0) : a(t); + if("Buffer" === t.type && Array.isArray(t.data)) + return a(t.data); + } + throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object."); + }(t); + var i = e; + if("string" == typeof i && "" !== i || (i = "utf8"), !h.isEncoding(i)) + throw new TypeError("Unknown encoding: " + i); + return (t = (r = n(e = 0 | l(t, i))).write(t, i)) !== e && (r = r.slice(0, t)), r; + }; + +function s(t) + { + if("number" != typeof t) + throw new TypeError('"size" argument must be of type number'); + if(t < 0) + throw new RangeError('"size" argument must not be negative'); + }; + +function o(t) + { + return s(t), n(t < 0 ? 0 : 0 | u(t)); + }; + +function a(t) + { + for(var e = t.length < 0 ? 0 : 0 | u(t.length), r = n(e), i = 0; i < e; i += 1) + r[i] = 255 & t[i]; + return r; + }; + +function u(t) + { + if(B <= t) + throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x" + B.toString(16) + " bytes"); + return 0 | t; + }; + +function l(t,e) + { + if(h.isBuffer(t)) + return t.length; + if(ArrayBuffer.isView(t) || S(t)) + return t.byteLength; + "string" != typeof t && (t = "" + t); + var r = t.length; + if(0 === r) + return 0; + for(var i = !1; ; ) + switch(e) + { + case "ascii": + case "latin1": + case "binary": + return r; + case "utf8": + case "utf-8": + case void 0: + return v(t).length; + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return 2 * r; + case "hex": + return r >>> 1; + case "base64": + return I.toByteArray(w(t)).length; + default: + if(i) + return v(t).length; + e = ("" + e).toLowerCase(), i = !0; + } + }; + +function f(t,e,r) + { + var i = t[e]; + t[e] = t[r], t[r] = i; + }; + +function c(t,e,r,i,n) + { + if(0 === t.length) + return - 1; + if("string" == typeof r ? (i = r, r = 0) : 2147483647 < r ? r = 2147483647 : r < - 2147483648 && (r = - 2147483648), (r = + r) != r && (r = n ? 0 : t.length - 1), + r < 0 && (r = t.length + r), r >= t.length) + { + if(n) + return - 1; + r = t.length - 1; + } + else + if(r < 0) + { + if(!n) + return - 1; + r = 0; + } + if("string" == typeof e && (e = h.from(e, i)), h.isBuffer(e)) + return 0 === e.length ? - 1 : d(t, e, r, i, n); + if("number" == typeof e) + return e &= 255, "function" == typeof Uint8Array.prototype.indexOf ? n ? Uint8Array.prototype.indexOf.call(t, e, r) : Uint8Array.prototype.lastIndexOf.call(t, + e, r) : d(t, [e], r, i, n); + throw new TypeError("val must be string, number or Buffer"); + }; + +function d(t,e,r,i,n) + { + +function s(t,e) + { + return 1 === o ? t[e] : t.readUInt16BE(e * o); + }; + var o = 1, a = t.length, h = e.length; + if(void 0 !== i && ("ucs2" === (i = String(i).toLowerCase()) || "ucs-2" === i || "utf16le" === i || "utf-16le" === i)) + { + if(t.length < 2 || e.length < 2) + return - 1; + a /= o = 2, h /= 2, r /= 2; + } + if(n) + for(i = - 1; r < a; r++) + if(s(t, r) === s(e, - 1 === i ? 0 : r - i)) + { + if( - 1 === i && (i = r), r - i + 1 === h) + return i * o; + } + else + - 1 !== i && (r -= r - i), i = - 1; + else + for(a < r + h && (r = a - h); 0 <= r; r--) + { + for(a = !0, i = 0; i < h; i++) + if(s(t, r + i) !== s(e, i)) + { + a = !1; + break; + } + if(a) + return r; + } + return - 1; + }; + +function p(t,e,r) + { + r = Math.min(t.length, r); + for(var i = []; e < r; ) + { + var n = t[e], s = null, o = 239 < n ? 4 : 223 < n ? 3 : 191 < n ? 2 : 1; + if(e + o <= r) + switch(o) + { + case 1: + n < 128 && (s = n); + break; + case 2: + var a = t[e + 1]; + 128 == (192 & a) && (127 < (n = (31 & n) << 6 | 63 & a) && (s = n)); + break; + case 3: + a = t[e + 1]; + var h = t[e + 2]; + 128 == (192 & a) && 128 == (192 & h) && (2047 < (n = (15 & n) << 12 | (63 & a) << 6 | 63 & h) && (n < 55296 || 57343 < n) && (s = n)); + break; + case 4: + a = t[e + 1], h = t[e + 2]; + var u = t[e + 3]; + 128 == (192 & a) && 128 == (192 & h) && 128 == (192 & u) && (65535 < (n = (15 & n) << 18 | (63 & a) << 12 | (63 & h) << 6 | 63 & u) && n < 1114112 && (s = n)); + } + null === s ? (s = 65533, o = 1) : 65535 < s && (s -= 65536, i.push(s >>> 10 & 1023 | 55296), s = 56320 | 1023 & s), i.push(s), + e += o; + } + if((t = i.length) <= x) + i = String.fromCharCode.apply(String, i); + else + { + for(r = "", e = 0; e < t; ) + r += String.fromCharCode.apply(String, i.slice(e, e += x)); + i = r; + } + return i; + }; + +function m(t,e,r) + { + if(0 != t % 1 || t < 0) + throw new RangeError("offset is not uint"); + if(r < t + e) + throw new RangeError("Trying to access beyond buffer length"); + }; + +function _(t,e,r,i,n,s) + { + if(!h.isBuffer(t)) + throw new TypeError('"buffer" argument must be a Buffer instance'); + if(n < e || e < s) + throw new RangeError('"value" argument is out of bounds'); + if(r + i > t.length) + throw new RangeError("Index out of range"); + }; + +function g(t,e,r,i,n,s) + { + if(r + i > t.length) + throw new RangeError("Index out of range"); + if(r < 0) + throw new RangeError("Index out of range"); + }; + +function b(t,e,r,i,n) + { + return e = + e, r >>>= 0, n || g(t, 0, r, 4), A.write(t, e, r, i, 23, 4), r + 4; + }; + +function y(t,e,r,i,n) + { + return e = + e, r >>>= 0, n || g(t, 0, r, 8), A.write(t, e, r, i, 52, 8), r + 8; + }; + +function w(t) + { + if((t = (t = t.split("=")[0]).trim().replace(L, "")).length < 2) + return ""; + for(; 0 != t.length % 4; ) + t += "="; + return t; + }; + +function v(t,e) + { + e = e || 1 / 0; + for(var r, i = t.length, n = null, s = [], o = 0; o < i; ++o) + { + if(55295 < (r = t.charCodeAt(o)) && r < 57344) + { + if(!n) + { + if(56319 < r) + { + - 1 < (e -= 3) && s.push(239, 191, 189); + continue; + } + if(o + 1 === i) + { + - 1 < (e -= 3) && s.push(239, 191, 189); + continue; + } + n = r; + continue; + } + if(r < 56320) + { + - 1 < (e -= 3) && s.push(239, 191, 189), n = r; + continue; + } + r = 65536 + (n - 55296 << 10 | r - 56320); + } + else + n && - 1 < (e -= 3) && s.push(239, 191, 189); + if(n = null, r < 128) + { + if(--e < 0) + break; + s.push(r); + } + else + if(r < 2048) + { + if((e -= 2) < 0) + break; + s.push(r >> 6 | 192, 63 & r | 128); + } + else + if(r < 65536) + { + if((e -= 3) < 0) + break; + s.push(r >> 12 | 224, r >> 6 & 63 | 128, 63 & r | 128); + } + else + { + if(!(r < 1114112)) + throw Error("Invalid code point"); + if((e -= 4) < 0) + break; + s.push(r >> 18 | 240, r >> 12 & 63 | 128, r >> 6 & 63 | 128, 63 & r | 128); + } + } + return s; + }; + +function M(t) + { + for(var e = [], r = 0; r < t.length; ++r) + e.push(255 & t.charCodeAt(r)); + return e; + }; + +function E(t,e,r,i) + { + for(var n = 0; n < i && !(n + r >= e.length || n >= t.length); ++n) + e[n + r] = t[n]; + return n; + }; + +function S(t) + { + return t instanceof ArrayBuffer || null != t && null != t.constructor && "ArrayBuffer" === t.constructor.name && "number" == typeof t.byteLength; + }; + var I = t("base64-js"), A = t("ieee754"); + r.Buffer = h, r.SlowBuffer = function (t) + { + return + t != t && (t = 0), h.alloc( + t); + }, r.INSPECT_MAX_BYTES = 50; + var B = 2147483647; + r.kMaxLength = B, (h.TYPED_ARRAY_SUPPORT = function () + { + try + { + var t = new Uint8Array(1); + return t.__proto__ = {__proto__:Uint8Array.prototype, foo:function () + { + return 42; + }}, 42 === t.foo(); + } + catch(t) + { + return !1; + } + }()) || "undefined" == typeof console || "function" != typeof console.error || console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."), + Object.defineProperty(h.prototype, "parent", {get:function () + { + if(this instanceof h) + return this.buffer; + }}), Object.defineProperty(h.prototype, "offset", {get:function () + { + if(this instanceof h) + return this.byteOffset; + }}), $jscomp.initSymbol(), $jscomp.initSymbol(), $jscomp.initSymbol(), "undefined" != typeof Symbol && Symbol.species && h[Symbol.species] === h && ($jscomp.initSymbol(), + Object.defineProperty(h, Symbol.species, {value:null, configurable:!0, enumerable:!1, writable:!1})), h.poolSize = 8192, h.from = function (t,e,r) + { + return i(t, e, r); + }, h.prototype.__proto__ = Uint8Array.prototype, h.__proto__ = Uint8Array, h.alloc = function (t,e,r) + { + return s(t), t = t <= 0 ? n(t) : void 0 !== e ? "string" == typeof r ? n(t).fill(e, r) : n(t).fill(e) : n(t); + }, h.allocUnsafe = function (t) + { + return o(t); + }, h.allocUnsafeSlow = function (t) + { + return o(t); + }, h.isBuffer = function (t) + { + return null != t && !0 === t._isBuffer; + }, h.compare = function (t,e) + { + if(!h.isBuffer(t) || !h.isBuffer(e)) + throw new TypeError("Arguments must be Buffers"); + if(t === e) + return 0; + for(var r = t.length, i = e.length, n = 0, s = Math.min(r, i); n < s; ++n) + if(t[n] !== e[n]) + { + r = t[n], i = e[n]; + break; + } + return r < i ? - 1 : i < r ? 1 : 0; + }, h.isEncoding = function (t) + { + switch(String(t).toLowerCase()) + { + case "hex": + case "utf8": + case "utf-8": + case "ascii": + case "latin1": + case "binary": + case "base64": + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return !0; + default: + return !1; + } + }, h.concat = function (t,e) + { + if(!Array.isArray(t)) + throw new TypeError('"list" argument must be an Array of Buffers'); + if(0 === t.length) + return h.alloc(0); + var r; + if(void 0 === e) + for(r = e = 0; r < t.length; ++r) + e += t[r].length; + var i = h.allocUnsafe(e), n = 0; + for(r = 0; r < t.length; ++r) + { + var s = t[r]; + if(ArrayBuffer.isView(s) && (s = h.from(s)), !h.isBuffer(s)) + throw new TypeError('"list" argument must be an Array of Buffers'); + s.copy(i, n), n += s.length; + } + return i; + }, h.byteLength = l, h.prototype._isBuffer = !0, h.prototype.swap16 = function () + { + var t = this.length; + if(0 != t % 2) + throw new RangeError("Buffer size must be a multiple of 16-bits"); + for(var e = 0; e < t; e += 2) + f(this, e, e + 1); + return this; + }, h.prototype.swap32 = function () + { + var t = this.length; + if(0 != t % 4) + throw new RangeError("Buffer size must be a multiple of 32-bits"); + for(var e = 0; e < t; e += 4) + f(this, e, e + 3), f(this, e + 1, e + 2); + return this; + }, h.prototype.swap64 = function () + { + var t = this.length; + if(0 != t % 8) + throw new RangeError("Buffer size must be a multiple of 64-bits"); + for(var e = 0; e < t; e += 8) + f(this, e, e + 7), f(this, e + 1, e + 6), f(this, e + 2, e + 5), f(this, e + 3, e + 4); + return this; + }, h.prototype.toLocaleString = h.prototype.toString = function () + { + var t = this.length; + return 0 === t ? "" : 0 === arguments.length ? p(this, 0, t) : function (t,e,r) + { + var i = !1; + if((void 0 === e || e < 0) && (e = 0), e > this.length) + return ""; + if((void 0 === r || r > this.length) && (r = this.length), r <= 0) + return ""; + if((r >>>= 0) <= (e >>>= 0)) + return ""; + for(t || (t = "utf8"); ; ) + switch(t) + { + case "hex": + for(t = e, e = r, r = this.length, (!t || t < 0) && (t = 0), (!e || e < 0 || r < e) && (e = r), i = "", r = t; r < e; ++r) + i = (t = i) + (i = (i = this[r]) < 16 ? "0" + i.toString(16) : i.toString(16)); + return i; + case "utf8": + case "utf-8": + return p(this, e, r); + case "ascii": + for(t = "", r = Math.min(this.length, r); e < r; ++e) + t += String.fromCharCode(127 & this[e]); + return t; + case "latin1": + case "binary": + for(t = "", r = Math.min(this.length, r); e < r; ++e) + t += String.fromCharCode(this[e]); + return t; + case "base64": + return e = 0 === e && r === this.length ? I.fromByteArray(this) : I.fromByteArray(this.slice(e, r)); + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + for(e = this.slice(e, r), r = "", t = 0; t < e.length; t += 2) + r += String.fromCharCode(e[t] + 256 * e[t + 1]); + return r; + default: + if(i) + throw new TypeError("Unknown encoding: " + t); + t = (t + "").toLowerCase(), i = !0; + } + }.apply(this, arguments); + }, h.prototype.equals = function (t) + { + if(!h.isBuffer(t)) + throw new TypeError("Argument must be a Buffer"); + return this === t || 0 === h.compare(this, t); + }, h.prototype.inspect = function () + { + var t = "", e = r.INSPECT_MAX_BYTES; + return 0 < this.length && (t = this.toString("hex", 0, e).match(/.{2}/g).join(" "), this.length > e && (t += " ... ")), ""; + }, h.prototype.compare = function (t,e,r,i,n) + { + if(!h.isBuffer(t)) + throw new TypeError("Argument must be a Buffer"); + if(void 0 === e && (e = 0), void 0 === r && (r = t ? t.length : 0), void 0 === i && (i = 0), void 0 === n && (n = this.length), + e < 0 || r > t.length || i < 0 || n > this.length) + throw new RangeError("out of range index"); + if(n <= i && r <= e) + return 0; + if(n <= i) + return - 1; + if(r <= e) + return 1; + if(this === t) + return 0; + var s = (n >>>= 0) - (i >>>= 0), o = (r >>>= 0) - (e >>>= 0), a = Math.min(s, o); + for(i = this.slice(i, n), t = t.slice(e, r), e = 0; e < a; ++e) + if(i[e] !== t[e]) + { + s = i[e], o = t[e]; + break; + } + return s < o ? - 1 : o < s ? 1 : 0; + }, h.prototype.includes = function (t,e,r) + { + return - 1 !== this.indexOf(t, e, r); + }, h.prototype.indexOf = function (t,e,r) + { + return c(this, t, e, r, !0); + }, h.prototype.lastIndexOf = function (t,e,r) + { + return c(this, t, e, r, !1); + }, h.prototype.write = function (t,e,r,i) + { + if(void 0 === e) + i = "utf8", r = this.length, e = 0; + else + if(void 0 === r && "string" == typeof e) + i = e, r = this.length, e = 0; + else + { + if(!isFinite(e)) + throw Error("Buffer.write(string, encoding, offset[, length]) is no longer supported"); + e >>>= 0, isFinite(r) ? (r >>>= 0, void 0 === i && (i = "utf8")) : (i = r, r = void 0); + } + var n = this.length - e; + if((void 0 === r || n < r) && (r = n), 0 < t.length && (r < 0 || e < 0) || e > this.length) + throw new RangeError("Attempt to write outside buffer bounds"); + for(i || (i = "utf8"), n = !1; ; ) + switch(i) + { + case "hex": + t: + { + for(e = Number(e) || 0, i = this.length - e, r ? i < (r = Number(r)) && (r = i) : r = i, (i = t.length) / 2 < r && (r = i / 2), + i = 0; i < r; ++i) + { + if((n = parseInt(t.substr(2 * i, 2), 16)) != n) + { + t = i; + break t; + } + this[e + i] = n; + } + t = i; + } + return t; + case "utf8": + case "utf-8": + return E(v(t, this.length - e), this, e, r); + case "ascii": + return E(M(t), this, e, r); + case "latin1": + case "binary": + return E(M(t), this, e, r); + case "base64": + return E(I.toByteArray(w(t)), this, e, r); + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + i = t, n = this.length - e; + for(var s = [], o = 0; o < i.length && !((n -= 2) < 0); ++o) + { + var a = i.charCodeAt(o); + t = a >> 8, a %= 256, s.push(a), s.push(t); + } + return E(s, this, e, r); + default: + if(n) + throw new TypeError("Unknown encoding: " + i); + i = ("" + i).toLowerCase(), n = !0; + } + }, h.prototype.toJSON = function () + { + return {type:"Buffer", data:Array.prototype.slice.call(this._arr || this, 0)}; + }; + var x = 4096; + h.prototype.slice = function (t,e) + { + var r = this.length; + return (t = ~~t) < 0 ? (t += r) < 0 && (t = 0) : r < t && (t = r), (e = void 0 === e ? r : ~~e) < 0 ? (e += r) < 0 && (e = 0) : r < e && (e = r), + e < t && (e = t), (r = this.subarray(t, e)).__proto__ = h.prototype, r; + }, h.prototype.readUIntLE = function (t,e,r) + { + t >>>= 0, e >>>= 0, r || m(t, e, this.length), r = this[t]; + for(var i = 1, n = 0; ++n < e && (i *= 256); ) + r += this[t + n] * i; + return r; + }, h.prototype.readUIntBE = function (t,e,r) + { + t >>>= 0, e >>>= 0, r || m(t, e, this.length), r = this[t + --e]; + for(var i = 1; 0 < e && (i *= 256); ) + r += this[t + --e] * i; + return r; + }, h.prototype.readUInt8 = function (t,e) + { + return t >>>= 0, e || m(t, 1, this.length), this[t]; + }, h.prototype.readUInt16LE = function (t,e) + { + return t >>>= 0, e || m(t, 2, this.length), this[t] | this[t + 1] << 8; + }, h.prototype.readUInt16BE = function (t,e) + { + return t >>>= 0, e || m(t, 2, this.length), this[t] << 8 | this[t + 1]; + }, h.prototype.readUInt32LE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), (this[t] | this[t + 1] << 8 | this[t + 2] << 16) + 16777216 * this[t + 3]; + }, h.prototype.readUInt32BE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), 16777216 * this[t] + (this[t + 1] << 16 | this[t + 2] << 8 | this[t + 3]); + }, h.prototype.readIntLE = function (t,e,r) + { + t >>>= 0, e >>>= 0, r || m(t, e, this.length), r = this[t]; + for(var i = 1, n = 0; ++n < e && (i *= 256); ) + r += this[t + n] * i; + return 128 * i <= r && (r -= Math.pow(2, 8 * e)), r; + }, h.prototype.readIntBE = function (t,e,r) + { + t >>>= 0, e >>>= 0, r || m(t, e, this.length), r = e; + for(var i = 1, n = this[t + --r]; 0 < r && (i *= 256); ) + n += this[t + --r] * i; + return 128 * i <= n && (n -= Math.pow(2, 8 * e)), n; + }, h.prototype.readInt8 = function (t,e) + { + return t >>>= 0, e || m(t, 1, this.length), 128 & this[t] ? - 1 * (255 - this[t] + 1) : this[t]; + }, h.prototype.readInt16LE = function (t,e) + { + t >>>= 0, e || m(t, 2, this.length); + var r = this[t] | this[t + 1] << 8; + return 32768 & r ? 4294901760 | r : r; + }, h.prototype.readInt16BE = function (t,e) + { + t >>>= 0, e || m(t, 2, this.length); + var r = this[t + 1] | this[t] << 8; + return 32768 & r ? 4294901760 | r : r; + }, h.prototype.readInt32LE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), this[t] | this[t + 1] << 8 | this[t + 2] << 16 | this[t + 3] << 24; + }, h.prototype.readInt32BE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), this[t] << 24 | this[t + 1] << 16 | this[t + 2] << 8 | this[t + 3]; + }, h.prototype.readFloatLE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), A.read(this, t, !0, 23, 4); + }, h.prototype.readFloatBE = function (t,e) + { + return t >>>= 0, e || m(t, 4, this.length), A.read(this, t, !1, 23, 4); + }, h.prototype.readDoubleLE = function (t,e) + { + return t >>>= 0, e || m(t, 8, this.length), A.read(this, t, !0, 52, 8); + }, h.prototype.readDoubleBE = function (t,e) + { + return t >>>= 0, e || m(t, 8, this.length), A.read(this, t, !1, 52, 8); + }, h.prototype.writeUIntLE = function (t,e,r,i) + { + t = + t, e >>>= 0, r >>>= 0, i || _(this, t, e, r, Math.pow(2, 8 * r) - 1, 0), i = 1; + var n = 0; + for(this[e] = 255 & t; ++n < r && (i *= 256); ) + this[e + n] = t / i & 255; + return e + r; + }, h.prototype.writeUIntBE = function (t,e,r,i) + { + t = + t, e >>>= 0, r >>>= 0, i || _(this, t, e, r, Math.pow(2, 8 * r) - 1, 0); + var n = 1; + for(this[e + (i = r - 1)] = 255 & t; 0 <= --i && (n *= 256); ) + this[e + i] = t / n & 255; + return e + r; + }, h.prototype.writeUInt8 = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 1, 255, 0), this[e] = 255 & t, e + 1; + }, h.prototype.writeUInt16LE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 2, 65535, 0), this[e] = 255 & t, this[e + 1] = t >>> 8, e + 2; + }, h.prototype.writeUInt16BE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 2, 65535, 0), this[e] = t >>> 8, this[e + 1] = 255 & t, e + 2; + }, h.prototype.writeUInt32LE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 4, 4294967295, 0), this[e + 3] = t >>> 24, this[e + 2] = t >>> 16, this[e + 1] = t >>> 8, + this[e] = 255 & t, e + 4; + }, h.prototype.writeUInt32BE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 4, 4294967295, 0), this[e] = t >>> 24, this[e + 1] = t >>> 16, this[e + 2] = t >>> 8, + this[e + 3] = 255 & t, e + 4; + }, h.prototype.writeIntLE = function (t,e,r,i) + { + t = + t, e >>>= 0, i || _(this, t, e, r, (i = Math.pow(2, 8 * r - 1)) - 1, - i); + var n = 1, s = i = 0; + for(this[e] = 255 & t; ++i < r && (n *= 256); ) + t < 0 && 0 === s && 0 !== this[e + i - 1] && (s = 1), this[e + i] = (t / n >> 0) - s & 255; + return e + r; + }, h.prototype.writeIntBE = function (t,e,r,i) + { + t = + t, e >>>= 0, i || _(this, t, e, r, (i = Math.pow(2, 8 * r - 1)) - 1, - i); + var n = 1, s = 0; + for(this[e + (i = r - 1)] = 255 & t; 0 <= --i && (n *= 256); ) + t < 0 && 0 === s && 0 !== this[e + i + 1] && (s = 1), this[e + i] = (t / n >> 0) - s & 255; + return e + r; + }, h.prototype.writeInt8 = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 1, 127, - 128), t < 0 && (t = 255 + t + 1), this[e] = 255 & t, e + 1; + }, h.prototype.writeInt16LE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 2, 32767, - 32768), this[e] = 255 & t, this[e + 1] = t >>> 8, e + 2; + }, h.prototype.writeInt16BE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 2, 32767, - 32768), this[e] = t >>> 8, this[e + 1] = 255 & t, e + 2; + }, h.prototype.writeInt32LE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 4, 2147483647, - 2147483648), this[e] = 255 & t, this[e + 1] = t >>> 8, this[e + 2] = t >>> 16, + this[e + 3] = t >>> 24, e + 4; + }, h.prototype.writeInt32BE = function (t,e,r) + { + return t = + t, e >>>= 0, r || _(this, t, e, 4, 2147483647, - 2147483648), t < 0 && (t = 4294967295 + t + 1), this[e] = t >>> 24, + this[e + 1] = t >>> 16, this[e + 2] = t >>> 8, this[e + 3] = 255 & t, e + 4; + }, h.prototype.writeFloatLE = function (t,e,r) + { + return b(this, t, e, !0, r); + }, h.prototype.writeFloatBE = function (t,e,r) + { + return b(this, t, e, !1, r); + }, h.prototype.writeDoubleLE = function (t,e,r) + { + return y(this, t, e, !0, r); + }, h.prototype.writeDoubleBE = function (t,e,r) + { + return y(this, t, e, !1, r); + }, h.prototype.copy = function (t,e,r,i) + { + if(!h.isBuffer(t)) + throw new TypeError("argument should be a Buffer"); + if(r || (r = 0), i || 0 === i || (i = this.length), e >= t.length && (e = t.length), e || (e = 0), 0 < i && i < r && (i = r), + i === r || 0 === t.length || 0 === this.length) + return 0; + if(e < 0) + throw new RangeError("targetStart out of bounds"); + if(r < 0 || r >= this.length) + throw new RangeError("Index out of range"); + if(i < 0) + throw new RangeError("sourceEnd out of bounds"); + i > this.length && (i = this.length), t.length - e < i - r && (i = t.length - e + r); + var n = i - r; + if(this === t && "function" == typeof Uint8Array.prototype.copyWithin) + this.copyWithin(e, r, i); + else + if(this === t && r < e && e < i) + for(i = n - 1; 0 <= i; --i) + t[i + e] = this[i + r]; + else + Uint8Array.prototype.set.call(t, this.subarray(r, i), e); + return n; + }, h.prototype.fill = function (t,e,r,i) + { + if("string" == typeof t) + { + if("string" == typeof e ? (i = e, e = 0, r = this.length) : "string" == typeof r && (i = r, r = this.length), void 0 !== i && "string" != typeof i) + throw new TypeError("encoding must be a string"); + if("string" == typeof i && !h.isEncoding(i)) + throw new TypeError("Unknown encoding: " + i); + if(1 === t.length) + { + var n = t.charCodeAt(0); + ("utf8" === i && n < 128 || "latin1" === i) && (t = n); + } + } + else + "number" == typeof t && (t &= 255); + if(e < 0 || this.length < e || this.length < r) + throw new RangeError("Out of range index"); + if(r <= e) + return this; + if(e >>>= 0, r = void 0 === r ? this.length : r >>> 0, t || (t = 0), "number" == typeof t) + for(i = e; i < r; ++i) + this[i] = t; + else + { + var s = (n = h.isBuffer(t) ? t : new h(t, i)).length; + if(0 === s) + throw new TypeError('The value "' + t + '" is invalid for argument "value"'); + for(i = 0; i < r - e; ++i) + this[i + e] = n[i % s]; + } + return this; + }; + var L = /[^+/0-9A-Za-z-_]/g; + }, {"base64-js":1, ieee754:6}], 4:[function (t,e,r) + { + (function (t) + { + r.isArray = function (t) + { + return Array.isArray ? Array.isArray(t) : "[object Array]" === Object.prototype.toString.call(t); + }, r.isBoolean = function (t) + { + return "boolean" == typeof t; + }, r.isNull = function (t) + { + return null === t; + }, r.isNullOrUndefined = function (t) + { + return null == t; + }, r.isNumber = function (t) + { + return "number" == typeof t; + }, r.isString = function (t) + { + return "string" == typeof t; + }, r.isSymbol = function (t) + { + return "symbol" == typeof t; + }, r.isUndefined = function (t) + { + return void 0 === t; + }, r.isRegExp = function (t) + { + return "[object RegExp]" === Object.prototype.toString.call(t); + }, r.isObject = function (t) + { + return "object" == typeof t && null !== t; + }, r.isDate = function (t) + { + return "[object Date]" === Object.prototype.toString.call(t); + }, r.isError = function (t) + { + return "[object Error]" === Object.prototype.toString.call(t) || t instanceof Error; + }, r.isFunction = function (t) + { + return "function" == typeof t; + }, r.isPrimitive = function (t) + { + return null === t || "boolean" == typeof t || "number" == typeof t || "string" == typeof t || "symbol" == typeof t || void 0 === t; + }, r.isBuffer = t.isBuffer; + }).call(this, {isBuffer:t("../../is-buffer/index.js")}); + }, {"../../is-buffer/index.js":8}], 5:[function (t,e,r) + { + +function o() + { + this._events && Object.prototype.hasOwnProperty.call(this, "_events") || (this._events = l(null), this._eventsCount = 0), this._maxListeners = this._maxListeners || void 0; + }; + +function i(t,e,r,i) + { + var n; + if("function" != typeof r) + throw new TypeError('"listener" argument must be a function'); + if(n = t._events) + { + n.newListener && (t.emit("newListener", e, r.listener ? r.listener : r), n = t._events); + var s = n[e]; + } + else + n = t._events = l(null), t._eventsCount = 0; + return s ? ("function" == typeof s ? s = n[e] = i ? [r, s] : [s, r] : i ? s.unshift(r) : s.push(r), s.warned || (r = void 0 === t._maxListeners ? o.defaultMaxListeners : t._maxListeners) && 0 < r && s.length > r && (s.warned = !0, + (r = Error("Possible EventEmitter memory leak detected. " + s.length + ' "' + String(e) + '" listeners added. Use emitter.setMaxListeners() to increase limit.')).name = "MaxListenersExceededWarning", + r.emitter = t, r.type = e, r.count = s.length, "object" == typeof console && console.warn && console.warn("%s: %s", r.name, + r.message))) : (n[e] = r, ++t._eventsCount), t; + }; + +function n() + { + if(!this.fired) + switch(this.target.removeListener(this.type, this.wrapFn), this.fired = !0, arguments.length) + { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call(this.target, arguments[0], arguments[1]); + case 3: + return this.listener.call(this.target, arguments[0], arguments[1], arguments[2]); + default: + for(var t = Array(arguments.length), e = 0; e < t.length; ++e) + t[e] = arguments[e]; + this.listener.apply(this.target, t); + } + }; + +function s(t,e,r) + { + return t = {fired:!1, wrapFn:void 0, target:t, type:e, listener:r}, (e = c.call(n, t)).listener = r, t.wrapFn = e; + }; + +function a(t,e,r) + { + if(!(t = t._events)) + return []; + if(!(e = t[e])) + return []; + if("function" == typeof e) + return r ? [e.listener || e] : [e]; + if(r) + for(r = Array(e.length), t = 0; t < r.length; ++t) + r[t] = e[t].listener || e[t]; + else + r = u(e, e.length); + return r; + }; + +function h(t) + { + var e = this._events; + if(e) + { + if("function" == typeof (t = e[t])) + return 1; + if(t) + return t.length; + } + return 0; + }; + +function u(t,e) + { + for(var r = Array(e), i = 0; i < e; ++i) + r[i] = t[i]; + return r; + }; + var l = Object.create || function (t) + { + var e = function () + { + }; + return e.prototype = t, new e; + }, f = Object.keys || function (t) + { + var e, r = []; + for(e in t) + Object.prototype.hasOwnProperty.call(t, e) && r.push(e); + return e; + }, c = Function.prototype.bind || function (t) + { + var e = this; + return function () + { + return e.apply(t, arguments); + }; + }; + ((e.exports = o).EventEmitter = o).prototype._events = void 0, o.prototype._maxListeners = void 0; + var d = 10; + try + { + t = {}, Object.defineProperty && Object.defineProperty(t, "x", {value:0}); + var p = 0 === t.x; + } + catch(t) + { + p = !1; + } + p ? Object.defineProperty(o, "defaultMaxListeners", {enumerable:!0, get:function () + { + return d; + }, set:function (t) + { + if("number" != typeof t || t < 0 || t != t) + throw new TypeError('"defaultMaxListeners" must be a positive number'); + d = t; + }}) : o.defaultMaxListeners = d, o.prototype.setMaxListeners = function (t) + { + if("number" != typeof t || t < 0 || isNaN(t)) + throw new TypeError('"n" argument must be a positive number'); + return this._maxListeners = t, this; + }, o.prototype.getMaxListeners = function () + { + return void 0 === this._maxListeners ? o.defaultMaxListeners : this._maxListeners; + }, o.prototype.emit = function (t) + { + var e, r, i, n = "error" === t; + if(i = this._events) + n = n && null == i.error; + else + if(!n) + return !1; + if(n) + { + if(1 < arguments.length && (e = arguments[1]), e instanceof Error) + throw e; + throw (i = Error('Unhandled "error" event. (' + e + ")")).context = e, i; + } + if(!(e = i[t])) + return !1; + i = "function" == typeof e; + var s = arguments.length; + switch(s) + { + case 1: + if(i) + e.call(this); + else + for(e = u(e, i = e.length), n = 0; n < i; ++n) + e[n].call(this); + break; + case 2: + if(n = arguments[1], i) + e.call(this, n); + else + for(e = u(e, i = e.length), s = 0; s < i; ++s) + e[s].call(this, n); + break; + case 3: + if(n = arguments[1], s = arguments[2], i) + e.call(this, n, s); + else + for(e = u(e, i = e.length), r = 0; r < i; ++r) + e[r].call(this, n, s); + break; + case 4: + if(n = arguments[1], s = arguments[2], r = arguments[3], i) + e.call(this, n, s, r); + else + { + e = u(e, i = e.length); + for(var o = 0; o < i; ++o) + e[o].call(this, n, s, r); + } + break; + default: + for(n = Array(s - 1), r = 1; r < s; r++) + n[r - 1] = arguments[r]; + if(i) + e.apply(this, n); + else + for(e = u(e, i = e.length), s = 0; s < i; ++s) + e[s].apply(this, n); + } + return !0; + }, o.prototype.on = o.prototype.addListener = function (t,e) + { + return i(this, t, e, !1); + }, o.prototype.prependListener = function (t,e) + { + return i(this, t, e, !0); + }, o.prototype.once = function (t,e) + { + if("function" != typeof e) + throw new TypeError('"listener" argument must be a function'); + return this.on(t, s(this, t, e)), this; + }, o.prototype.prependOnceListener = function (t,e) + { + if("function" != typeof e) + throw new TypeError('"listener" argument must be a function'); + return this.prependListener(t, s(this, t, e)), this; + }, o.prototype.removeListener = function (t,e) + { + var r; + if("function" != typeof e) + throw new TypeError('"listener" argument must be a function'); + var i = this._events; + if(!i) + return this; + var n = i[t]; + if(!n) + return this; + if(n === e || n.listener === e) + 0 == --this._eventsCount ? this._events = l(null) : (delete i[t], i.removeListener && this.emit("removeListener", t, n.listener || e)); + else + if("function" != typeof n) + { + var s = - 1; + for(r = n.length - 1; 0 <= r; r--) + if(n[r] === e || n[r].listener === e) + { + var o = n[r].listener; + s = r; + break; + } + if(s < 0) + return this; + if(0 === s) + n.shift(); + else + { + r = s + 1; + for(var a = n.length; r < a; s += 1, r += 1) + n[s] = n[r]; + n.pop(); + } + 1 === n.length && (i[t] = n[0]), i.removeListener && this.emit("removeListener", t, o || e); + } + return this; + }, o.prototype.removeAllListeners = function (t) + { + var e = this._events; + if(!e) + return this; + if(!e.removeListener) + return 0 === arguments.length ? (this._events = l(null), this._eventsCount = 0) : e[t] && (0 == --this._eventsCount ? this._events = l(null) : delete e[t]), + this; + if(0 === arguments.length) + { + var r = f(e); + for(e = 0; e < r.length; ++e) + { + var i = r[e]; + "removeListener" !== i && this.removeAllListeners(i); + } + return this.removeAllListeners("removeListener"), this._events = l(null), this._eventsCount = 0, this; + } + if("function" == typeof (r = e[t])) + this.removeListener(t, r); + else + if(r) + for(e = r.length - 1; 0 <= e; e--) + this.removeListener(t, r[e]); + return this; + }, o.prototype.listeners = function (t) + { + return a(this, t, !0); + }, o.prototype.rawListeners = function (t) + { + return a(this, t, !1); + }, o.listenerCount = function (t,e) + { + return "function" == typeof t.listenerCount ? t.listenerCount(e) : h.call(t, e); + }, o.prototype.listenerCount = h, o.prototype.eventNames = function () + { + return 0 < this._eventsCount ? Reflect.ownKeys(this._events) : []; + }; + }, {}], 6:[function (t,e,r) + { + r.read = function (t,e,r,i,n) + { + var s = 8 * n - i - 1, o = (1 << s) - 1, a = o >> 1, h = - 7, u = r ? - 1 : 1, l = t[e + (n = r ? n - 1 : 0)]; + for(n += u, r = l & (1 << - h) - 1, l >>= - h, h += s; 0 < h; r = 256 * r + t[e + n], n += u, h -= 8); + for(s = r & (1 << - h) - 1, r >>= - h, h += i; 0 < h; s = 256 * s + t[e + n], n += u, h -= 8); + if(0 === r) + r = 1 - a; + else + { + if(r === o) + return s ? NaN : 1 / 0 * (l ? - 1 : 1); + s += Math.pow(2, i), r -= a; + } + return (l ? - 1 : 1) * s * Math.pow(2, r - i); + }, r.write = function (t,e,r,i,n,s) + { + var o, a = 8 * s - n - 1, h = (1 << a) - 1, u = h >> 1, l = 23 === n ? Math.pow(2, - 24) - Math.pow(2, - 77) : 0; + s = i ? 0 : s - 1; + var f = i ? 1 : - 1, c = e < 0 || 0 === e && 1 / e < 0 ? 1 : 0; + for(e = Math.abs(e), isNaN(e) || 1 / 0 === e ? (e = isNaN(e) ? 1 : 0, i = h) : (i = Math.floor(Math.log(e) / Math.LN2), e * (o = Math.pow(2, + - i)) < 1 && (i--, o *= 2), 2 <= (e = 1 <= i + u ? e + l / o : e + l * Math.pow(2, 1 - u)) * o && (i++, o /= 2), h <= i + u ? (e = 0, + i = h) : 1 <= i + u ? (e = (e * o - 1) * Math.pow(2, n), i += u) : (e = e * Math.pow(2, u - 1) * Math.pow(2, n), i = 0)); 8 <= n; t[r + s] = 255 & e, + s += f, e /= 256, n -= 8); + for(i = i << n | e, a += n; 0 < a; t[r + s] = 255 & i, s += f, i /= 256, a -= 8); + t[r + s - f] |= 128 * c; + }; + }, {}], 7:[function (t,e,r) + { + e.exports = "function" == typeof Object.create ? function (t,e) + { + t.super_ = e, t.prototype = Object.create(e.prototype, {constructor:{value:t, enumerable:!1, writable:!0, configurable:!0}}); + } : function (t,e) + { + t.super_ = e; + var r = function () + { + }; + r.prototype = e.prototype, t.prototype = new r, t.prototype.constructor = t; + }; + }, {}], 8:[function (t,e,r) + { + +function i(t) + { + return !!t.constructor && "function" == typeof t.constructor.isBuffer && t.constructor.isBuffer(t); + }; + e.exports = function (t) + { + return null != t && (i(t) || "function" == typeof t.readFloatLE && "function" == typeof t.slice && i(t.slice(0, 0)) || !!t._isBuffer); + }; + }, {}], 9:[function (t,e,r) + { + var i = {}.toString; + e.exports = Array.isArray || function (t) + { + return "[object Array]" == i.call(t); + }; + }, {}], 10:[function (t,e,r) + { + (function (o) + { + !o.version || 0 === o.version.indexOf("v0.") || 0 === o.version.indexOf("v1.") && 0 !== o.version.indexOf("v1.8.") ? e.exports = {nextTick:function (t,e,r,i) + { + if("function" != typeof t) + throw new TypeError('"callback" argument must be a function'); + var n = arguments.length; + switch(n) + { + case 0: + case 1: + return o.nextTick(t); + case 2: + return o.nextTick(function () + { + t.call(null, e); + }); + case 3: + return o.nextTick(function () + { + t.call(null, e, r); + }); + case 4: + return o.nextTick(function () + { + t.call(null, e, r, i); + }); + default: + var s = Array(n - 1); + for(n = 0; n < s.length; ) + s[n++] = arguments[n]; + return o.nextTick(function () + { + t.apply(null, s); + }); + } + }} : e.exports = o; + }).call(this, t("_process")); + }, {_process:11}], 11:[function (t,e,r) + { + +function i() + { + throw Error("setTimeout has not been defined"); + }; + +function n() + { + throw Error("clearTimeout has not been defined"); + }; + +function s(e) + { + if(l === setTimeout) + return setTimeout(e, 0); + if((l === i || !l) && setTimeout) + return l = setTimeout, setTimeout(e, 0); + try + { + return l(e, 0); + } + catch(t) + { + try + { + return l.call(null, e, 0); + } + catch(t) + { + return l.call(this, e, 0); + } + } + }; + +function o() + { + p && c && (p = !1, c.length ? d = c.concat(d) : m = - 1, d.length && a()); + }; + +function a() + { + if(!p) + { + var t = s(o); + p = !0; + for(var e = d.length; e; ) + { + for(c = d, d = []; ++m < e; ) + c && c[m].run(); + m = - 1, e = d.length; + } + c = null, p = !1, function (e) + { + if(f === clearTimeout) + return clearTimeout(e); + if((f === n || !f) && clearTimeout) + return f = clearTimeout, clearTimeout(e); + try + { + f(e); + } + catch(t) + { + try + { + return f.call(null, e); + } + catch(t) + { + return f.call(this, e); + } + } + }(t); + } + }; + +function h(t,e) + { + this.fun = t, this.array = e; + }; + +function u() + { + }; + t = e.exports = {}; + try + { + var l = "function" == typeof setTimeout ? setTimeout : i; + } + catch(t) + { + l = i; + } + try + { + var f = "function" == typeof clearTimeout ? clearTimeout : n; + } + catch(t) + { + f = n; + } + var c, d = [], p = !1, m = - 1; + t.nextTick = function (t) + { + var e = Array(arguments.length - 1); + if(1 < arguments.length) + for(var r = 1; r < arguments.length; r++) + e[r - 1] = arguments[r]; + d.push(new h(t, e)), 1 !== d.length || p || s(a); + }, h.prototype.run = function () + { + this.fun.apply(null, this.array); + }, t.title = "browser", t.browser = !0, t.env = {}, t.argv = [], t.version = "", t.versions = {}, t.on = u, t.addListener = u, + t.once = u, t.off = u, t.removeListener = u, t.removeAllListeners = u, t.emit = u, t.prependListener = u, t.prependOnceListener = u, + t.listeners = function (t) + { + return []; + }, t.binding = function (t) + { + throw Error("process.binding is not supported"); + }, t.cwd = function () + { + return "/"; + }, t.chdir = function (t) + { + throw Error("process.chdir is not supported"); + }, t.umask = function () + { + return 0; + }; + }, {}], 12:[function (t,e,r) + { + e.exports = t("./lib/_stream_duplex.js"); + }, {"./lib/_stream_duplex.js":13}], 13:[function (t,e,r) + { + +function i(t) + { + if(!(this instanceof i)) + return new i(t); + a.call(this, t), h.call(this, t), t && !1 === t.readable && (this.readable = !1), t && !1 === t.writable && (this.writable = !1), + this.allowHalfOpen = !0, t && !1 === t.allowHalfOpen && (this.allowHalfOpen = !1), this.once("end", n); + }; + +function n() + { + this.allowHalfOpen || this._writableState.ended || o.nextTick(s, this); + }; + +function s(t) + { + t.end(); + }; + var o = t("process-nextick-args"); + r = Object.keys || function (t) + { + var e, r = []; + for(e in t) + r.push(e); + return r; + }, e.exports = i, (e = t("core-util-is")).inherits = t("inherits"); + var a = t("./_stream_readable"), h = t("./_stream_writable"); + for(e.inherits(i, a), t = r(h.prototype), e = 0; e < t.length; e++) + r = t[e], i.prototype[r] || (i.prototype[r] = h.prototype[r]); + Object.defineProperty(i.prototype, "writableHighWaterMark", {enumerable:!1, get:function () + { + return this._writableState.highWaterMark; + }}), Object.defineProperty(i.prototype, "destroyed", {get:function () + { + return void 0 !== this._readableState && void 0 !== this._writableState && (this._readableState.destroyed && this._writableState.destroyed); + }, set:function (t) + { + void 0 !== this._readableState && void 0 !== this._writableState && (this._readableState.destroyed = t, this._writableState.destroyed = t); + }}), i.prototype._destroy = function (t,e) + { + this.push(null), this.end(), o.nextTick(e, t); + }; + }, {"./_stream_readable":15, "./_stream_writable":17, "core-util-is":4, inherits:7, "process-nextick-args":10}], 14:[function (t,e,r) + { + +function i(t) + { + if(!(this instanceof i)) + return new i(t); + n.call(this, t); + }; + e.exports = i; + var n = t("./_stream_transform"); + (e = t("core-util-is")).inherits = t("inherits"), e.inherits(i, n), i.prototype._transform = function (t,e,r) + { + r(null, t); + }; + }, {"./_stream_transform":16, "core-util-is":4, inherits:7}], 15:[function (L,k,t) + { + (function (m,t) + { + +function e(t,e) + { + t = t || {}; + var r = e instanceof (p = p || L("./_stream_duplex")); + this.objectMode = !!t.objectMode, r && (this.objectMode = this.objectMode || !!t.readableObjectMode); + var i = t.highWaterMark, n = t.readableHighWaterMark, s = this.objectMode ? 16 : 16384; + this.highWaterMark = i || 0 === i ? i : r && (n || 0 === n) ? n : s, this.highWaterMark = Math.floor(this.highWaterMark), this.buffer = new B, + this.length = 0, this.pipes = null, this.pipesCount = 0, this.flowing = null, this.reading = this.endEmitted = this.ended = !1, + this.sync = !0, this.destroyed = this.resumeScheduled = this.readableListening = this.emittedReadable = this.needReadable = !1, + this.defaultEncoding = t.defaultEncoding || "utf8", this.awaitDrain = 0, this.readingMore = !1, this.encoding = this.decoder = null, + t.encoding && (A || (A = L("string_decoder/").StringDecoder), this.decoder = new A(t.encoding), this.encoding = t.encoding); + }; + +function r(t) + { + if(p = p || L("./_stream_duplex"), !(this instanceof r)) + return new r(t); + this._readableState = new e(t, this), this.readable = !0, t && ("function" == typeof t.read && (this._read = t.read), "function" == typeof t.destroy && (this._destroy = t.destroy)), + w.call(this); + }; + +function n(t,e,r,i,n) + { + var s = t._readableState; + if(null === e) + s.reading = !1, s.ended || (s.decoder && (e = s.decoder.end()) && e.length && (s.buffer.push(e), s.length += s.objectMode ? 1 : e.length), + s.ended = !0, u(t)); + else + { + if(!n) + { + var o; + n = e, v.isBuffer(n) || n instanceof M || "string" == typeof n || void 0 === n || s.objectMode || (o = new TypeError("Invalid non-string/buffer chunk")); + var a = o; + } + a ? t.emit("error", a) : s.objectMode || e && 0 < e.length ? ("string" == typeof e || s.objectMode || Object.getPrototypeOf(e) === v.prototype || (e = v.from(e)), + i ? s.endEmitted ? t.emit("error", Error("stream.unshift() after end event")) : h(t, s, e, !0) : s.ended ? t.emit("error", + Error("stream.push() after EOF")) : (s.reading = !1, s.decoder && !r ? (e = s.decoder.write(e), s.objectMode || 0 !== e.length ? h(t, + s, e, !1) : s.readingMore || (s.readingMore = !0, b.nextTick(l, t, s))) : h(t, s, e, !1))) : i || (s.reading = !1); + } + return !s.ended && (s.needReadable || s.length < s.highWaterMark || 0 === s.length); + }; + +function h(t,e,r,i) + { + e.flowing && 0 === e.length && !e.sync ? (t.emit("data", r), t.read(0)) : (e.length += e.objectMode ? 1 : r.length, i ? e.buffer.unshift(r) : e.buffer.push(r), + e.needReadable && u(t)), e.readingMore || (e.readingMore = !0, b.nextTick(l, t, e)); + }; + +function s(t,e) + { + if(t <= 0 || 0 === e.length && e.ended) + return 0; + if(e.objectMode) + return 1; + if(t != t) + return e.flowing && e.length ? e.buffer.head.data.length : e.length; + if(t > e.highWaterMark) + { + var r = t; + 8388608 <= r ? r = 8388608 : (r--, r |= r >>> 1, r |= r >>> 2, r |= r >>> 4, r |= r >>> 8, r |= r >>> 16, r++), e.highWaterMark = r; + } + return t <= e.length ? t : e.ended ? e.length : (e.needReadable = !0, 0); + }; + +function u(t) + { + var e = t._readableState; + e.needReadable = !1, e.emittedReadable || (I("emitReadable", e.flowing), e.emittedReadable = !0, e.sync ? b.nextTick(i, t) : i(t)); + }; + +function i(t) + { + I("emit readable"), t.emit("readable"), _(t); + }; + +function l(t,e) + { + for(var r = e.length; !e.reading && !e.flowing && !e.ended && e.length < e.highWaterMark && (I("maybeReadMore read 0"), t.read(0), + r !== e.length); ) + r = e.length; + e.readingMore = !1; + }; + +function o(t) + { + I("readable nexttick read 0"), t.read(0); + }; + +function a(t,e) + { + e.reading || (I("resume read 0"), t.read(0)), e.resumeScheduled = !1, e.awaitDrain = 0, t.emit("resume"), _(t), e.flowing && !e.reading && t.read(0); + }; + +function _(t) + { + var e = t._readableState; + for(I("flow", e.flowing); e.flowing && null !== t.read(); ); + }; + +function f(t,e) + { + if(0 === e.length) + return null; + if(e.objectMode) + var r = e.buffer.shift(); + else + if(!t || t >= e.length) + r = e.decoder ? e.buffer.join("") : 1 === e.buffer.length ? e.buffer.head.data : e.buffer.concat(e.length), e.buffer.clear(); + else + { + r = e.buffer; + var i = e.decoder; + if(t < r.head.data.length) + i = r.head.data.slice(0, t), r.head.data = r.head.data.slice(t); + else + { + if(t === r.head.data.length) + r = r.shift(); + else + if(i) + { + var n = r.head, s = 1, o = n.data; + for(i = t - o.length; n = n.next; ) + { + var a = n.data, h = i > a.length ? a.length : i; + if(o = h === a.length ? o + a : o + a.slice(0, i), 0 === (i -= h)) + { + h === a.length ? (++s, r.head = n.next ? n.next : r.tail = null) : (r.head = n).data = a.slice(h); + break; + } + ++s; + } + r.length -= s, r = o; + } + else + { + for(i = t, n = v.allocUnsafe(i), o = 1, (s = r.head).data.copy(n), i -= s.data.length; s = s.next; ) + { + if(h = i > (a = s.data).length ? a.length : i, a.copy(n, n.length - i, 0, h), 0 === (i -= h)) + { + h === a.length ? (++o, r.head = s.next ? s.next : r.tail = null) : (r.head = s).data = a.slice(h); + break; + } + ++o; + } + r.length -= o, r = n; + } + i = r; + } + r = i; + } + return r; + }; + +function c(t) + { + var e = t._readableState; + if(0 < e.length) + throw Error('"endReadable()" called on non-empty stream'); + e.endEmitted || (e.ended = !0, b.nextTick(d, e, t)); + }; + +function d(t,e) + { + t.endEmitted || 0 !== t.length || (t.endEmitted = !0, e.readable = !1, e.emit("end")); + }; + +function g(t,e) + { + for(var r = 0, i = t.length; r < i; r++) + if(t[r] === e) + return r; + return - 1; + }; + var b = L("process-nextick-args"); + k.exports = r; + var p, y = L("isarray"); + r.ReadableState = e, L("events"); + var w = L("./internal/streams/stream"), v = L("safe-buffer").Buffer, M = t.Uint8Array || function () + { + }, E = L("core-util-is"); + E.inherits = L("inherits"); + var S = L("util"), I = void 0; + I = S && S.debuglog ? S.debuglog("stream") : function () + { + }; + var A, B = L("./internal/streams/BufferList"); + S = L("./internal/streams/destroy"), E.inherits(r, w); + var x = ["error", "close", "destroy", "pause", "resume"]; + Object.defineProperty(r.prototype, "destroyed", {get:function () + { + return void 0 !== this._readableState && this._readableState.destroyed; + }, set:function (t) + { + this._readableState && (this._readableState.destroyed = t); + }}), r.prototype.destroy = S.destroy, r.prototype._undestroy = S.undestroy, r.prototype._destroy = function (t,e) + { + this.push(null), e(t); + }, r.prototype.push = function (t,e) + { + var r = this._readableState; + if(r.objectMode) + var i = !0; + else + "string" == typeof t && ((e = e || r.defaultEncoding) !== r.encoding && (t = v.from(t, e), e = ""), i = !0); + return n(this, t, e, !1, i); + }, r.prototype.unshift = function (t) + { + return n(this, t, null, !0, !1); + }, r.prototype.isPaused = function () + { + return !1 === this._readableState.flowing; + }, r.prototype.setEncoding = function (t) + { + return A || (A = L("string_decoder/").StringDecoder), this._readableState.decoder = new A(t), this._readableState.encoding = t, + this; + }, r.prototype.read = function (t) + { + I("read", t), t = parseInt(t, 10); + var e = this._readableState, r = t; + if(0 !== t && (e.emittedReadable = !1), 0 === t && e.needReadable && (e.length >= e.highWaterMark || e.ended)) + return I("read: emitReadable", e.length, e.ended), 0 === e.length && e.ended ? c(this) : u(this), null; + if(0 === (t = s(t, e)) && e.ended) + return 0 === e.length && c(this), null; + var i = e.needReadable; + return I("need readable", i), (0 === e.length || e.length - t < e.highWaterMark) && I("length less than watermark", i = !0), + e.ended || e.reading ? I("reading or ended", !1) : i && (I("do read"), e.reading = !0, e.sync = !0, 0 === e.length && (e.needReadable = !0), + this._read(e.highWaterMark), e.sync = !1, e.reading || (t = s(r, e))), null === (i = 0 < t ? f(t, e) : null) ? (e.needReadable = !0, + t = 0) : e.length -= t, 0 === e.length && (e.ended || (e.needReadable = !0), r !== t && e.ended && c(this)), null !== i && this.emit("data", + i), i; + }, r.prototype._read = function (t) + { + this.emit("error", Error("_read() is not implemented")); + }, r.prototype.pipe = function (i,t) + { + +function n() + { + I("onend"), i.end(); + }; + +function s(t) + { + I("ondata"), (p = !1) !== i.write(t) || p || ((1 === f.pipesCount && f.pipes === i || 1 < f.pipesCount && - 1 !== g(f.pipes, + i)) && !d && (I("false write response, pause", l._readableState.awaitDrain), l._readableState.awaitDrain++, p = !0), l.pause()); + }; + +function o(t) + { + I("onerror", t), u(), i.removeListener("error", o), 0 === i.listeners("error").length && i.emit("error", t); + }; + +function a() + { + i.removeListener("finish", h), u(); + }; + +function h() + { + I("onfinish"), i.removeListener("close", a), u(); + }; + +function u() + { + I("unpipe"), l.unpipe(i); + }; + var l = this, f = this._readableState; + switch(f.pipesCount) + { + case 0: + f.pipes = i; + break; + case 1: + f.pipes = [f.pipes, i]; + break; + default: + f.pipes.push(i); + } + f.pipesCount += 1, I("pipe count=%d opts=%j", f.pipesCount, t); + var e = t && !1 === t.end || i === m.stdout || i === m.stderr ? u : n; + f.endEmitted ? b.nextTick(e) : l.once("end", e), i.on("unpipe", function t(e,r) + { + I("onunpipe"), e === l && r && !1 === r.hasUnpiped && (r.hasUnpiped = !0, I("cleanup"), i.removeListener("close", a), i.removeListener("finish", + h), i.removeListener("drain", c), i.removeListener("error", o), i.removeListener("unpipe", t), l.removeListener("end", n), + l.removeListener("end", u), l.removeListener("data", s), d = !0, !f.awaitDrain || i._writableState && !i._writableState.needDrain || c()); + }); + var r, c = (r = l, function () + { + var t = r._readableState; + I("pipeOnDrain", t.awaitDrain), t.awaitDrain && t.awaitDrain--, 0 === t.awaitDrain && r.listeners("data").length && (t.flowing = !0, + _(r)); + }); + i.on("drain", c); + var d = !1, p = !1; + return l.on("data", s), function (t,e,r) + { + if("function" == typeof t.prependListener) + return t.prependListener(e, r); + t._events && t._events[e] ? y(t._events[e]) ? t._events[e].unshift(r) : t._events[e] = [r, t._events[e]] : t.on(e, r); + }(i, "error", o), i.once("close", a), i.once("finish", h), i.emit("pipe", l), f.flowing || (I("pipe resume"), l.resume()), + i; + }, r.prototype.unpipe = function (t) + { + var e = this._readableState, r = {hasUnpiped:!1}; + if(0 === e.pipesCount) + return this; + if(1 === e.pipesCount) + return t && t !== e.pipes || (t || (t = e.pipes), e.pipes = null, e.pipesCount = 0, e.flowing = !1, t && t.emit("unpipe", this, + r)), this; + if(t) + return - 1 === (i = g(e.pipes, t)) || (e.pipes.splice(i, 1), --e.pipesCount, 1 === e.pipesCount && (e.pipes = e.pipes[0]), + t.emit("unpipe", this, r)), this; + t = e.pipes; + var i = e.pipesCount; + for(e.pipes = null, e.pipesCount = 0, e.flowing = !1, e = 0; e < i; e++) + t[e].emit("unpipe", this, r); + return this; + }, r.prototype.addListener = r.prototype.on = function (t,e) + { + var r = w.prototype.on.call(this, t, e); + if("data" === t) + !1 !== this._readableState.flowing && this.resume(); + else + if("readable" === t) + { + var i = this._readableState; + i.endEmitted || i.readableListening || (i.readableListening = i.needReadable = !0, i.emittedReadable = !1, i.reading ? i.length && u(this) : b.nextTick(o, + this)); + } + return r; + }, r.prototype.resume = function () + { + var t = this._readableState; + return t.flowing || (I("resume"), t.flowing = !0, t.resumeScheduled || (t.resumeScheduled = !0, b.nextTick(a, this, t))), this; + }, r.prototype.pause = function () + { + return I("call pause flowing=%j", this._readableState.flowing), !1 !== this._readableState.flowing && (I("pause"), this._readableState.flowing = !1, + this.emit("pause")), this; + }, r.prototype.wrap = function (e) + { + var r = this, i = this._readableState, n = !1; + for(var t in e.on("end", function () + { + if(I("wrapped end"), i.decoder && !i.ended) + { + var t = i.decoder.end(); + t && t.length && r.push(t); + } + r.push(null); + }), e.on("data", function (t) + { + I("wrapped data"), i.decoder && (t = i.decoder.write(t)), i.objectMode && null == t || !(i.objectMode || t && t.length) || r.push(t) || (n = !0, + e.pause()); + }), e) + void 0 === this[t] && "function" == typeof e[t] && (this[t] = function (t) + { + return function () + { + return e[t].apply(e, arguments); + }; + }(t)); + for(t = 0; t < x.length; t++) + e.on(x[t], this.emit.bind(this, x[t])); + return this._read = function (t) + { + I("wrapped _read", t), n && (n = !1, e.resume()); + }, this; + }, Object.defineProperty(r.prototype, "readableHighWaterMark", {enumerable:!1, get:function () + { + return this._readableState.highWaterMark; + }}), r._fromList = f; + }).call(this, L("_process"), "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {}); + }, {"./_stream_duplex":13, "./internal/streams/BufferList":18, "./internal/streams/destroy":19, "./internal/streams/stream":20, + _process:11, "core-util-is":4, events:5, inherits:7, isarray:9, "process-nextick-args":10, "safe-buffer":25, "string_decoder/":27, + util:2}], 16:[function (t,e,r) + { + +function i(t) + { + if(!(this instanceof i)) + return new i(t); + o.call(this, t), this._transformState = {afterTransform:function (t,e) + { + var r = this._transformState; + r.transforming = !1; + var i = r.writecb; + if(!i) + return this.emit("error", Error("write callback called multiple times")); + r.writechunk = null, (r.writecb = null) != e && this.push(e), i(t), (r = this._readableState).reading = !1, (r.needReadable || r.length < r.highWaterMark) && this._read(r.highWaterMark); + }.bind(this), needTransform:!1, transforming:!1, writecb:null, writechunk:null, writeencoding:null}, this._readableState.needReadable = !0, + this._readableState.sync = !1, t && ("function" == typeof t.transform && (this._transform = t.transform), "function" == typeof t.flush && (this._flush = t.flush)), + this.on("prefinish", n); + }; + +function n() + { + var r = this; + "function" == typeof this._flush ? this._flush(function (t,e) + { + s(r, t, e); + }) : s(this, null, null); + }; + +function s(t,e,r) + { + if(e) + return t.emit("error", e); + if(null != r && t.push(r), t._writableState.length) + throw Error("Calling transform done when ws.length != 0"); + if(t._transformState.transforming) + throw Error("Calling transform done when still transforming"); + return t.push(null); + }; + e.exports = i; + var o = t("./_stream_duplex"); + (e = t("core-util-is")).inherits = t("inherits"), e.inherits(i, o), i.prototype.push = function (t,e) + { + return this._transformState.needTransform = !1, o.prototype.push.call(this, t, e); + }, i.prototype._transform = function (t,e,r) + { + throw Error("_transform() is not implemented"); + }, i.prototype._write = function (t,e,r) + { + var i = this._transformState; + i.writecb = r, i.writechunk = t, i.writeencoding = e, i.transforming || (t = this._readableState, (i.needTransform || t.needReadable || t.length < t.highWaterMark) && this._read(t.highWaterMark)); + }, i.prototype._read = function (t) + { + null !== (t = this._transformState).writechunk && t.writecb && !t.transforming ? (t.transforming = !0, this._transform(t.writechunk, + t.writeencoding, t.afterTransform)) : t.needTransform = !0; + }, i.prototype._destroy = function (t,e) + { + var r = this; + o.prototype._destroy.call(this, t, function (t) + { + e(t), r.emit("close"); + }); + }; + }, {"./_stream_duplex":13, "core-util-is":4, inherits:7}], 17:[function (v,M,t) + { + (function (t,e,r) + { + +function a(r) + { + var i = this; + this.entry = this.next = null, this.finish = function () + { + var t = i.entry; + for(i.entry = null; t; ) + { + var e = t.callback; + r.pendingcb--, e(void 0), t = t.next; + } + r.corkedRequestsFree ? r.corkedRequestsFree.next = i : r.corkedRequestsFree = i; + }; + }; + +function l() + { + }; + +function i(t,n) + { + p = p || v("./_stream_duplex"), t = t || {}; + var e = n instanceof p; + this.objectMode = !!t.objectMode, e && (this.objectMode = this.objectMode || !!t.writableObjectMode); + var r = t.highWaterMark, i = t.writableHighWaterMark, s = this.objectMode ? 16 : 16384; + this.highWaterMark = r || 0 === r ? r : e && (i || 0 === i) ? i : s, this.highWaterMark = Math.floor(this.highWaterMark), this.destroyed = this.finished = this.ended = this.ending = this.needDrain = this.finalCalled = !1, + this.decodeStrings = !1 !== t.decodeStrings, this.defaultEncoding = t.defaultEncoding || "utf8", this.length = 0, this.writing = !1, + this.corked = 0, this.sync = !0, this.bufferProcessing = !1, this.onwrite = function (t) + { + var e = n._writableState, r = e.sync, i = e.writecb; + e.writing = !1, e.writecb = null, e.length -= e.writelen, e.writelen = 0, t ? (--e.pendingcb, r ? (d.nextTick(i, t), d.nextTick(c, + n, e), n._writableState.errorEmitted = !0, n.emit("error", t)) : (i(t), n._writableState.errorEmitted = !0, n.emit("error", + t), c(n, e))) : ((t = u(e)) || e.corked || e.bufferProcessing || !e.bufferedRequest || h(n, e), r ? m(o, n, e, t, i) : o(n, + e, t, i)); + }, this.writecb = null, this.writelen = 0, this.lastBufferedRequest = this.bufferedRequest = null, this.pendingcb = 0, this.errorEmitted = this.prefinished = !1, + this.bufferedRequestCount = 0, this.corkedRequestsFree = new a(this); + }; + +function n(t) + { + if(p = p || v("./_stream_duplex"), !(w.call(n, this) || this instanceof p)) + return new n(t); + this._writableState = new i(t, this), this.writable = !0, t && ("function" == typeof t.write && (this._write = t.write), "function" == typeof t.writev && (this._writev = t.writev), + "function" == typeof t.destroy && (this._destroy = t.destroy), "function" == typeof t.final && (this._final = t.final)), g.call(this); + }; + +function f(t,e,r,i,n,s,o) + { + e.writelen = i, e.writecb = o, e.writing = !0, e.sync = !0, r ? t._writev(n, e.onwrite) : t._write(n, s, e.onwrite), e.sync = !1; + }; + +function o(t,e,r,i) + { + !r && 0 === e.length && e.needDrain && (e.needDrain = !1, t.emit("drain")), e.pendingcb--, i(), c(t, e); + }; + +function h(t,e) + { + e.bufferProcessing = !0; + var r = e.bufferedRequest; + if(t._writev && r && r.next) + { + var i = Array(e.bufferedRequestCount), n = e.corkedRequestsFree; + n.entry = r; + for(var s = 0, o = !0; r; ) + (i[s] = r).isBuf || (o = !1), r = r.next, s += 1; + i.allBuffers = o, f(t, e, !0, e.length, i, "", n.finish), e.pendingcb++, e.lastBufferedRequest = null, n.next ? (e.corkedRequestsFree = n.next, + n.next = null) : e.corkedRequestsFree = new a(e), e.bufferedRequestCount = 0; + } + else + { + for(; r && (i = r.chunk, f(t, e, !1, e.objectMode ? 1 : i.length, i, r.encoding, r.callback), r = r.next, e.bufferedRequestCount--, + !e.writing); ); + null === r && (e.lastBufferedRequest = null); + } + e.bufferedRequest = r, e.bufferProcessing = !1; + }; + +function u(t) + { + return t.ending && 0 === t.length && null === t.bufferedRequest && !t.finished && !t.writing; + }; + +function s(e,r) + { + e._final(function (t) + { + r.pendingcb--, t && e.emit("error", t), r.prefinished = !0, e.emit("prefinish"), c(e, r); + }); + }; + +function c(t,e) + { + var r = u(e); + return r && (e.prefinished || e.finalCalled || ("function" == typeof t._final ? (e.pendingcb++, e.finalCalled = !0, d.nextTick(s, + t, e)) : (e.prefinished = !0, t.emit("prefinish"))), 0 === e.pendingcb && (e.finished = !0, t.emit("finish"))), r; + }; + var d = v("process-nextick-args"); + M.exports = n; + var p, m = !t.browser && - 1 < ["v0.10", "v0.9."].indexOf(t.version.slice(0, 5)) ? r : d.nextTick; + n.WritableState = i, (t = v("core-util-is")).inherits = v("inherits"); + var _ = {deprecate:v("util-deprecate")}, g = v("./internal/streams/stream"), b = v("safe-buffer").Buffer, y = e.Uint8Array || function () + { + }; + if(e = v("./internal/streams/destroy"), t.inherits(n, g), i.prototype.getBuffer = function () + { + for(var t = this.bufferedRequest, e = []; t; ) + e.push(t), t = t.next; + return e; + }, function () + { + try + { + Object.defineProperty(i.prototype, "buffer", {get:_.deprecate(function () + { + return this.getBuffer(); + }, "_writableState.buffer is deprecated. Use _writableState.getBuffer instead.", "DEP0003")}); + } + catch(t) + { + } + }(), $jscomp.initSymbol(), $jscomp.initSymbol(), $jscomp.initSymbol(), "function" == typeof Symbol && Symbol.hasInstance && "function" == typeof Function.prototype[Symbol.hasInstance]) + { + $jscomp.initSymbol(); + var w = Function.prototype[Symbol.hasInstance]; + $jscomp.initSymbol(), Object.defineProperty(n, Symbol.hasInstance, {value:function (t) + { + return !!w.call(this, t) || this === n && (t && t._writableState instanceof i); + }}); + } + else + w = function (t) + { + return t instanceof this; + }; + n.prototype.pipe = function () + { + this.emit("error", Error("Cannot pipe, not readable")); + }, n.prototype.write = function (t,e,r) + { + var i, n = this._writableState, s = !1; + if((i = !n.objectMode) && (i = t, i = b.isBuffer(i) || i instanceof y), i && !b.isBuffer(t) && (t = b.from(t)), "function" == typeof e && (r = e, + e = null), i ? e = "buffer" : e || (e = n.defaultEncoding), "function" != typeof r && (r = l), n.ended) + n = r, r = Error("write after end"), this.emit("error", r), d.nextTick(n, r); + else + { + var o; + if(!(o = i)) + { + var a = r, h = !0, u = !1; + null === (o = t) ? u = new TypeError("May not write null values to stream") : "string" == typeof o || void 0 === o || n.objectMode || (u = new TypeError("Invalid non-string/buffer chunk")), + u && (this.emit("error", u), d.nextTick(a, u), h = !1), o = h; + } + o && (n.pendingcb++, (s = i) || (i = t, n.objectMode || !1 === n.decodeStrings || "string" != typeof i || (i = b.from(i, e)), + t !== i && (s = !0, e = "buffer", t = i)), o = n.objectMode ? 1 : t.length, n.length += o, (i = n.length < n.highWaterMark) || (n.needDrain = !0), + n.writing || n.corked ? (o = n.lastBufferedRequest, n.lastBufferedRequest = {chunk:t, encoding:e, isBuf:s, callback:r, next:null}, + o ? o.next = n.lastBufferedRequest : n.bufferedRequest = n.lastBufferedRequest, n.bufferedRequestCount += 1) : f(this, n, !1, + o, t, e, r), s = i); + } + return s; + }, n.prototype.cork = function () + { + this._writableState.corked++; + }, n.prototype.uncork = function () + { + var t = this._writableState; + t.corked && (t.corked--, t.writing || t.corked || t.finished || t.bufferProcessing || !t.bufferedRequest || h(this, t)); + }, n.prototype.setDefaultEncoding = function (t) + { + if("string" == typeof t && (t = t.toLowerCase()), !( - 1 < "hex utf8 utf-8 ascii binary base64 ucs2 ucs-2 utf16le utf-16le raw".split(" ").indexOf((t + "").toLowerCase()))) + throw new TypeError("Unknown encoding: " + t); + return this._writableState.defaultEncoding = t, this; + }, Object.defineProperty(n.prototype, "writableHighWaterMark", {enumerable:!1, get:function () + { + return this._writableState.highWaterMark; + }}), n.prototype._write = function (t,e,r) + { + r(Error("_write() is not implemented")); + }, n.prototype._writev = null, n.prototype.end = function (t,e,r) + { + var i = this._writableState; + "function" == typeof t ? (r = t, e = t = null) : "function" == typeof e && (r = e, e = null), null != t && this.write(t, e), + i.corked && (i.corked = 1, this.uncork()), i.ending || i.finished || (t = r, i.ending = !0, c(this, i), t && (i.finished ? d.nextTick(t) : this.once("finish", + t)), i.ended = !0, this.writable = !1); + }, Object.defineProperty(n.prototype, "destroyed", {get:function () + { + return void 0 !== this._writableState && this._writableState.destroyed; + }, set:function (t) + { + this._writableState && (this._writableState.destroyed = t); + }}), n.prototype.destroy = e.destroy, n.prototype._undestroy = e.undestroy, n.prototype._destroy = function (t,e) + { + this.end(), e(t); + }; + }).call(this, v("_process"), "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {}, + v("timers").setImmediate); + }, {"./_stream_duplex":13, "./internal/streams/destroy":19, "./internal/streams/stream":20, _process:11, "core-util-is":4, + inherits:7, "process-nextick-args":10, "safe-buffer":25, timers:28, "util-deprecate":29}], 18:[function (t,e,r) + { + var i = t("safe-buffer").Buffer, n = t("util"); + e.exports = function () + { + +function t() + { + if(!(this instanceof t)) + throw new TypeError("Cannot call a class as a function"); + this.tail = this.head = null, this.length = 0; + }; + return t.prototype.push = function (t) + { + t = {data:t, next:null}, 0 < this.length ? this.tail.next = t : this.head = t, this.tail = t, ++this.length; + }, t.prototype.unshift = function (t) + { + t = {data:t, next:this.head}, 0 === this.length && (this.tail = t), this.head = t, ++this.length; + }, t.prototype.shift = function () + { + if(0 !== this.length) + { + var t = this.head.data; + return this.head = 1 === this.length ? this.tail = null : this.head.next, --this.length, t; + } + }, t.prototype.clear = function () + { + this.head = this.tail = null, this.length = 0; + }, t.prototype.join = function (t) + { + if(0 === this.length) + return ""; + for(var e = this.head, r = "" + e.data; e = e.next; ) + r += t + e.data; + return r; + }, t.prototype.concat = function (t) + { + if(0 === this.length) + return i.alloc(0); + if(1 === this.length) + return this.head.data; + t = i.allocUnsafe(t >>> 0); + for(var e = this.head, r = 0; e; ) + e.data.copy(t, r), r += e.data.length, e = e.next; + return t; + }, t; + }(), n && n.inspect && n.inspect.custom && (e.exports.prototype[n.inspect.custom] = function () + { + var t = n.inspect({length:this.length}); + return this.constructor.name + " " + t; + }); + }, {"safe-buffer":25, util:2}], 19:[function (t,e,r) + { + +function n(t,e) + { + t.emit("error", e); + }; + var s = t("process-nextick-args"); + e.exports = {destroy:function (t,e) + { + var r = this, i = this._writableState && this._writableState.destroyed; + return this._readableState && this._readableState.destroyed || i ? e ? e(t) : !t || this._writableState && this._writableState.errorEmitted || s.nextTick(n, + this, t) : (this._readableState && (this._readableState.destroyed = !0), this._writableState && (this._writableState.destroyed = !0), + this._destroy(t || null, function (t) + { + !e && t ? (s.nextTick(n, r, t), r._writableState && (r._writableState.errorEmitted = !0)) : e && e(t); + })), this; + }, undestroy:function () + { + this._readableState && (this._readableState.destroyed = !1, this._readableState.reading = !1, this._readableState.ended = !1, + this._readableState.endEmitted = !1), this._writableState && (this._writableState.destroyed = !1, this._writableState.ended = !1, + this._writableState.ending = !1, this._writableState.finished = !1, this._writableState.errorEmitted = !1); + }}; + }, {"process-nextick-args":10}], 20:[function (t,e,r) + { + e.exports = t("events").EventEmitter; + }, {events:5}], 21:[function (t,e,r) + { + e.exports = t("./readable").PassThrough; + }, {"./readable":22}], 22:[function (t,e,r) + { + (((r = e.exports = t("./lib/_stream_readable.js")).Stream = r).Readable = r).Writable = t("./lib/_stream_writable.js"), r.Duplex = t("./lib/_stream_duplex.js"), + r.Transform = t("./lib/_stream_transform.js"), r.PassThrough = t("./lib/_stream_passthrough.js"); + }, {"./lib/_stream_duplex.js":13, "./lib/_stream_passthrough.js":14, "./lib/_stream_readable.js":15, "./lib/_stream_transform.js":16, + "./lib/_stream_writable.js":17}], 23:[function (t,e,r) + { + e.exports = t("./readable").Transform; + }, {"./readable":22}], 24:[function (t,e,r) + { + e.exports = t("./lib/_stream_writable.js"); + }, {"./lib/_stream_writable.js":17}], 25:[function (t,e,r) + { + +function i(t,e) + { + for(var r in t) + e[r] = t[r]; + }; + +function n(t,e,r) + { + return o(t, e, r); + }; + var s = t("buffer"), o = s.Buffer; + o.from && o.alloc && o.allocUnsafe && o.allocUnsafeSlow ? e.exports = s : (i(s, r), r.Buffer = n), i(o, n), n.from = function (t,e,r) + { + if("number" == typeof t) + throw new TypeError("Argument must not be a number"); + return o(t, e, r); + }, n.alloc = function (t,e,r) + { + if("number" != typeof t) + throw new TypeError("Argument must be a number"); + return t = o(t), void 0 !== e ? "string" == typeof r ? t.fill(e, r) : t.fill(e) : t.fill(0), t; + }, n.allocUnsafe = function (t) + { + if("number" != typeof t) + throw new TypeError("Argument must be a number"); + return o(t); + }, n.allocUnsafeSlow = function (t) + { + if("number" != typeof t) + throw new TypeError("Argument must be a number"); + return s.SlowBuffer(t); + }; + }, {buffer:3}], 26:[function (t,e,r) + { + +function i() + { + l.call(this); + }; + e.exports = i; + var l = t("events").EventEmitter; + t("inherits")(i, l), i.Readable = t("readable-stream/readable.js"), i.Writable = t("readable-stream/writable.js"), i.Duplex = t("readable-stream/duplex.js"), + i.Transform = t("readable-stream/transform.js"), i.PassThrough = t("readable-stream/passthrough.js"), (i.Stream = i).prototype.pipe = function (e,t) + { + +function r(t) + { + e.writable && !1 === e.write(t) && h.pause && h.pause(); + }; + +function i() + { + h.readable && h.resume && h.resume(); + }; + +function n() + { + u || (u = !0, e.end()); + }; + +function s() + { + u || (u = !0, "function" == typeof e.destroy && e.destroy()); + }; + +function o(t) + { + if(a(), 0 === l.listenerCount(this, "error")) + throw t; + }; + +function a() + { + h.removeListener("data", r), e.removeListener("drain", i), h.removeListener("end", n), h.removeListener("close", s), h.removeListener("error", + o), e.removeListener("error", o), h.removeListener("end", a), h.removeListener("close", a), e.removeListener("close", a); + }; + var h = this; + h.on("data", r), e.on("drain", i), e._isStdio || t && !1 === t.end || (h.on("end", n), h.on("close", s)); + var u = !1; + return h.on("error", o), e.on("error", o), h.on("end", a), h.on("close", a), e.on("close", a), e.emit("pipe", h), e; + }; + }, {events:5, inherits:7, "readable-stream/duplex.js":12, "readable-stream/passthrough.js":21, "readable-stream/readable.js":22, + "readable-stream/transform.js":23, "readable-stream/writable.js":24}], 27:[function (t,e,r) + { + +function i(t) + { + var e = function (t) + { + if(!t) + return "utf8"; + for(var e; ; ) + switch(t) + { + case "utf8": + case "utf-8": + return "utf8"; + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + return "utf16le"; + case "latin1": + case "binary": + return "latin1"; + case "base64": + case "ascii": + case "hex": + return t; + default: + if(e) + return ; + t = ("" + t).toLowerCase(), e = !0; + } + }(t); + if("string" != typeof e && (c.isEncoding === d || !d(t))) + throw Error("Unknown encoding: " + t); + switch(this.encoding = e || t, this.encoding) + { + case "utf16le": + this.text = o, this.end = a, t = 4; + break; + case "utf8": + this.fillLast = n, t = 4; + break; + case "base64": + this.text = h, this.end = u, t = 3; + break; + default: + return this.write = l, void (this.end = f); + } + this.lastTotal = this.lastNeed = 0, this.lastChar = c.allocUnsafe(t); + }; + +function s(t) + { + return t <= 127 ? 0 : 6 == t >> 5 ? 2 : 14 == t >> 4 ? 3 : 30 == t >> 3 ? 4 : 2 == t >> 6 ? - 1 : - 2; + }; + +function n(t) + { + var e = this.lastTotal - this.lastNeed; + t: + if(128 != (192 & t[0])) + { + this.lastNeed = 0; + var r = "�"; + } + else + { + if(1 < this.lastNeed && 1 < t.length) + { + if(128 != (192 & t[1])) + { + this.lastNeed = 1, r = "�"; + break t; + } + if(2 < this.lastNeed && 2 < t.length && 128 != (192 & t[2])) + { + this.lastNeed = 2, r = "�"; + break t; + } + } + r = void 0; + } + return void 0 !== r ? r : this.lastNeed <= t.length ? (t.copy(this.lastChar, e, 0, this.lastNeed), this.lastChar.toString(this.encoding, + 0, this.lastTotal)) : (t.copy(this.lastChar, e, 0, t.length), void (this.lastNeed -= t.length)); + }; + +function o(t,e) + { + if(0 != (t.length - e) % 2) + return this.lastNeed = 1, this.lastTotal = 2, this.lastChar[0] = t[t.length - 1], t.toString("utf16le", e, t.length - 1); + var r = t.toString("utf16le", e); + if(r) + { + var i = r.charCodeAt(r.length - 1); + if(55296 <= i && i <= 56319) + return this.lastNeed = 2, this.lastTotal = 4, this.lastChar[0] = t[t.length - 2], this.lastChar[1] = t[t.length - 1], r.slice(0, + - 1); + } + return r; + }; + +function a(t) + { + return t = t && t.length ? this.write(t) : "", this.lastNeed ? t + this.lastChar.toString("utf16le", 0, this.lastTotal - this.lastNeed) : t; + }; + +function h(t,e) + { + var r = (t.length - e) % 3; + return 0 === r ? t.toString("base64", e) : (this.lastNeed = 3 - r, this.lastTotal = 3, 1 === r ? this.lastChar[0] = t[t.length - 1] : (this.lastChar[0] = t[t.length - 2], + this.lastChar[1] = t[t.length - 1]), t.toString("base64", e, t.length - r)); + }; + +function u(t) + { + return t = t && t.length ? this.write(t) : "", this.lastNeed ? t + this.lastChar.toString("base64", 0, 3 - this.lastNeed) : t; + }; + +function l(t) + { + return t.toString(this.encoding); + }; + +function f(t) + { + return t && t.length ? this.write(t) : ""; + }; + var c = t("safe-buffer").Buffer, d = c.isEncoding || function (t) + { + switch((t = "" + t) && t.toLowerCase()) + { + case "hex": + case "utf8": + case "utf-8": + case "ascii": + case "binary": + case "base64": + case "ucs2": + case "ucs-2": + case "utf16le": + case "utf-16le": + case "raw": + return !0; + default: + return !1; + } + }; + (r.StringDecoder = i).prototype.write = function (t) + { + if(0 === t.length) + return ""; + if(this.lastNeed) + { + var e = this.fillLast(t); + if(void 0 === e) + return ""; + var r = this.lastNeed; + this.lastNeed = 0; + } + else + r = 0; + return r < t.length ? e ? e + this.text(t, r) : this.text(t, r) : e || ""; + }, i.prototype.end = function (t) + { + return t = t && t.length ? this.write(t) : "", this.lastNeed ? t + "�" : t; + }, i.prototype.text = function (t,e) + { + var r = function (t,e,r) + { + var i = e.length - 1; + if(i < r) + return 0; + var n = s(e[i]); + return 0 <= n ? (0 < n && (t.lastNeed = n - 1), n) : --i < r || - 2 === n ? 0 : 0 <= (n = s(e[i])) ? (0 < n && (t.lastNeed = n - 2), + n) : --i < r || - 2 === n ? 0 : 0 <= (n = s(e[i])) ? (0 < n && (2 === n ? n = 0 : t.lastNeed = n - 3), n) : 0; + }(this, t, e); + return this.lastNeed ? (this.lastTotal = r, r = t.length - (r - this.lastNeed), t.copy(this.lastChar, 0, r), t.toString("utf8", + e, r)) : t.toString("utf8", e); + }, i.prototype.fillLast = function (t) + { + if(this.lastNeed <= t.length) + return t.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed), this.lastChar.toString(this.encoding, 0, this.lastTotal); + t.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, t.length), this.lastNeed -= t.length; + }; + }, {"safe-buffer":25}], 28:[function (h,t,u) + { + (function (t,e) + { + +function r(t,e) + { + this._id = t, this._clearFn = e; + }; + var i = h("process/browser.js").nextTick, n = Function.prototype.apply, s = Array.prototype.slice, o = {}, a = 0; + u.setTimeout = function () + { + return new r(n.call(setTimeout, window, arguments), clearTimeout); + }, u.setInterval = function () + { + return new r(n.call(setInterval, window, arguments), clearInterval); + }, u.clearTimeout = u.clearInterval = function (t) + { + t.close(); + }, r.prototype.unref = r.prototype.ref = function () + { + }, r.prototype.close = function () + { + this._clearFn.call(window, this._id); + }, u.enroll = function (t,e) + { + clearTimeout(t._idleTimeoutId), t._idleTimeout = e; + }, u.unenroll = function (t) + { + clearTimeout(t._idleTimeoutId), t._idleTimeout = - 1; + }, u._unrefActive = u.active = function (t) + { + clearTimeout(t._idleTimeoutId); + var e = t._idleTimeout; + 0 <= e && (t._idleTimeoutId = setTimeout(function () + { + t._onTimeout && t._onTimeout(); + }, e)); + }, u.setImmediate = "function" == typeof t ? t : function (t) + { + var e = a++, r = !(arguments.length < 2) && s.call(arguments, 1); + return o[e] = !0, i(function () + { + o[e] && (r ? t.apply(null, r) : t.call(null), u.clearImmediate(e)); + }), e; + }, u.clearImmediate = "function" == typeof e ? e : function (t) + { + delete o[t]; + }; + }).call(this, h("timers").setImmediate, h("timers").clearImmediate); + }, {"process/browser.js":11, timers:28}], 29:[function (t,r,e) + { + (function (e) + { + +function i(t) + { + try + { + if(!e.localStorage) + return !1; + } + catch(t) + { + return !1; + } + return null != (t = e.localStorage[t]) && "true" === String(t).toLowerCase(); + }; + r.exports = function (t,e) + { + if(i("noDeprecation")) + return t; + var r = !1; + return function () + { + if(!r) + { + if(i("throwDeprecation")) + throw Error(e); + i("traceDeprecation") ? console.trace(e) : console.warn(e), r = !0; + } + return t.apply(this, arguments); + }; + }; + }).call(this, "undefined" != typeof global ? global : "undefined" != typeof self ? self : "undefined" != typeof window ? window : {}); + }, {}], 30:[function (t,e,r) + { + window.SignLib = t("secp256k1/lib/js"), window.Buffer = t("safe-buffer").Buffer; + }, {"safe-buffer":42, "secp256k1/lib/js":48}], 31:[function (t,e,r) + { + +function i(t) + { + s.call(this), (this.hashMode = "string" == typeof t) ? this[t] = this._finalOrDigest : this.final = this._finalOrDigest, this._final && (this.__final = this._final, + this._final = null), this._encoding = this._decoder = null; + }; + var n = t("safe-buffer").Buffer, s = t("stream").Transform, o = t("string_decoder").StringDecoder; + t("inherits")(i, s), i.prototype.update = function (t,e,r) + { + return "string" == typeof t && (t = n.from(t, e)), t = this._update(t), this.hashMode ? this : (r && (t = this._toString(t, + r)), t); + }, i.prototype.setAutoPadding = function () + { + }, i.prototype.getAuthTag = function () + { + throw Error("trying to get auth tag in unsupported state"); + }, i.prototype.setAuthTag = function () + { + throw Error("trying to set auth tag in unsupported state"); + }, i.prototype.setAAD = function () + { + throw Error("trying to set aad in unsupported state"); + }, i.prototype._transform = function (t,e,r) + { + try + { + this.hashMode ? this._update(t) : this.push(this._update(t)); + } + catch(t) + { + var i = t; + } + finally + { + r(i); + } + }, i.prototype._flush = function (t) + { + try + { + this.push(this.__final()); + } + catch(t) + { + var e = t; + } + t(e); + }, i.prototype._finalOrDigest = function (t) + { + var e = this.__final() || n.alloc(0); + return t && (e = this._toString(e, t, !0)), e; + }, i.prototype._toString = function (t,e,r) + { + if(this._decoder || (this._decoder = new o(e), this._encoding = e), this._encoding !== e) + throw Error("can't switch encodings"); + return t = this._decoder.write(t), r && (t += this._decoder.end()), t; + }, e.exports = i; + }, {inherits:39, "safe-buffer":42, stream:26, string_decoder:27}], 32:[function (t,e,r) + { + +function i(t) + { + a.call(this, "digest"), this._hash = t; + }; + r = t("inherits"); + var n = t("md5.js"), s = t("ripemd160"), o = t("sha.js"), a = t("cipher-base"); + r(i, a), i.prototype._update = function (t) + { + this._hash.update(t); + }, i.prototype._final = function () + { + return this._hash.digest(); + }, e.exports = function (t) + { + return "md5" === (t = t.toLowerCase()) ? new n : "rmd160" === t || "ripemd160" === t ? new s : new i(o(t)); + }; + }, {"cipher-base":31, inherits:39, "md5.js":40, ripemd160:41, "sha.js":51}], 33:[function (t,e,r) + { + var i = t("md5.js"); + e.exports = function (t) + { + return (new i).update(t).digest(); + }; + }, {"md5.js":40}], 34:[function (t,e,r) + { + +function i(t,e) + { + o.call(this, "digest"), "string" == typeof e && (e = a.from(e)); + var r = "sha512" === t || "sha384" === t ? 128 : 64; + this._alg = t, (this._key = e).length > r ? e = ("rmd160" === t ? new h : u(t)).update(e).digest() : e.length < r && (e = a.concat([e, + l], r)); + for(var i = this._ipad = a.allocUnsafe(r), n = this._opad = a.allocUnsafe(r), s = 0; s < r; s++) + i[s] = 54 ^ e[s], n[s] = 92 ^ e[s]; + this._hash = "rmd160" === t ? new h : u(t), this._hash.update(i); + }; + r = t("inherits"); + var n = t("./legacy"), o = t("cipher-base"), a = t("safe-buffer").Buffer, s = t("create-hash/md5"), h = t("ripemd160"), u = t("sha.js"), + l = a.alloc(128); + r(i, o), i.prototype._update = function (t) + { + this._hash.update(t); + }, i.prototype._final = function () + { + var t = this._hash.digest(); + return ("rmd160" === this._alg ? new h : u(this._alg)).update(this._opad).update(t).digest(); + }, e.exports = function (t,e) + { + return "rmd160" === (t = t.toLowerCase()) || "ripemd160" === t ? new i("rmd160", e) : "md5" === t ? new n(s, e) : new i(t, + e); + }; + }, {"./legacy":35, "cipher-base":31, "create-hash/md5":33, inherits:39, ripemd160:41, "safe-buffer":42, "sha.js":51}], 35:[function (t,e,r) + { + +function i(t,e) + { + o.call(this, "digest"), "string" == typeof e && (e = s.from(e)), this._alg = t, 64 < (this._key = e).length ? e = t(e) : e.length < 64 && (e = s.concat([e, + a], 64)); + for(var r = this._ipad = s.allocUnsafe(64), i = this._opad = s.allocUnsafe(64), n = 0; n < 64; n++) + r[n] = 54 ^ e[n], i[n] = 92 ^ e[n]; + this._hash = [r]; + }; + r = t("inherits"); + var s = t("safe-buffer").Buffer, o = t("cipher-base"), a = s.alloc(128); + r(i, o), i.prototype._update = function (t) + { + this._hash.push(t); + }, i.prototype._final = function () + { + var t = this._alg(s.concat(this._hash)); + return this._alg(s.concat([this._opad, t])); + }, e.exports = i; + }, {"cipher-base":31, inherits:39, "safe-buffer":42}], 36:[function (e,h,t) + { + (function (n) + { + +function t(t,e,r,i) + { + var n = s[t]; + if(void 0 === n) + throw Error("hash " + t + " is not supported"); + this._algo = t, this._securityStrength = n.securityStrength / 8, this._outlen = n.outlen / 8, this._reseedInterval = 281474976710656, + this._init(e, r, i); + }; + var i = e("create-hmac"), s = e("./lib/hash-info.json"), o = new n(0), r = new n([0]), a = new n([1]); + t.prototype._update = function (t) + { + var e = i(this._algo, this._K).update(this._V).update(r); + t && e.update(t), this._K = e.digest(), this._V = i(this._algo, this._K).update(this._V).digest(), t && (this._K = i(this._algo, + this._K).update(this._V).update(a).update(t).digest(), this._V = i(this._algo, this._K).update(this._V).digest()); + }, t.prototype._init = function (t,e,r) + { + if(t.length < this._securityStrength) + throw Error("Not enough entropy"); + this._K = new n(this._outlen), this._V = new n(this._outlen); + for(var i = 0; i < this._K.length; ++i) + this._K[i] = 0, this._V[i] = 1; + this._update(n.concat([t, e, r || o])), this._reseed = 1; + }, t.prototype.reseed = function (t,e) + { + if(t.length < this._securityStrength) + throw Error("Not enough entropy"); + this._update(n.concat([t, e || o])), this._reseed = 1; + }, t.prototype.generate = function (t,e) + { + if(this._reseed > this._reseedInterval) + throw Error("Reseed is required"); + e && 0 === e.length && (e = void 0), e && this._update(e); + for(var r = new n(0); r.length < t; ) + this._V = i(this._algo, this._K).update(this._V).digest(), r = n.concat([r, this._V]); + return this._update(e), this._reseed += 1, r.slice(0, t); + }, h.exports = t; + }).call(this, e("buffer").Buffer); + }, {"./lib/hash-info.json":37, buffer:3, "create-hmac":34}], 37:[function (t,e,r) + { + e.exports = {sha1:{securityStrength:128, outlen:160, seedlen:440}, sha224:{securityStrength:192, outlen:224, seedlen:440}, + sha256:{securityStrength:256, outlen:256, seedlen:440}, sha384:{securityStrength:256, outlen:384, seedlen:888}, sha512:{securityStrength:256, + outlen:512, seedlen:888}}; + }, {}], 38:[function (t,e,r) + { + +function i(t) + { + n.call(this), this._block = s.allocUnsafe(t), this._blockSize = t, this._blockOffset = 0, this._length = [0, 0, 0, 0], this._finalized = !1; + }; + var s = t("safe-buffer").Buffer, n = t("stream").Transform; + t("inherits")(i, n), i.prototype._transform = function (t,e,r) + { + var i = null; + try + { + this.update(t, e); + } + catch(t) + { + i = t; + } + r(i); + }, i.prototype._flush = function (t) + { + var e = null; + try + { + this.push(this.digest()); + } + catch(t) + { + e = t; + } + t(e); + }, i.prototype.update = function (t,e) + { + var r = t; + if(!s.isBuffer(r) && "string" != typeof r) + throw new TypeError("Data must be a string or a buffer"); + if(this._finalized) + throw Error("Digest already called"); + s.isBuffer(t) || (t = s.from(t, e)), r = this._block; + for(var i = 0; this._blockOffset + t.length - i >= this._blockSize; ) + { + for(var n = this._blockOffset; n < this._blockSize; ) + r[n++] = t[i++]; + this._update(), this._blockOffset = 0; + } + for(; i < t.length; ) + r[this._blockOffset++] = t[i++]; + for(r = 0, i = 8 * t.length; 0 < i; ++r) + this._length[r] += i, 0 < (i = this._length[r] / 4294967296 | 0) && (this._length[r] -= 4294967296 * i); + return this; + }, i.prototype._update = function () + { + throw Error("_update is not implemented"); + }, i.prototype.digest = function (t) + { + if(this._finalized) + throw Error("Digest already called"); + this._finalized = !0; + var e = this._digest(); + for(void 0 !== t && (e = e.toString(t)), this._block.fill(0), t = this._blockOffset = 0; t < 4; ++t) + this._length[t] = 0; + return e; + }, i.prototype._digest = function () + { + throw Error("_digest is not implemented"); + }, e.exports = i; + }, {inherits:39, "safe-buffer":42, stream:26}], 39:[function (t,e,r) + { + arguments[4][7][0].apply(r, arguments); + }, {dup:7}], 40:[function (l,f,t) + { + (function (e) + { + +function t() + { + i.call(this, 64), this._a = 1732584193, this._b = 4023233417, this._c = 2562383102, this._d = 271733878; + }; + +function a(t,e) + { + return t << e | t >>> 32 - e; + }; + +function n(t,e,r,i,n,s,o) + { + return a(t + (e & r | ~e & i) + n + s | 0, o) + e | 0; + }; + +function s(t,e,r,i,n,s,o) + { + return a(t + (e & i | r & ~i) + n + s | 0, o) + e | 0; + }; + +function o(t,e,r,i,n,s,o) + { + return a(t + (e ^ r ^ i) + n + s | 0, o) + e | 0; + }; + +function h(t,e,r,i,n,s,o) + { + return a(t + (r ^ (e | ~i)) + n + s | 0, o) + e | 0; + }; + var r = l("inherits"), i = l("hash-base"), u = Array(16); + r(t, i), t.prototype._update = function () + { + for(var t = 0; t < 16; ++t) + u[t] = this._block.readInt32LE(4 * t); + t = this._a; + var e = this._b, r = this._c, i = this._d; + e = h(e = h(e = h(e = h(e = o(e = o(e = o(e = o(e = s(e = s(e = s(e = s(e = n(e = n(e = n(e = n(e, r = n(r, i = n(i, t = n(t, + e, r, i, u[0], 3614090360, 7), e, r, u[1], 3905402710, 12), t, e, u[2], 606105819, 17), i, t, u[3], 3250441966, 22), r = n(r, + i = n(i, t = n(t, e, r, i, u[4], 4118548399, 7), e, r, u[5], 1200080426, 12), t, e, u[6], 2821735955, 17), i, t, u[7], 4249261313, + 22), r = n(r, i = n(i, t = n(t, e, r, i, u[8], 1770035416, 7), e, r, u[9], 2336552879, 12), t, e, u[10], 4294925233, 17), i, + t, u[11], 2304563134, 22), r = n(r, i = n(i, t = n(t, e, r, i, u[12], 1804603682, 7), e, r, u[13], 4254626195, 12), t, e, u[14], + 2792965006, 17), i, t, u[15], 1236535329, 22), r = s(r, i = s(i, t = s(t, e, r, i, u[1], 4129170786, 5), e, r, u[6], 3225465664, + 9), t, e, u[11], 643717713, 14), i, t, u[0], 3921069994, 20), r = s(r, i = s(i, t = s(t, e, r, i, u[5], 3593408605, 5), e, + r, u[10], 38016083, 9), t, e, u[15], 3634488961, 14), i, t, u[4], 3889429448, 20), r = s(r, i = s(i, t = s(t, e, r, i, u[9], + 568446438, 5), e, r, u[14], 3275163606, 9), t, e, u[3], 4107603335, 14), i, t, u[8], 1163531501, 20), r = s(r, i = s(i, t = s(t, + e, r, i, u[13], 2850285829, 5), e, r, u[2], 4243563512, 9), t, e, u[7], 1735328473, 14), i, t, u[12], 2368359562, 20), r = o(r, + i = o(i, t = o(t, e, r, i, u[5], 4294588738, 4), e, r, u[8], 2272392833, 11), t, e, u[11], 1839030562, 16), i, t, u[14], 4259657740, + 23), r = o(r, i = o(i, t = o(t, e, r, i, u[1], 2763975236, 4), e, r, u[4], 1272893353, 11), t, e, u[7], 4139469664, 16), i, + t, u[10], 3200236656, 23), r = o(r, i = o(i, t = o(t, e, r, i, u[13], 681279174, 4), e, r, u[0], 3936430074, 11), t, e, u[3], + 3572445317, 16), i, t, u[6], 76029189, 23), r = o(r, i = o(i, t = o(t, e, r, i, u[9], 3654602809, 4), e, r, u[12], 3873151461, + 11), t, e, u[15], 530742520, 16), i, t, u[2], 3299628645, 23), r = h(r, i = h(i, t = h(t, e, r, i, u[0], 4096336452, 6), e, + r, u[7], 1126891415, 10), t, e, u[14], 2878612391, 15), i, t, u[5], 4237533241, 21), r = h(r, i = h(i, t = h(t, e, r, i, u[12], + 1700485571, 6), e, r, u[3], 2399980690, 10), t, e, u[10], 4293915773, 15), i, t, u[1], 2240044497, 21), r = h(r, i = h(i, t = h(t, + e, r, i, u[8], 1873313359, 6), e, r, u[15], 4264355552, 10), t, e, u[6], 2734768916, 15), i, t, u[13], 1309151649, 21), r = h(r, + i = h(i, t = h(t, e, r, i, u[4], 4149444226, 6), e, r, u[11], 3174756917, 10), t, e, u[2], 718787259, 15), i, t, u[9], 3951481745, + 21), this._a = this._a + t | 0, this._b = this._b + e | 0, this._c = this._c + r | 0, this._d = this._d + i | 0; + }, t.prototype._digest = function () + { + this._block[this._blockOffset++] = 128, 56 < this._blockOffset && (this._block.fill(0, this._blockOffset, 64), this._update(), + this._blockOffset = 0), this._block.fill(0, this._blockOffset, 56), this._block.writeUInt32LE(this._length[0], 56), this._block.writeUInt32LE(this._length[1], + 60), this._update(); + var t = new e(16); + return t.writeInt32LE(this._a, 0), t.writeInt32LE(this._b, 4), t.writeInt32LE(this._c, 8), t.writeInt32LE(this._d, 12), t; + }, f.exports = t; + }).call(this, l("buffer").Buffer); + }, {buffer:3, "hash-base":38, inherits:39}], 41:[function (t,e,r) + { + +function i() + { + s.call(this, 64), this._a = 1732584193, this._b = 4023233417, this._c = 2562383102, this._d = 271733878, this._e = 3285377520; + }; + +function d(t,e) + { + return t << e | t >>> 32 - e; + }; + var n = t("buffer").Buffer; + r = t("inherits"); + var s = t("hash-base"), p = Array(16), m = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, + 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, + 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13], _ = [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, + 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11], g = [11, 14, 15, 12, 5, 8, 7, + 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, + 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, + 8, 5, 6], b = [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, + 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, + 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11], y = [0, 1518500249, 1859775393, 2400959708, 2840853838], w = [1352829926, 1548603684, + 1836072691, 2053994217, 0]; + r(i, s), i.prototype._update = function () + { + for(var t = 0; t < 16; ++t) + p[t] = this._block.readInt32LE(4 * t); + var e = 0 | this._a; + t = 0 | this._b; + for(var r = 0 | this._c, i = 0 | this._d, n = 0 | this._e, s = 0 | this._a, o = 0 | this._b, a = 0 | this._c, h = 0 | this._d, + u = 0 | this._e, l = 0; l < 80; l += 1) + { + if(l < 16) + { + var f = n; + f = d(e + (t ^ r ^ i) + p[m[l]] + y[0] | 0, g[l]) + f | 0, e = u; + var c = d(s + (o ^ (a | ~h)) + p[_[l]] + w[0] | 0, b[l]) + e | 0; + } + else + c = l < 32 ? (f = n, f = d(e + (t & r | ~t & i) + p[m[l]] + y[1] | 0, g[l]) + f | 0, e = u, d(s + (o & h | a & ~h) + p[_[l]] + w[1] | 0, + b[l]) + e | 0) : l < 48 ? (f = n, f = d(e + ((t | ~r) ^ i) + p[m[l]] + y[2] | 0, g[l]) + f | 0, e = u, d(s + ((o | ~a) ^ h) + p[_[l]] + w[2] | 0, + b[l]) + e | 0) : l < 64 ? (f = n, f = d(e + (t & i | r & ~i) + p[m[l]] + y[3] | 0, g[l]) + f | 0, e = u, d(s + (o & a | ~o & h) + p[_[l]] + w[3] | 0, + b[l]) + e | 0) : (f = n, f = d(e + (t ^ (r | ~i)) + p[m[l]] + y[4] | 0, g[l]) + f | 0, e = u, d(s + (o ^ a ^ h) + p[_[l]] + w[4] | 0, + b[l]) + e | 0); + e = n, n = i, i = d(r, 10), r = t, t = f, s = u, u = h, h = d(a, 10), a = o, o = c; + } + r = this._b + r + h | 0, this._b = this._c + i + u | 0, this._c = this._d + n + s | 0, this._d = this._e + e + o | 0, this._e = this._a + t + a | 0, + this._a = r; + }, i.prototype._digest = function () + { + this._block[this._blockOffset++] = 128, 56 < this._blockOffset && (this._block.fill(0, this._blockOffset, 64), this._update(), + this._blockOffset = 0), this._block.fill(0, this._blockOffset, 56), this._block.writeUInt32LE(this._length[0], 56), this._block.writeUInt32LE(this._length[1], + 60), this._update(); + var t = n.alloc ? n.alloc(20) : new n(20); + return t.writeInt32LE(this._a, 0), t.writeInt32LE(this._b, 4), t.writeInt32LE(this._c, 8), t.writeInt32LE(this._d, 12), t.writeInt32LE(this._e, + 16), t; + }, e.exports = i; + }, {buffer:3, "hash-base":38, inherits:39}], 42:[function (t,e,r) + { + arguments[4][25][0].apply(r, arguments); + }, {buffer:3, dup:25}], 43:[function (t,e,r) + { + +function l() + { + this.negative = 0, this.words = null, this.length = 0; + }; + var i = t("safe-buffer").Buffer; + t = t("./optimized"), l.fromNumber = function (t) + { + var e = new l; + return e.words = [67108863 & t], e.length = 1, e; + }, l.fromBuffer = function (t) + { + var e = new l; + return e.words = Array(10), e.words[0] = (3 & t[28]) << 24 | t[29] << 16 | t[30] << 8 | t[31], e.words[1] = (15 & t[25]) << 22 | t[26] << 14 | t[27] << 6 | t[28] >>> 2, + e.words[2] = (63 & t[22]) << 20 | t[23] << 12 | t[24] << 4 | t[25] >>> 4, e.words[3] = (255 & t[19]) << 18 | t[20] << 10 | t[21] << 2 | t[22] >>> 6, + e.words[4] = (3 & t[15]) << 24 | t[16] << 16 | t[17] << 8 | t[18], e.words[5] = (15 & t[12]) << 22 | t[13] << 14 | t[14] << 6 | t[15] >>> 2, + e.words[6] = (63 & t[9]) << 20 | t[10] << 12 | t[11] << 4 | t[12] >>> 4, e.words[7] = (255 & t[6]) << 18 | t[7] << 10 | t[8] << 2 | t[9] >>> 6, + e.words[8] = (3 & t[2]) << 24 | t[3] << 16 | t[4] << 8 | t[5], e.words[9] = t[0] << 14 | t[1] << 6 | t[2] >>> 2, e.length = 10, + e.strip(); + }, l.prototype.toBuffer = function () + { + for(var t = this.words, e = this.length; e < 10; ++e) + t[e] = 0; + return i.from([t[9] >>> 14 & 255, t[9] >>> 6 & 255, (63 & t[9]) << 2 | t[8] >>> 24 & 3, t[8] >>> 16 & 255, t[8] >>> 8 & 255, + 255 & t[8], t[7] >>> 18 & 255, t[7] >>> 10 & 255, t[7] >>> 2 & 255, (3 & t[7]) << 6 | t[6] >>> 20 & 63, t[6] >>> 12 & 255, + t[6] >>> 4 & 255, (15 & t[6]) << 4 | t[5] >>> 22 & 15, t[5] >>> 14 & 255, t[5] >>> 6 & 255, (63 & t[5]) << 2 | t[4] >>> 24 & 3, + t[4] >>> 16 & 255, t[4] >>> 8 & 255, 255 & t[4], t[3] >>> 18 & 255, t[3] >>> 10 & 255, t[3] >>> 2 & 255, (3 & t[3]) << 6 | t[2] >>> 20 & 63, + t[2] >>> 12 & 255, t[2] >>> 4 & 255, (15 & t[2]) << 4 | t[1] >>> 22 & 15, t[1] >>> 14 & 255, t[1] >>> 6 & 255, (63 & t[1]) << 2 | t[0] >>> 24 & 3, + t[0] >>> 16 & 255, t[0] >>> 8 & 255, 255 & t[0]]); + }, l.prototype.clone = function () + { + var t = new l; + t.words = Array(this.length); + for(var e = 0; e < this.length; e++) + t.words[e] = this.words[e]; + return t.length = this.length, t.negative = this.negative, t; + }, l.prototype.strip = function () + { + for(; 1 < this.length && 0 == (0 | this.words[this.length - 1]); ) + this.length--; + return this; + }, l.prototype.normSign = function () + { + return 1 === this.length && 0 === this.words[0] && (this.negative = 0), this; + }, l.prototype.isEven = function () + { + return 0 == (1 & this.words[0]); + }, l.prototype.isOdd = function () + { + return 1 == (1 & this.words[0]); + }, l.prototype.isZero = function () + { + return 1 === this.length && 0 === this.words[0]; + }, l.prototype.ucmp = function (t) + { + if(this.length !== t.length) + return this.length > t.length ? 1 : - 1; + for(var e = this.length - 1; 0 <= e; --e) + if(this.words[e] !== t.words[e]) + return this.words[e] > t.words[e] ? 1 : - 1; + return 0; + }, l.prototype.gtOne = function () + { + return 1 < this.length || 1 < this.words[0]; + }, l.prototype.isOverflow = function () + { + return 0 <= this.ucmp(l.n); + }, l.prototype.isHigh = function () + { + return 1 === this.ucmp(l.nh); + }, l.prototype.bitLengthGT256 = function () + { + return 10 < this.length || 10 === this.length && 4194303 < this.words[9]; + }, l.prototype.iuaddn = function (t) + { + for(this.words[0] += t, t = 0; 67108863 < this.words[t] && t < this.length; ++t) + this.words[t] -= 67108864, this.words[t + 1] += 1; + return t === this.length && (this.words[t] = 1, this.length += 1), this; + }, l.prototype.iadd = function (t) + { + if(this.negative !== t.negative) + return 0 !== this.negative ? (this.negative = 0, this.isub(t), this.negative ^= 1) : (t.negative = 0, this.isub(t), t.negative = 1), + this.normSign(); + if(this.length > t.length) + var e = this; + else + e = t, t = this; + for(var r = 0, i = 0; r < t.length; ++r) + i = e.words[r] + t.words[r] + i, this.words[r] = 67108863 & i, i >>>= 26; + for(; 0 !== i && r < e.length; ++r) + i = e.words[r] + i, this.words[r] = 67108863 & i, i >>>= 26; + if(this.length = e.length, 0 !== i) + this.words[this.length++] = i; + else + if(e !== this) + for(; r < e.length; ++r) + this.words[r] = e.words[r]; + return this; + }, l.prototype.add = function (t) + { + return this.clone().iadd(t); + }, l.prototype.isub = function (t) + { + if(this.negative !== t.negative) + return 0 !== this.negative ? (this.negative = 0, this.iadd(t), this.negative = 1) : (t.negative = 0, this.iadd(t), t.negative = 1), + this.normSign(); + var e = this.ucmp(t); + if(0 === e) + return this.negative = 0, this.words[0] = 0, this.length = 1, this; + 0 < e ? e = this : (e = t, t = this); + for(var r = 0, i = 0; r < t.length; ++r) + { + var n = e.words[r] - t.words[r] + i; + i = n >> 26, this.words[r] = 67108863 & n; + } + for(; 0 !== i && r < e.length; ++r) + i = (n = e.words[r] + i) >> 26, this.words[r] = 67108863 & n; + if(0 === i && r < e.length && e !== this) + for(; r < e.length; ++r) + this.words[r] = e.words[r]; + return this.length = Math.max(this.length, r), e !== this && (this.negative ^= 1), this.strip().normSign(); + }, l.prototype.sub = function (t) + { + return this.clone().isub(t); + }, l.umulTo = function (t,e,r) + { + r.length = t.length + e.length - 1; + var i = t.words[0] * e.words[0], n = i / 67108864 | 0; + r.words[0] = 67108863 & i, i = 1; + for(var s = r.length; i < s; i++) + { + var o = n >>> 26, a = 67108863 & n; + n = Math.max(0, i - t.length + 1); + for(var h = Math.min(i, e.length - 1); n <= h; n++) + o += (a = t.words[i - n] * e.words[n] + a) / 67108864 | 0, a &= 67108863; + r.words[i] = a, n = o; + } + return 0 !== n && (r.words[r.length++] = n), r.strip(); + }, l.umulTo10x10 = Math.imul ? t.umulTo10x10 : l.umulTo, l.umulnTo = function (t,e,r) + { + if(0 === e) + return r.words = [0], r.length = 1, r; + for(var i = 0, n = 0; i < t.length; ++i) + n = t.words[i] * e + n, r.words[i] = 67108863 & n, n = n / 67108864 | 0; + return r.length = 0 < n ? (r.words[i] = n, t.length + 1) : t.length, r; + }, l.prototype.umul = function (t) + { + var e = new l; + return e.words = Array(this.length + t.length), 10 === this.length && 10 === t.length ? l.umulTo10x10(this, t, e) : 1 === this.length ? l.umulnTo(t, + this.words[0], e) : 1 === t.length ? l.umulnTo(this, t.words[0], e) : l.umulTo(this, t, e); + }, l.prototype.isplit = function (t) + { + t.length = Math.min(this.length, 9); + for(var e = 0; e < t.length; ++e) + t.words[e] = this.words[e]; + if(this.length <= 9) + return this.words[0] = 0, this.length = 1, this; + var r = this.words[9]; + for(t.words[t.length++] = 4194303 & r, e = 10; e < this.length; ++e) + t = this.words[e], this.words[e - 10] = (4194303 & t) << 4 | r >>> 22, r = t; + return r >>>= 22, this.words[e - 10] = r, this.length = 0 === r && 10 < this.length ? this.length - 10 : this.length - 9, this; + }, l.prototype.fireduce = function () + { + return this.isOverflow() && this.isub(l.n), this; + }, l.prototype.ureduce = function () + { + var t = this.clone().isplit(l.tmp).umul(l.nc).iadd(l.tmp); + return t.bitLengthGT256() && ((t = t.isplit(l.tmp).umul(l.nc).iadd(l.tmp)).bitLengthGT256() && (t = t.isplit(l.tmp).umul(l.nc).iadd(l.tmp))), + t.fireduce(); + }, l.prototype.ishrn = function (t) + { + for(var e = (1 << t) - 1, r = 26 - t, i = this.length - 1, n = 0; 0 <= i; --i) + { + var s = this.words[i]; + this.words[i] = n << r | s >>> t, n = s & e; + } + return 1 < this.length && 0 === this.words[this.length - 1] && --this.length, this; + }, l.prototype.uinvm = function () + { + for(var t = this.clone(), e = l.n.clone(), r = l.fromNumber(1), i = l.fromNumber(0), n = l.fromNumber(0), s = l.fromNumber(1); t.isEven() && e.isEven(); ) + { + for(var o = 1, a = 1; 0 == (t.words[0] & a) && 0 == (e.words[0] & a) && o < 26; ++o, a <<= 1); + t.ishrn(o), e.ishrn(o); + } + for(o = e.clone(), a = t.clone(); !t.isZero(); ) + { + for(var h = 0, u = 1; 0 == (t.words[0] & u) && h < 26; ++h, u <<= 1); + if(0 < h) + for(t.ishrn(h); 0 < h--; ) + (r.isOdd() || i.isOdd()) && (r.iadd(o), i.isub(a)), r.ishrn(1), i.ishrn(1); + for(h = 0, u = 1; 0 == (e.words[0] & u) && h < 26; ++h, u <<= 1); + if(0 < h) + for(e.ishrn(h); 0 < h--; ) + (n.isOdd() || s.isOdd()) && (n.iadd(o), s.isub(a)), n.ishrn(1), s.ishrn(1); + 0 <= t.ucmp(e) ? (t.isub(e), r.isub(n), i.isub(s)) : (e.isub(t), n.isub(r), s.isub(i)); + } + return 1 === n.negative ? (n.negative = 0, (t = n.ureduce()).negative ^= 1, t.normSign().iadd(l.n)) : n.ureduce(); + }, l.prototype.imulK = function () + { + this.words[this.length] = 0, this.words[this.length + 1] = 0, this.length += 2; + for(var t = 0, e = 0; t < this.length; ++t) + { + var r = 0 | this.words[t]; + e += 977 * r, this.words[t] = 67108863 & e, e = 64 * r + (e / 67108864 | 0); + } + return 0 === this.words[this.length - 1] && (--this.length, 0 === this.words[this.length - 1] && --this.length), this; + }, l.prototype.redIReduce = function () + { + this.isplit(l.tmp).imulK().iadd(l.tmp), this.bitLengthGT256() && this.isplit(l.tmp).imulK().iadd(l.tmp); + var t = this.ucmp(l.p); + return 0 === t ? (this.words[0] = 0, this.length = 1) : 0 < t ? this.isub(l.p) : this.strip(), this; + }, l.prototype.redNeg = function () + { + return this.isZero() ? l.fromNumber(0) : l.p.sub(this); + }, l.prototype.redAdd = function (t) + { + return this.clone().redIAdd(t); + }, l.prototype.redIAdd = function (t) + { + return this.iadd(t), 0 <= this.ucmp(l.p) && this.isub(l.p), this; + }, l.prototype.redIAdd7 = function () + { + return this.iuaddn(7), 0 <= this.ucmp(l.p) && this.isub(l.p), this; + }, l.prototype.redSub = function (t) + { + return this.clone().redISub(t); + }, l.prototype.redISub = function (t) + { + return this.isub(t), 0 !== this.negative && this.iadd(l.p), this; + }, l.prototype.redMul = function (t) + { + return this.umul(t).redIReduce(); + }, l.prototype.redSqr = function () + { + return this.umul(this).redIReduce(); + }, l.prototype.redSqrt = function () + { + if(this.isZero()) + return this.clone(); + for(var t = this.redSqr(), e = t.redSqr(), r = (t = (e = e.redSqr().redMul(e)).redMul(t)).redMul(this), i = r, n = 0; n < 54; ++n) + i = i.redSqr().redSqr().redSqr().redSqr().redMul(r); + for(i = i.redSqr().redSqr().redSqr().redSqr().redMul(t), n = 0; n < 5; ++n) + i = i.redSqr().redSqr().redSqr().redSqr().redMul(r); + return 0 === (i = (i = i.redSqr().redSqr().redSqr().redSqr().redMul(e)).redSqr().redSqr().redSqr().redSqr().redSqr().redSqr().redMul(e)).redSqr().ucmp(this) ? i : null; + }, l.prototype.redInvm = function () + { + for(var t = this.clone(), e = l.p.clone(), r = l.fromNumber(1), i = l.fromNumber(0); t.gtOne() && e.gtOne(); ) + { + for(var n = 0, s = 1; 0 == (t.words[0] & s) && n < 26; ++n, s <<= 1); + if(0 < n) + for(t.ishrn(n); 0 < n--; ) + r.isOdd() && r.iadd(l.p), r.ishrn(1); + for(n = 0, s = 1; 0 == (e.words[0] & s) && n < 26; ++n, s <<= 1); + if(0 < n) + for(e.ishrn(n); 0 < n--; ) + i.isOdd() && i.iadd(l.p), i.ishrn(1); + 0 <= t.ucmp(e) ? (t.isub(e), r.isub(i)) : (e.isub(t), i.isub(r)); + } + return 0 !== (t = 1 === t.length && 1 === t.words[0] ? r : i).negative && t.iadd(l.p), 0 !== t.negative ? (t.negative = 0, + t.redIReduce().redNeg()) : t.redIReduce(); + }, l.prototype.getNAF = function (t) + { + var e = [], r = 1 << t + 1, i = r - 1; + r >>= 1; + for(var n = this.clone(); !n.isZero(); ) + { + for(var s = 0, o = 1; 0 == (n.words[0] & o) && s < 26; ++s, o <<= 1) + e.push(0); + if(0 !== s) + n.ishrn(s); + else + if(r <= (s = n.words[0] & i)) + e.push(r - s), n.iuaddn(s - r).ishrn(1); + else + if(e.push(s), n.words[0] -= s, !n.isZero()) + { + for(s = t - 1; 0 < s; --s) + e.push(0); + n.ishrn(t); + } + } + return e; + }, l.prototype.inspect = function () + { + if(this.isZero()) + return "0"; + for(var t = this.toBuffer().toString("hex"), e = 0; "0" === t[e]; ++e); + return t.slice(e); + }, l.n = l.fromBuffer(i.from("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", "hex")), l.nh = l.n.clone().ishrn(1), + l.nc = l.fromBuffer(i.from("000000000000000000000000000000014551231950B75FC4402DA1732FC9BEBF", "hex")), l.p = l.fromBuffer(i.from("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", + "hex")), l.psn = l.p.sub(l.n), (l.tmp = new l).words = Array(10), l.fromNumber(1).words[3] = 0, e.exports = l; + }, {"./optimized":44, "safe-buffer":42}], 44:[function (t,e,r) + { + r.umulTo10x10 = function (t,e,r) + { + var i = t.words, n = e.words; + e = r.words; + var s = (t = 0) | i[0], o = 8191 & s, a = s >>> 13, h = 0 | i[1]; + s = 8191 & h; + var u = h >>> 13, l = 0 | i[2]; + h = 8191 & l; + var f = l >>> 13, c = 0 | i[3]; + l = 8191 & c; + var d = c >>> 13, p = 0 | i[4]; + c = 8191 & p; + var m = p >>> 13, _ = 0 | i[5]; + p = 8191 & _; + var g = _ >>> 13, b = 0 | i[6]; + _ = 8191 & b; + var y = b >>> 13, w = 0 | i[7]; + b = 8191 & w; + var v = w >>> 13, M = 0 | i[8]; + w = 8191 & M, M >>>= 13; + var E = 0 | i[9]; + i = 8191 & E, E >>>= 13; + var S = 0 | n[0], I = 8191 & S, A = S >>> 13, B = 0 | n[1]; + S = 8191 & B; + var x = B >>> 13, L = 0 | n[2]; + B = 8191 & L; + var k = L >>> 13, T = 0 | n[3]; + L = 8191 & T; + var C = T >>> 13, F = 0 | n[4]; + T = 8191 & F; + var j = F >>> 13, O = 0 | n[5]; + F = 8191 & O; + var R = O >>> 13, N = 0 | n[6]; + O = 8191 & N; + var P = N >>> 13, U = 0 | n[7]; + N = 8191 & U; + var D = U >>> 13, q = 0 | n[8]; + U = 8191 & q; + var K = q >>> 13, V = 8191 & (n = 0 | n[9]), Y = n >>> 13; + r.length = 19; + var z = Math.imul(o, I); + n = Math.imul(o, A); + var $ = t + z + ((8191 & (n += Math.imul(a, I))) << 13); + t = (q = Math.imul(a, A)) + (n >>> 13) + ($ >>> 26), $ &= 67108863, z = Math.imul(s, I), n = Math.imul(s, A), n += Math.imul(u, + I), q = Math.imul(u, A), z += Math.imul(o, S), n += Math.imul(o, x); + var W = t + z + ((8191 & (n += Math.imul(a, S))) << 13); + t = (q += Math.imul(a, x)) + (n >>> 13) + (W >>> 26), W &= 67108863, z = Math.imul(h, I), n = Math.imul(h, A), n += Math.imul(f, + I), q = Math.imul(f, A), z += Math.imul(s, S), n += Math.imul(s, x), n += Math.imul(u, S), q += Math.imul(u, x), z += Math.imul(o, + B), n += Math.imul(o, k); + var Z = t + z + ((8191 & (n += Math.imul(a, B))) << 13); + t = (q += Math.imul(a, k)) + (n >>> 13) + (Z >>> 26), Z &= 67108863, z = Math.imul(l, I), n = Math.imul(l, A), n += Math.imul(d, + I), q = Math.imul(d, A), z += Math.imul(h, S), n += Math.imul(h, x), n += Math.imul(f, S), q += Math.imul(f, x), z += Math.imul(s, + B), n += Math.imul(s, k), n += Math.imul(u, B), q += Math.imul(u, k), z += Math.imul(o, L), n += Math.imul(o, C); + var G = t + z + ((8191 & (n += Math.imul(a, L))) << 13); + t = (q += Math.imul(a, C)) + (n >>> 13) + (G >>> 26), G &= 67108863, z = Math.imul(c, I), n = Math.imul(c, A), n += Math.imul(m, + I), q = Math.imul(m, A), z += Math.imul(l, S), n += Math.imul(l, x), n += Math.imul(d, S), q += Math.imul(d, x), z += Math.imul(h, + B), n += Math.imul(h, k), n += Math.imul(f, B), q += Math.imul(f, k), z += Math.imul(s, L), n += Math.imul(s, C), n += Math.imul(u, + L), q += Math.imul(u, C), z += Math.imul(o, T), n += Math.imul(o, j); + var H = t + z + ((8191 & (n += Math.imul(a, T))) << 13); + t = (q += Math.imul(a, j)) + (n >>> 13) + (H >>> 26), H &= 67108863, z = Math.imul(p, I), n = Math.imul(p, A), n += Math.imul(g, + I), q = Math.imul(g, A), z += Math.imul(c, S), n += Math.imul(c, x), n += Math.imul(m, S), q += Math.imul(m, x), z += Math.imul(l, + B), n += Math.imul(l, k), n += Math.imul(d, B), q += Math.imul(d, k), z += Math.imul(h, L), n += Math.imul(h, C), n += Math.imul(f, + L), q += Math.imul(f, C), z += Math.imul(s, T), n += Math.imul(s, j), n += Math.imul(u, T), q += Math.imul(u, j), z += Math.imul(o, + F), n += Math.imul(o, R); + var J = t + z + ((8191 & (n += Math.imul(a, F))) << 13); + t = (q += Math.imul(a, R)) + (n >>> 13) + (J >>> 26), J &= 67108863, z = Math.imul(_, I), n = Math.imul(_, A), n += Math.imul(y, + I), q = Math.imul(y, A), z += Math.imul(p, S), n += Math.imul(p, x), n += Math.imul(g, S), q += Math.imul(g, x), z += Math.imul(c, + B), n += Math.imul(c, k), n += Math.imul(m, B), q += Math.imul(m, k), z += Math.imul(l, L), n += Math.imul(l, C), n += Math.imul(d, + L), q += Math.imul(d, C), z += Math.imul(h, T), n += Math.imul(h, j), n += Math.imul(f, T), q += Math.imul(f, j), z += Math.imul(s, + F), n += Math.imul(s, R), n += Math.imul(u, F), q += Math.imul(u, R), z += Math.imul(o, O), n += Math.imul(o, P); + var X = t + z + ((8191 & (n += Math.imul(a, O))) << 13); + t = (q += Math.imul(a, P)) + (n >>> 13) + (X >>> 26), X &= 67108863, z = Math.imul(b, I), n = Math.imul(b, A), n += Math.imul(v, + I), q = Math.imul(v, A), z += Math.imul(_, S), n += Math.imul(_, x), n += Math.imul(y, S), q += Math.imul(y, x), z += Math.imul(p, + B), n += Math.imul(p, k), n += Math.imul(g, B), q += Math.imul(g, k), z += Math.imul(c, L), n += Math.imul(c, C), n += Math.imul(m, + L), q += Math.imul(m, C), z += Math.imul(l, T), n += Math.imul(l, j), n += Math.imul(d, T), q += Math.imul(d, j), z += Math.imul(h, + F), n += Math.imul(h, R), n += Math.imul(f, F), q += Math.imul(f, R), z += Math.imul(s, O), n += Math.imul(s, P), n += Math.imul(u, + O), q += Math.imul(u, P), z += Math.imul(o, N), n += Math.imul(o, D); + var Q = t + z + ((8191 & (n += Math.imul(a, N))) << 13); + t = (q += Math.imul(a, D)) + (n >>> 13) + (Q >>> 26), Q &= 67108863, z = Math.imul(w, I), n = Math.imul(w, A), n += Math.imul(M, + I), q = Math.imul(M, A), z += Math.imul(b, S), n += Math.imul(b, x), n += Math.imul(v, S), q += Math.imul(v, x), z += Math.imul(_, + B), n += Math.imul(_, k), n += Math.imul(y, B), q += Math.imul(y, k), z += Math.imul(p, L), n += Math.imul(p, C), n += Math.imul(g, + L), q += Math.imul(g, C), z += Math.imul(c, T), n += Math.imul(c, j), n += Math.imul(m, T), q += Math.imul(m, j), z += Math.imul(l, + F), n += Math.imul(l, R), n += Math.imul(d, F), q += Math.imul(d, R), z += Math.imul(h, O), n += Math.imul(h, P), n += Math.imul(f, + O), q += Math.imul(f, P), z += Math.imul(s, N), n += Math.imul(s, D), n += Math.imul(u, N), q += Math.imul(u, D), z += Math.imul(o, + U), n += Math.imul(o, K); + var tt = t + z + ((8191 & (n += Math.imul(a, U))) << 13); + return t = (q += Math.imul(a, K)) + (n >>> 13) + (tt >>> 26), tt &= 67108863, z = Math.imul(i, I), n = Math.imul(i, A), n += Math.imul(E, + I), q = Math.imul(E, A), z += Math.imul(w, S), n += Math.imul(w, x), n += Math.imul(M, S), q += Math.imul(M, x), z += Math.imul(b, + B), n += Math.imul(b, k), n += Math.imul(v, B), q += Math.imul(v, k), z += Math.imul(_, L), n += Math.imul(_, C), n += Math.imul(y, + L), q += Math.imul(y, C), z += Math.imul(p, T), n += Math.imul(p, j), n += Math.imul(g, T), q += Math.imul(g, j), z += Math.imul(c, + F), n += Math.imul(c, R), n += Math.imul(m, F), q += Math.imul(m, R), z += Math.imul(l, O), n += Math.imul(l, P), n += Math.imul(d, + O), q += Math.imul(d, P), z += Math.imul(h, N), n += Math.imul(h, D), n += Math.imul(f, N), q += Math.imul(f, D), z += Math.imul(s, + U), n += Math.imul(s, K), n += Math.imul(u, U), q += Math.imul(u, K), z += Math.imul(o, V), n += Math.imul(o, Y), n += Math.imul(a, + V), t = (q += Math.imul(a, Y)) + (n >>> 13) + ((o = t + z + ((8191 & n) << 13)) >>> 26), o &= 67108863, z = Math.imul(i, S), + n = Math.imul(i, x), n += Math.imul(E, S), q = Math.imul(E, x), z += Math.imul(w, B), n += Math.imul(w, k), n += Math.imul(M, + B), q += Math.imul(M, k), z += Math.imul(b, L), n += Math.imul(b, C), n += Math.imul(v, L), q += Math.imul(v, C), z += Math.imul(_, + T), n += Math.imul(_, j), n += Math.imul(y, T), q += Math.imul(y, j), z += Math.imul(p, F), n += Math.imul(p, R), n += Math.imul(g, + F), q += Math.imul(g, R), z += Math.imul(c, O), n += Math.imul(c, P), n += Math.imul(m, O), q += Math.imul(m, P), z += Math.imul(l, + N), n += Math.imul(l, D), n += Math.imul(d, N), q += Math.imul(d, D), z += Math.imul(h, U), n += Math.imul(h, K), n += Math.imul(f, + U), q += Math.imul(f, K), z += Math.imul(s, V), n += Math.imul(s, Y), n += Math.imul(u, V), t = (q += Math.imul(u, Y)) + (n >>> 13) + ((s = t + z + ((8191 & n) << 13)) >>> 26), + s &= 67108863, z = Math.imul(i, B), n = Math.imul(i, k), n += Math.imul(E, B), q = Math.imul(E, k), z += Math.imul(w, L), n += Math.imul(w, + C), n += Math.imul(M, L), q += Math.imul(M, C), z += Math.imul(b, T), n += Math.imul(b, j), n += Math.imul(v, T), q += Math.imul(v, + j), z += Math.imul(_, F), n += Math.imul(_, R), n += Math.imul(y, F), q += Math.imul(y, R), z += Math.imul(p, O), n += Math.imul(p, + P), n += Math.imul(g, O), q += Math.imul(g, P), z += Math.imul(c, N), n += Math.imul(c, D), n += Math.imul(m, N), q += Math.imul(m, + D), z += Math.imul(l, U), n += Math.imul(l, K), n += Math.imul(d, U), q += Math.imul(d, K), z += Math.imul(h, V), n += Math.imul(h, + Y), n += Math.imul(f, V), t = (q += Math.imul(f, Y)) + (n >>> 13) + ((h = t + z + ((8191 & n) << 13)) >>> 26), h &= 67108863, + z = Math.imul(i, L), n = Math.imul(i, C), n += Math.imul(E, L), q = Math.imul(E, C), z += Math.imul(w, T), n += Math.imul(w, + j), n += Math.imul(M, T), q += Math.imul(M, j), z += Math.imul(b, F), n += Math.imul(b, R), n += Math.imul(v, F), q += Math.imul(v, + R), z += Math.imul(_, O), n += Math.imul(_, P), n += Math.imul(y, O), q += Math.imul(y, P), z += Math.imul(p, N), n += Math.imul(p, + D), n += Math.imul(g, N), q += Math.imul(g, D), z += Math.imul(c, U), n += Math.imul(c, K), n += Math.imul(m, U), q += Math.imul(m, + K), z += Math.imul(l, V), n += Math.imul(l, Y), n += Math.imul(d, V), t = (q += Math.imul(d, Y)) + (n >>> 13) + ((l = t + z + ((8191 & n) << 13)) >>> 26), + l &= 67108863, z = Math.imul(i, T), n = Math.imul(i, j), n += Math.imul(E, T), q = Math.imul(E, j), z += Math.imul(w, F), n += Math.imul(w, + R), n += Math.imul(M, F), q += Math.imul(M, R), z += Math.imul(b, O), n += Math.imul(b, P), n += Math.imul(v, O), q += Math.imul(v, + P), z += Math.imul(_, N), n += Math.imul(_, D), n += Math.imul(y, N), q += Math.imul(y, D), z += Math.imul(p, U), n += Math.imul(p, + K), n += Math.imul(g, U), q += Math.imul(g, K), z += Math.imul(c, V), n += Math.imul(c, Y), n += Math.imul(m, V), t = (q += Math.imul(m, + Y)) + (n >>> 13) + ((c = t + z + ((8191 & n) << 13)) >>> 26), c &= 67108863, z = Math.imul(i, F), n = Math.imul(i, R), n += Math.imul(E, + F), q = Math.imul(E, R), z += Math.imul(w, O), n += Math.imul(w, P), n += Math.imul(M, O), q += Math.imul(M, P), z += Math.imul(b, + N), n += Math.imul(b, D), n += Math.imul(v, N), q += Math.imul(v, D), z += Math.imul(_, U), n += Math.imul(_, K), n += Math.imul(y, + U), q += Math.imul(y, K), z += Math.imul(p, V), n += Math.imul(p, Y), n += Math.imul(g, V), t = (q += Math.imul(g, Y)) + (n >>> 13) + ((p = t + z + ((8191 & n) << 13)) >>> 26), + p &= 67108863, z = Math.imul(i, O), n = Math.imul(i, P), n += Math.imul(E, O), q = Math.imul(E, P), z += Math.imul(w, N), n += Math.imul(w, + D), n += Math.imul(M, N), q += Math.imul(M, D), z += Math.imul(b, U), n += Math.imul(b, K), n += Math.imul(v, U), q += Math.imul(v, + K), z += Math.imul(_, V), n += Math.imul(_, Y), n += Math.imul(y, V), t = (q += Math.imul(y, Y)) + (n >>> 13) + ((_ = t + z + ((8191 & n) << 13)) >>> 26), + _ &= 67108863, z = Math.imul(i, N), n = Math.imul(i, D), n += Math.imul(E, N), q = Math.imul(E, D), z += Math.imul(w, U), n += Math.imul(w, + K), n += Math.imul(M, U), q += Math.imul(M, K), z += Math.imul(b, V), n += Math.imul(b, Y), n += Math.imul(v, V), t = (q += Math.imul(v, + Y)) + (n >>> 13) + ((b = t + z + ((8191 & n) << 13)) >>> 26), b &= 67108863, z = Math.imul(i, U), n = Math.imul(i, K), n += Math.imul(E, + U), q = Math.imul(E, K), z += Math.imul(w, V), n += Math.imul(w, Y), n += Math.imul(M, V), t = (q += Math.imul(M, Y)) + (n >>> 13) + ((w = t + z + ((8191 & n) << 13)) >>> 26), + w &= 67108863, z = Math.imul(i, V), n = Math.imul(i, Y), n += Math.imul(E, V), t = (q = Math.imul(E, Y)) + (n >>> 13) + ((a = t + z + ((8191 & n) << 13)) >>> 26), + e[0] = $, e[1] = W, e[2] = Z, e[3] = G, e[4] = H, e[5] = J, e[6] = X, e[7] = Q, e[8] = tt, e[9] = o, e[10] = s, e[11] = h, + e[12] = l, e[13] = c, e[14] = p, e[15] = _, e[16] = b, e[17] = w, e[18] = 67108863 & a, 0 !== t && (e[19] = t, r.length++), + r; + }; + }, {}], 45:[function (t,e,r) + { + +function a(t,e,r) + { + this.z = null === t && null === e && null === r ? (this.y = this.x = a.one, a.zero) : (this.x = t, this.y = e, r), this.zOne = this.z === a.one; + }; + t = t("./bn"), a.zero = t.fromNumber(0), a.one = t.fromNumber(1), a.prototype.neg = function () + { + return this.inf ? this : new a(this.x, this.y.redNeg(), this.z); + }, a.prototype.add = function (t) + { + if(this.inf) + return t; + if(t.inf) + return this; + var e = t.z.redSqr(), r = this.z.redSqr(), i = this.x.redMul(e), n = t.x.redMul(r); + if(e = this.y.redMul(e).redMul(t.z), r = t.y.redMul(r).redMul(this.z), n = i.redSub(n), r = e.redSub(r), n.isZero()) + return r.isZero() ? this.dbl() : new a(null, null, null); + var s = n.redSqr(), o = i.redMul(s); + return s = s.redMul(n), new a(i = r.redSqr().redIAdd(s).redISub(o).redISub(o), e = r.redMul(o.redISub(i)).redISub(e.redMul(s)), + t = this.z.redMul(t.z).redMul(n)); + }, a.prototype.mixedAdd = function (t) + { + if(this.inf) + return t.toECJPoint(); + if(t.inf) + return this; + var e = this.z.redSqr(), r = this.x, i = t.x.redMul(e), n = this.y; + if(t = t.y.redMul(e).redMul(this.z), i = r.redSub(i), t = n.redSub(t), i.isZero()) + return t.isZero() ? this.dbl() : new a(null, null, null); + var s = i.redSqr(); + return e = r.redMul(s), s = s.redMul(i), new a(r = t.redSqr().redIAdd(s).redISub(e).redISub(e), n = t.redMul(e.redISub(r)).redISub(n.redMul(s)), + i = this.z.redMul(i)); + }, a.prototype.dbl = function () + { + if(this.inf) + return this; + if(this.zOne) + { + var t = this.x.redSqr(), e = this.y.redSqr(), r = e.redSqr(); + e = (e = this.x.redAdd(e).redSqr().redISub(t).redISub(r)).redIAdd(e); + var i = (t = t.redAdd(t).redIAdd(t)).redSqr().redISub(e).redISub(e), n = r.redIAdd(r).redIAdd(r).redIAdd(r); + r = i, e = t.redMul(e.redISub(i)).redISub(n), t = this.y.redAdd(this.y); + } + else + t = this.x.redSqr(), r = (e = this.y.redSqr()).redSqr(), e = (e = this.x.redAdd(e).redSqr().redISub(t).redISub(r)).redIAdd(e), + i = (t = t.redAdd(t).redIAdd(t)).redSqr(), n = r.redIAdd(r).redIAdd(r).redIAdd(r), r = i.redISub(e).redISub(e), e = t.redMul(e.redISub(r)).redISub(n), + t = (t = this.y.redMul(this.z)).redIAdd(t); + return new a(r, e, t); + }, a.prototype.dblp = function (t) + { + if(0 === t || this.inf) + return this; + for(var e = this, r = 0; r < t; r++) + e = e.dbl(); + return e; + }, Object.defineProperty(a.prototype, "inf", {enumerable:!0, get:function () + { + return this.z.isZero(); + }}), e.exports = a; + }, {"./bn":43}], 46:[function (t,e,r) + { + +function s(t,e) + { + this.inf = null === t && null === e ? (this.x = this.y = null, !0) : (this.x = t, this.y = e, !1); + }; + var i = t("safe-buffer").Buffer, n = t("./bn"), o = t("./ecjpoint"); + s.fromPublicKey = function (t) + { + var e = t[0]; + if(33 !== t.length || 2 !== e && 3 !== e) + return 65 !== t.length || 4 !== e && 6 !== e && 7 !== e ? null : (r = n.fromBuffer(t.slice(1, 33)), t = n.fromBuffer(t.slice(33, + 65)), 0 <= r.ucmp(n.p) || 0 <= t.ucmp(n.p) || (6 === e || 7 === e) && t.isOdd() !== (7 === e) || 0 !== r.redSqr().redMul(r).redIAdd7().ucmp(t.redSqr()) ? null : new s(r, + t)); + var r = n.fromBuffer(t.slice(1, 33)); + return 0 <= r.ucmp(n.p) ? null : null === (t = r.redSqr().redMul(r).redIAdd7().redSqrt()) ? null : (3 === e !== t.isOdd() && (t = t.redNeg()), + new s(r, t)); + }, s.prototype.toPublicKey = function (t) + { + var e = this.x, r = this.y; + return t ? ((t = i.alloc(33))[0] = r.isOdd() ? 3 : 2, e.toBuffer().copy(t, 1)) : ((t = i.alloc(65))[0] = 4, e.toBuffer().copy(t, + 1), r.toBuffer().copy(t, 33)), t; + }, s.fromECJPoint = function (t) + { + if(t.inf) + return new s(null, null); + var e = t.z.redInvm(), r = e.redSqr(); + return new s(t.x.redMul(r), t = t.y.redMul(r).redMul(e)); + }, s.prototype.toECJPoint = function () + { + return this.inf ? new o(null, null, null) : new o(this.x, this.y, o.one); + }, s.prototype.neg = function () + { + return this.inf ? this : new s(this.x, this.y.redNeg()); + }, s.prototype.add = function (t) + { + if(this.inf) + return t; + if(t.inf) + return this; + if(0 === this.x.ucmp(t.x)) + return 0 === this.y.ucmp(t.y) ? this.dbl() : new s(null, null); + var e = this.y.redSub(t.y); + return e.isZero() || (e = e.redMul(this.x.redSub(t.x).redInvm())), new s(t = e.redSqr().redISub(this.x).redISub(t.x), e = e.redMul(this.x.redSub(t)).redISub(this.y)); + }, s.prototype.dbl = function () + { + if(this.inf) + return this; + var t = this.y.redAdd(this.y); + if(t.isZero()) + return new s(null, null); + var e = this.x.redSqr(); + return new s(t = (e = e.redAdd(e).redIAdd(e).redMul(t.redInvm())).redSqr().redISub(this.x.redAdd(this.x)), e = e.redMul(this.x.redSub(t)).redISub(this.y)); + }, s.prototype.mul = function (t) + { + var e = this._getNAFPoints(4), r = e.points; + t = t.getNAF(e.wnd), e = new o(null, null, null); + for(var i = t.length - 1; 0 <= i; i--) + { + for(var n = 0; 0 <= i && 0 === t[i]; i--, ++n); + if(0 <= i && (n += 1), e = e.dblp(n), i < 0) + break; + e = 0 < (n = t[i]) ? e.mixedAdd(r[n - 1 >> 1]) : e.mixedAdd(r[ - n - 1 >> 1].neg()); + } + return s.fromECJPoint(e); + }, s.prototype._getNAFPoints1 = function () + { + return {wnd:1, points:[this]}; + }, s.prototype._getNAFPoints = function (t) + { + for(var e = Array((1 << t) - 1), r = (e[0] = this).dbl(), i = 1; i < e.length; ++i) + e[i] = e[i - 1].add(r); + return {wnd:t, points:e}; + }, e.exports = s; + }, {"./bn":43, "./ecjpoint":45, "safe-buffer":42}], 47:[function (t,e,r) + { + +function i() + { + this.x = s.fromBuffer(n.from("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", "hex")), this.y = s.fromBuffer(n.from("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", + "hex")), this.inf = !1, this._precompute(); + }; + var n = t("safe-buffer").Buffer, s = t("./bn"), u = t("./ecpoint"), l = t("./ecjpoint"); + i.prototype._precompute = function () + { + for(var t = new u(this.x, this.y), e = Array(66), r = e[0] = t, i = 1; i < e.length; ++i) + { + for(var n = 0; n < 4; n++) + r = r.dbl(); + e[i] = r; + } + this.precomputed = {naf:t._getNAFPoints(7), doubles:{step:4, points:e, negpoints:e.map(function (t) + { + return t.neg(); + })}}; + }, i.prototype.mul = function (t) + { + var e = this.precomputed.doubles.step, r = this.precomputed.doubles.points, i = this.precomputed.doubles.negpoints, n = t.getNAF(1), + s = ((1 << e + 1) - (0 == e % 2 ? 2 : 1)) / 3; + t = []; + for(var o = 0; o < n.length; o += e) + { + for(var a = 0, h = o + e - 1; o <= h; h--) + a = (a << 1) + n[h]; + t.push(a); + } + for(e = new l(null, null, null), n = new l(null, null, null); 0 < s; s--) + { + for(o = 0; o < t.length; o++) + t[o] === s ? n = n.mixedAdd(r[o]) : t[o] === - s && (n = n.mixedAdd(i[o])); + e = e.add(n); + } + return u.fromECJPoint(e); + }, i.prototype.mulAdd = function (t,e,r) + { + var i = this.precomputed.naf, n = e._getNAFPoints1(); + for(e = [i.points, n.points], t = [t.getNAF(i.wnd), r.getNAF(n.wnd)], r = new l(null, null, null), i = [null, null], n = Math.max(t[0].length, + t[1].length); 0 <= n; n--) + { + for(var s = 0; 0 <= n && (i[0] = 0 | t[0][n], i[1] = 0 | t[1][n], 0 === i[0] && 0 === i[1]); ++s, --n); + if(0 <= n && (s += 1), r = r.dblp(s), n < 0) + break; + for(s = 0; s < 2; s++) + { + var o, a = i[s]; + 0 !== a && (0 < a ? o = e[s][a >> 1] : a < 0 && (o = e[s][ - a >> 1].neg()), r = void 0 === o.z ? r.mixedAdd(o) : r.add(o)); + } + } + return r; + }, e.exports = new i; + }, {"./bn":43, "./ecjpoint":45, "./ecpoint":46, "safe-buffer":42}], 48:[function (t,e,i) + { + var f = t("safe-buffer").Buffer, n = t("create-hash"), c = t("drbg.js/hmac"), d = t("../messages.json"), p = t("./bn"), o = t("./ecpoint"), + m = t("./ecpointg"); + i.privateKeyVerify = function (t) + { + return !((t = p.fromBuffer(t)).isOverflow() || t.isZero()); + }, i.privateKeyExport = function (t,e) + { + var r = p.fromBuffer(t); + if(r.isOverflow() || r.isZero()) + throw Error(d.EC_PRIVATE_KEY_EXPORT_DER_FAIL); + return m.mul(r).toPublicKey(e); + }, i.privateKeyNegate = function (t) + { + return (t = p.fromBuffer(t)).isZero() ? f.alloc(32) : (0 < t.ucmp(p.n) && t.isub(p.n), p.n.sub(t).toBuffer()); + }, i.privateKeyModInverse = function (t) + { + if((t = p.fromBuffer(t)).isOverflow() || t.isZero()) + throw Error(d.EC_PRIVATE_KEY_RANGE_INVALID); + return t.uinvm().toBuffer(); + }, i.privateKeyTweakAdd = function (t,e) + { + var r = p.fromBuffer(e); + if(r.isOverflow()) + throw Error(d.EC_PRIVATE_KEY_TWEAK_ADD_FAIL); + if(r.iadd(p.fromBuffer(t)), r.isOverflow() && r.isub(p.n), r.isZero()) + throw Error(d.EC_PRIVATE_KEY_TWEAK_ADD_FAIL); + return r.toBuffer(); + }, i.privateKeyTweakMul = function (t,e) + { + var r = p.fromBuffer(e); + if(r.isOverflow() || r.isZero()) + throw Error(d.EC_PRIVATE_KEY_TWEAK_MUL_FAIL); + var i = p.fromBuffer(t); + return r.umul(i).ureduce().toBuffer(); + }, i.publicKeyCreate = function (t,e) + { + var r = p.fromBuffer(t); + if(r.isOverflow() || r.isZero()) + throw Error(d.EC_PUBLIC_KEY_CREATE_FAIL); + return m.mul(r).toPublicKey(e); + }, i.publicKeyConvert = function (t,e) + { + var r = o.fromPublicKey(t); + if(null === r) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + return r.toPublicKey(e); + }, i.publicKeyVerify = function (t) + { + return null !== o.fromPublicKey(t); + }, i.publicKeyTweakAdd = function (t,e,r) + { + if(null === (t = o.fromPublicKey(t))) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + if((e = p.fromBuffer(e)).isOverflow()) + throw Error(d.EC_PUBLIC_KEY_TWEAK_ADD_FAIL); + return m.mul(e).add(t).toPublicKey(r); + }, i.publicKeyTweakMul = function (t,e,r) + { + if(null === (t = o.fromPublicKey(t))) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + if((e = p.fromBuffer(e)).isOverflow() || e.isZero()) + throw Error(d.EC_PUBLIC_KEY_TWEAK_MUL_FAIL); + return t.mul(e).toPublicKey(r); + }, i.publicKeyCombine = function (t,e) + { + for(var r = Array(t.length), i = 0; i < t.length; ++i) + if(r[i] = o.fromPublicKey(t[i]), null === r[i]) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + i = r[0]; + for(var n = 1; n < r.length; ++n) + i = i.add(r[n]); + if(i.inf) + throw Error(d.EC_PUBLIC_KEY_COMBINE_FAIL); + return i.toPublicKey(e); + }, i.signatureNormalize = function (t) + { + var e = p.fromBuffer(t.slice(0, 32)), r = p.fromBuffer(t.slice(32, 64)); + if(e.isOverflow() || r.isOverflow()) + throw Error(d.ECDSA_SIGNATURE_PARSE_FAIL); + return t = f.from(t), r.isHigh() && p.n.sub(r).toBuffer().copy(t, 32), t; + }, i.signatureExport = function (t) + { + var e = t.slice(0, 32); + if(t = t.slice(32, 64), p.fromBuffer(e).isOverflow() || p.fromBuffer(t).isOverflow()) + throw Error(d.ECDSA_SIGNATURE_PARSE_FAIL); + return {r:e, s:t}; + }, i.signatureImport = function (t) + { + var e = p.fromBuffer(t.r); + return e.isOverflow() && (e = p.fromNumber(0)), (t = p.fromBuffer(t.s)).isOverflow() && (t = p.fromNumber(0)), f.concat([e.toBuffer(), + t.toBuffer()]); + }, i.sign = function (t,e,r,i) + { + var n = p.fromBuffer(e); + if(n.isOverflow() || n.isZero()) + throw Error(d.ECDSA_SIGN_FAIL); + if(null === r) + { + var s = new c("sha256", e, t, i); + r = function () + { + return s.generate(32); + }; + } + for(var o = p.fromBuffer(t), a = 0; ; ++a) + { + var h = r(t, e, null, i, a); + if(!f.isBuffer(h) || 32 !== h.length) + throw Error(d.ECDSA_SIGN_FAIL); + var u = p.fromBuffer(h); + if(!u.isOverflow() && !u.isZero()) + { + var l = m.mul(u); + if(!(h = l.x.fireduce()).isZero() && !(u = u.uinvm().umul(h.umul(n).ureduce().iadd(o).fireduce()).ureduce()).isZero()) + return t = (0 !== l.x.ucmp(h) ? 2 : 0) | (l.y.isOdd() ? 1 : 0), u.isHigh() && (u = p.n.sub(u), t ^= 1), {signature:f.concat([h.toBuffer(), + u.toBuffer()]), recovery:t}; + } + } + }, i.verify = function (t,e,r) + { + var i = p.fromBuffer(e.slice(0, 32)); + if(e = p.fromBuffer(e.slice(32, 64)), i.isOverflow() || e.isOverflow()) + throw Error(d.ECDSA_SIGNATURE_PARSE_FAIL); + if(e.isHigh() || i.isZero() || e.isZero()) + return !1; + if(null === (r = o.fromPublicKey(r))) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + return t = (e = e.uinvm()).umul(p.fromBuffer(t)).ureduce(), e = e.umul(i).ureduce(), !(t = m.mulAdd(t, r, e)).inf && (r = t.z.redSqr(), + 0 === i.redMul(r).ucmp(t.x) || !(0 <= i.ucmp(p.psn)) && 0 === i.iadd(p.psn).redMul(r).ucmp(t.x)); + }, i.recover = function (t,e,r,i) + { + var n = p.fromBuffer(e.slice(0, 32)); + if(e = p.fromBuffer(e.slice(32, 64)), n.isOverflow() || e.isOverflow()) + throw Error(d.ECDSA_SIGNATURE_PARSE_FAIL); + do + { + if(!n.isZero() && !e.isZero()) + { + var s = n; + if(r >> 1) + { + if(0 <= s.ucmp(p.psn)) + break; + s = n.add(p.n); + } + if(s = f.concat([f.from([2 + (1 & r)]), s.toBuffer()]), null !== (s = o.fromPublicKey(s))) + return r = n.uinvm(), t = p.n.sub(p.fromBuffer(t)).umul(r).ureduce(), e = e.umul(r).ureduce(), o.fromECJPoint(m.mulAdd(t, s, + e)).toPublicKey(i); + } + } + while(0); + throw Error(d.ECDSA_RECOVER_FAIL); + }, i.ecdh = function (t,e) + { + var r = i.ecdhUnsafe(t, e, !0); + return n("sha256").update(r).digest(); + }, i.ecdhUnsafe = function (t,e,r) + { + if(null === (t = o.fromPublicKey(t))) + throw Error(d.EC_PUBLIC_KEY_PARSE_FAIL); + if((e = p.fromBuffer(e)).isOverflow() || e.isZero()) + throw Error(d.ECDH_FAIL); + return t.mul(e).toPublicKey(r); + }; + }, {"../messages.json":49, "./bn":43, "./ecpoint":46, "./ecpointg":47, "create-hash":32, "drbg.js/hmac":36, "safe-buffer":42}], + 49:[function (t,e,r) + { + e.exports = {COMPRESSED_TYPE_INVALID:"compressed should be a boolean", EC_PRIVATE_KEY_TYPE_INVALID:"private key should be a Buffer", + EC_PRIVATE_KEY_LENGTH_INVALID:"private key length is invalid", EC_PRIVATE_KEY_RANGE_INVALID:"private key range is invalid", + EC_PRIVATE_KEY_TWEAK_ADD_FAIL:"tweak out of range or resulting private key is invalid", EC_PRIVATE_KEY_TWEAK_MUL_FAIL:"tweak out of range", + EC_PRIVATE_KEY_EXPORT_DER_FAIL:"couldn't export to DER format", EC_PRIVATE_KEY_IMPORT_DER_FAIL:"couldn't import from DER format", + EC_PUBLIC_KEYS_TYPE_INVALID:"public keys should be an Array", EC_PUBLIC_KEYS_LENGTH_INVALID:"public keys Array should have at least 1 element", + EC_PUBLIC_KEY_TYPE_INVALID:"public key should be a Buffer", EC_PUBLIC_KEY_LENGTH_INVALID:"public key length is invalid", EC_PUBLIC_KEY_PARSE_FAIL:"the public key could not be parsed or is invalid", + EC_PUBLIC_KEY_CREATE_FAIL:"private was invalid, try again", EC_PUBLIC_KEY_TWEAK_ADD_FAIL:"tweak out of range or resulting public key is invalid", + EC_PUBLIC_KEY_TWEAK_MUL_FAIL:"tweak out of range", EC_PUBLIC_KEY_COMBINE_FAIL:"the sum of the public keys is not valid", ECDH_FAIL:"scalar was invalid (zero or overflow)", + ECDSA_SIGNATURE_TYPE_INVALID:"signature should be a Buffer", ECDSA_SIGNATURE_LENGTH_INVALID:"signature length is invalid", + ECDSA_SIGNATURE_PARSE_FAIL:"couldn't parse signature", ECDSA_SIGNATURE_PARSE_DER_FAIL:"couldn't parse DER signature", ECDSA_SIGNATURE_SERIALIZE_DER_FAIL:"couldn't serialize signature to DER format", + ECDSA_SIGN_FAIL:"nonce generation function failed or private key is invalid", ECDSA_RECOVER_FAIL:"couldn't recover public key from signature", + MSG32_TYPE_INVALID:"message should be a Buffer", MSG32_LENGTH_INVALID:"message length is invalid", OPTIONS_TYPE_INVALID:"options should be an Object", + OPTIONS_DATA_TYPE_INVALID:"options.data should be a Buffer", OPTIONS_DATA_LENGTH_INVALID:"options.data length is invalid", + OPTIONS_NONCEFN_TYPE_INVALID:"options.noncefn should be a Function", RECOVERY_ID_TYPE_INVALID:"recovery should be a Number", + RECOVERY_ID_VALUE_INVALID:"recovery should have value between -1 and 4", TWEAK_TYPE_INVALID:"tweak should be a Buffer", TWEAK_LENGTH_INVALID:"tweak length is invalid"}; + }, {}], 50:[function (t,e,r) + { + +function i(t,e) + { + this._block = l.alloc(t), this._finalSize = e, this._blockSize = t, this._len = 0; + }; + var l = t("safe-buffer").Buffer; + i.prototype.update = function (t,e) + { + "string" == typeof t && (t = l.from(t, e || "utf8")); + for(var r = this._block, i = this._blockSize, n = t.length, s = this._len, o = 0; o < n; ) + { + for(var a = s % i, h = Math.min(n - o, i - a), u = 0; u < h; u++) + r[a + u] = t[o + u]; + o += h, 0 == (s += h) % i && this._update(r); + } + return this._len += n, this; + }, i.prototype.digest = function (t) + { + var e = this._len % this._blockSize; + if(this._block[e] = 128, this._block.fill(0, e + 1), e >= this._finalSize && (this._update(this._block), this._block.fill(0)), + (e = 8 * this._len) <= 4294967295) + this._block.writeUInt32BE(e, this._blockSize - 4); + else + { + var r = (4294967295 & e) >>> 0; + this._block.writeUInt32BE((e - r) / 4294967296, this._blockSize - 8), this._block.writeUInt32BE(r, this._blockSize - 4); + } + return this._update(this._block), e = this._hash(), t ? e.toString(t) : e; + }, i.prototype._update = function () + { + throw Error("_update must be implemented by subclass"); + }, e.exports = i; + }, {"safe-buffer":42}], 51:[function (t,e,r) + { + (r = e.exports = function (t) + { + t = t.toLowerCase(); + var e = r[t]; + if(!e) + throw Error(t + " is not supported (we accept pull requests)"); + return new e; + }).sha = t("./sha"), r.sha1 = t("./sha1"), r.sha224 = t("./sha224"), r.sha256 = t("./sha256"), r.sha384 = t("./sha384"), r.sha512 = t("./sha512"); + }, {"./sha":52, "./sha1":53, "./sha224":54, "./sha256":55, "./sha384":56, "./sha512":57}], 52:[function (t,e,r) + { + +function i() + { + this.init(), this._w = o, n.call(this, 64, 56); + }; + r = t("inherits"); + var n = t("./hash"), s = t("safe-buffer").Buffer, h = [1518500249, 1859775393, - 1894007588, - 899497514], o = Array(80); + r(i, n), i.prototype.init = function () + { + return this._a = 1732584193, this._b = 4023233417, this._c = 2562383102, this._d = 271733878, this._e = 3285377520, this; + }, i.prototype._update = function (t) + { + for(var e = this._w, r = 0 | this._a, i = 0 | this._b, n = 0 | this._c, s = 0 | this._d, o = 0 | this._e, a = 0; a < 16; ++a) + e[a] = t.readInt32BE(4 * a); + for(; a < 80; ++a) + e[a] = e[a - 3] ^ e[a - 8] ^ e[a - 14] ^ e[a - 16]; + for(t = 0; t < 80; ++t) + { + a = (r << 5 | r >>> 27) + (0 === (a = ~~(t / 20)) ? i & n | ~i & s : 2 === a ? i & n | i & s | n & s : i ^ n ^ s) + o + e[t] + h[a] | 0, + o = s, s = n, n = i << 30 | i >>> 2, i = r, r = a; + } + this._a = r + this._a | 0, this._b = i + this._b | 0, this._c = n + this._c | 0, this._d = s + this._d | 0, this._e = o + this._e | 0; + }, i.prototype._hash = function () + { + var t = s.allocUnsafe(20); + return t.writeInt32BE(0 | this._a, 0), t.writeInt32BE(0 | this._b, 4), t.writeInt32BE(0 | this._c, 8), t.writeInt32BE(0 | this._d, + 12), t.writeInt32BE(0 | this._e, 16), t; + }, e.exports = i; + }, {"./hash":50, inherits:39, "safe-buffer":42}], 53:[function (t,e,r) + { + +function i() + { + this.init(), this._w = o, n.call(this, 64, 56); + }; + r = t("inherits"); + var n = t("./hash"), s = t("safe-buffer").Buffer, h = [1518500249, 1859775393, - 1894007588, - 899497514], o = Array(80); + r(i, n), i.prototype.init = function () + { + return this._a = 1732584193, this._b = 4023233417, this._c = 2562383102, this._d = 271733878, this._e = 3285377520, this; + }, i.prototype._update = function (t) + { + for(var e = this._w, r = 0 | this._a, i = 0 | this._b, n = 0 | this._c, s = 0 | this._d, o = 0 | this._e, a = 0; a < 16; ++a) + e[a] = t.readInt32BE(4 * a); + for(; a < 80; ++a) + t = e[a - 3] ^ e[a - 8] ^ e[a - 14] ^ e[a - 16], e[a] = t << 1 | t >>> 31; + for(a = 0; a < 80; ++a) + { + t = (r << 5 | r >>> 27) + (0 === (t = ~~(a / 20)) ? i & n | ~i & s : 2 === t ? i & n | i & s | n & s : i ^ n ^ s) + o + e[a] + h[t] | 0, + o = s, s = n, n = i << 30 | i >>> 2, i = r, r = t; + } + this._a = r + this._a | 0, this._b = i + this._b | 0, this._c = n + this._c | 0, this._d = s + this._d | 0, this._e = o + this._e | 0; + }, i.prototype._hash = function () + { + var t = s.allocUnsafe(20); + return t.writeInt32BE(0 | this._a, 0), t.writeInt32BE(0 | this._b, 4), t.writeInt32BE(0 | this._c, 8), t.writeInt32BE(0 | this._d, + 12), t.writeInt32BE(0 | this._e, 16), t; + }, e.exports = i; + }, {"./hash":50, inherits:39, "safe-buffer":42}], 54:[function (t,e,r) + { + +function i() + { + this.init(), this._w = a, s.call(this, 64, 56); + }; + r = t("inherits"); + var n = t("./sha256"), s = t("./hash"), o = t("safe-buffer").Buffer, a = Array(64); + r(i, n), i.prototype.init = function () + { + return this._a = 3238371032, this._b = 914150663, this._c = 812702999, this._d = 4144912697, this._e = 4290775857, this._f = 1750603025, + this._g = 1694076839, this._h = 3204075428, this; + }, i.prototype._hash = function () + { + var t = o.allocUnsafe(28); + return t.writeInt32BE(this._a, 0), t.writeInt32BE(this._b, 4), t.writeInt32BE(this._c, 8), t.writeInt32BE(this._d, 12), t.writeInt32BE(this._e, + 16), t.writeInt32BE(this._f, 20), t.writeInt32BE(this._g, 24), t; + }, e.exports = i; + }, {"./hash":50, "./sha256":55, inherits:39, "safe-buffer":42}], 55:[function (t,e,r) + { + +function i() + { + this.init(), this._w = o, n.call(this, 64, 56); + }; + r = t("inherits"); + var n = t("./hash"), s = t("safe-buffer").Buffer, c = [1116352408, 1899447441, 3049323471, 3921009573, 961987163, 1508970993, + 2453635748, 2870763221, 3624381080, 310598401, 607225278, 1426881987, 1925078388, 2162078206, 2614888103, 3248222580, 3835390401, + 4022224774, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, 2554220882, 2821834349, 2952996808, 3210313671, + 3336571891, 3584528711, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, 2177026350, + 2456956037, 2730485921, 2820302411, 3259730800, 3345764771, 3516065817, 3600352804, 4094571909, 275423344, 430227734, 506948616, + 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, 2227730452, 2361852424, 2428436474, + 2756734187, 3204031479, 3329325298], o = Array(64); + r(i, n), i.prototype.init = function () + { + return this._a = 1779033703, this._b = 3144134277, this._c = 1013904242, this._d = 2773480762, this._e = 1359893119, this._f = 2600822924, + this._g = 528734635, this._h = 1541459225, this; + }, i.prototype._update = function (t) + { + for(var e = this._w, r = 0 | this._a, i = 0 | this._b, n = 0 | this._c, s = 0 | this._d, o = 0 | this._e, a = 0 | this._f, + h = 0 | this._g, u = 0 | this._h, l = 0; l < 16; ++l) + e[l] = t.readInt32BE(4 * l); + for(; l < 64; ++l) + { + t = e[l - 2]; + var f = e[l - 15]; + e[l] = ((t >>> 17 | t << 15) ^ (t >>> 19 | t << 13) ^ t >>> 10) + e[l - 7] + ((f >>> 7 | f << 25) ^ (f >>> 18 | f << 14) ^ f >>> 3) + e[l - 16] | 0; + } + for(l = 0; l < 64; ++l) + t = u + ((o >>> 6 | o << 26) ^ (o >>> 11 | o << 21) ^ (o >>> 25 | o << 7)) + (h ^ o & (a ^ h)) + c[l] + e[l] | 0, f = ((r >>> 2 | r << 30) ^ (r >>> 13 | r << 19) ^ (r >>> 22 | r << 10)) + (r & i | n & (r | i)) | 0, + u = h, h = a, a = o, o = s + t | 0, s = n, n = i, i = r, r = t + f | 0; + this._a = r + this._a | 0, this._b = i + this._b | 0, this._c = n + this._c | 0, this._d = s + this._d | 0, this._e = o + this._e | 0, + this._f = a + this._f | 0, this._g = h + this._g | 0, this._h = u + this._h | 0; + }, i.prototype._hash = function () + { + var t = s.allocUnsafe(32); + return t.writeInt32BE(this._a, 0), t.writeInt32BE(this._b, 4), t.writeInt32BE(this._c, 8), t.writeInt32BE(this._d, 12), t.writeInt32BE(this._e, + 16), t.writeInt32BE(this._f, 20), t.writeInt32BE(this._g, 24), t.writeInt32BE(this._h, 28), t; + }, e.exports = i; + }, {"./hash":50, inherits:39, "safe-buffer":42}], 56:[function (t,e,r) + { + +function i() + { + this.init(), this._w = a, s.call(this, 128, 112); + }; + r = t("inherits"); + var n = t("./sha512"), s = t("./hash"), o = t("safe-buffer").Buffer, a = Array(160); + r(i, n), i.prototype.init = function () + { + return this._ah = 3418070365, this._bh = 1654270250, this._ch = 2438529370, this._dh = 355462360, this._eh = 1731405415, this._fh = 2394180231, + this._gh = 3675008525, this._hh = 1203062813, this._al = 3238371032, this._bl = 914150663, this._cl = 812702999, this._dl = 4144912697, + this._el = 4290775857, this._fl = 1750603025, this._gl = 1694076839, this._hl = 3204075428, this; + }, i.prototype._hash = function () + { + +function t(t,e,r) + { + i.writeInt32BE(t, r), i.writeInt32BE(e, r + 4); + }; + var i = o.allocUnsafe(48); + return t(this._ah, this._al, 0), t(this._bh, this._bl, 8), t(this._ch, this._cl, 16), t(this._dh, this._dl, 24), t(this._eh, + this._el, 32), t(this._fh, this._fl, 40), i; + }, e.exports = i; + }, {"./hash":50, "./sha512":57, inherits:39, "safe-buffer":42}], 57:[function (t,e,r) + { + +function i() + { + this.init(), this._w = o, n.call(this, 128, 112); + }; + +function k(t,e) + { + return t >>> 0 < e >>> 0 ? 1 : 0; + }; + r = t("inherits"); + var n = t("./hash"), s = t("safe-buffer").Buffer, T = [1116352408, 3609767458, 1899447441, 602891725, 3049323471, 3964484399, + 3921009573, 2173295548, 961987163, 4081628472, 1508970993, 3053834265, 2453635748, 2937671579, 2870763221, 3664609560, 3624381080, + 2734883394, 310598401, 1164996542, 607225278, 1323610764, 1426881987, 3590304994, 1925078388, 4068182383, 2162078206, 991336113, + 2614888103, 633803317, 3248222580, 3479774868, 3835390401, 2666613458, 4022224774, 944711139, 264347078, 2341262773, 604807628, + 2007800933, 770255983, 1495990901, 1249150122, 1856431235, 1555081692, 3175218132, 1996064986, 2198950837, 2554220882, 3999719339, + 2821834349, 766784016, 2952996808, 2566594879, 3210313671, 3203337956, 3336571891, 1034457026, 3584528711, 2466948901, 113926993, + 3758326383, 338241895, 168717936, 666307205, 1188179964, 773529912, 1546045734, 1294757372, 1522805485, 1396182291, 2643833823, + 1695183700, 2343527390, 1986661051, 1014477480, 2177026350, 1206759142, 2456956037, 344077627, 2730485921, 1290863460, 2820302411, + 3158454273, 3259730800, 3505952657, 3345764771, 106217008, 3516065817, 3606008344, 3600352804, 1432725776, 4094571909, 1467031594, + 275423344, 851169720, 430227734, 3100823752, 506948616, 1363258195, 659060556, 3750685593, 883997877, 3785050280, 958139571, + 3318307427, 1322822218, 3812723403, 1537002063, 2003034995, 1747873779, 3602036899, 1955562222, 1575990012, 2024104815, 1125592928, + 2227730452, 2716904306, 2361852424, 442776044, 2428436474, 593698344, 2756734187, 3733110249, 3204031479, 2999351573, 3329325298, + 3815920427, 3391569614, 3928383900, 3515267271, 566280711, 3940187606, 3454069534, 4118630271, 4000239992, 116418474, 1914138554, + 174292421, 2731055270, 289380356, 3203993006, 460393269, 320620315, 685471733, 587496836, 852142971, 1086792851, 1017036298, + 365543100, 1126000580, 2618297676, 1288033470, 3409855158, 1501505948, 4234509866, 1607167915, 987167468, 1816402316, 1246189591], + o = Array(160); + r(i, n), i.prototype.init = function () + { + return this._ah = 1779033703, this._bh = 3144134277, this._ch = 1013904242, this._dh = 2773480762, this._eh = 1359893119, this._fh = 2600822924, + this._gh = 528734635, this._hh = 1541459225, this._al = 4089235720, this._bl = 2227873595, this._cl = 4271175723, this._dl = 1595750129, + this._el = 2917565137, this._fl = 725511199, this._gl = 4215389547, this._hl = 327033209, this; + }, i.prototype._update = function (t) + { + for(var e = this._w, r = 0 | this._ah, i = 0 | this._bh, n = 0 | this._ch, s = 0 | this._dh, o = 0 | this._eh, a = 0 | this._fh, + h = 0 | this._gh, u = 0 | this._hh, l = 0 | this._al, f = 0 | this._bl, c = 0 | this._cl, d = 0 | this._dl, p = 0 | this._el, + m = 0 | this._fl, _ = 0 | this._gl, g = 0 | this._hl, b = 0; b < 32; b += 2) + e[b] = t.readInt32BE(4 * b), e[b + 1] = t.readInt32BE(4 * b + 4); + for(; b < 160; b += 2) + { + t = e[b - 30]; + var y = e[b - 30 + 1], w = (t >>> 1 | y << 31) ^ (t >>> 8 | y << 24) ^ t >>> 7, v = (y >>> 1 | t << 31) ^ (y >>> 8 | t << 24) ^ (y >>> 7 | t << 25), + M = ((t = e[b - 4]) >>> 19 | (y = e[b - 4 + 1]) << 13) ^ (y >>> 29 | t << 3) ^ t >>> 6; + y = (y >>> 19 | t << 13) ^ (t >>> 29 | y << 3) ^ (y >>> 6 | t << 26); + var E = e[b - 32], S = e[b - 32 + 1]; + t = v + e[b - 14 + 1] | 0, w = (w = (w = w + e[b - 14] + k(t, v) | 0) + M + k(t = t + y | 0, y) | 0) + E + k(t = t + S | 0, + S) | 0, e[b] = w, e[b + 1] = t; + } + for(b = 0; b < 160; b += 2) + { + w = e[b], t = e[b + 1], y = r & i | n & (r | i); + var I = l & f | c & (l | f); + E = (r >>> 28 | l << 4) ^ (l >>> 2 | r << 30) ^ (l >>> 7 | r << 25), S = (l >>> 28 | r << 4) ^ (r >>> 2 | l << 30) ^ (r >>> 7 | l << 25); + var A = T[b], B = T[b + 1], x = h ^ o & (a ^ h), L = _ ^ p & (m ^ _); + v = (v = (v = (v = u + ((o >>> 14 | p << 18) ^ (o >>> 18 | p << 14) ^ (p >>> 9 | o << 23)) + k(M = g + ((p >>> 14 | o << 18) ^ (p >>> 18 | o << 14) ^ (o >>> 9 | p << 23)) | 0, + g) | 0) + x + k(M = M + L | 0, L) | 0) + A + k(M = M + B | 0, B) | 0) + w + k(M = M + t | 0, t) | 0, w = E + y + k(t = S + I | 0, + S) | 0, u = h, g = _, h = a, _ = m, a = o, m = p, o = s + v + k(p = d + M | 0, d) | 0, s = n, d = c, n = i, c = f, i = r, f = l, + r = v + w + k(l = M + t | 0, M) | 0; + } + this._al = this._al + l | 0, this._bl = this._bl + f | 0, this._cl = this._cl + c | 0, this._dl = this._dl + d | 0, this._el = this._el + p | 0, + this._fl = this._fl + m | 0, this._gl = this._gl + _ | 0, this._hl = this._hl + g | 0, this._ah = this._ah + r + k(this._al, + l) | 0, this._bh = this._bh + i + k(this._bl, f) | 0, this._ch = this._ch + n + k(this._cl, c) | 0, this._dh = this._dh + s + k(this._dl, + d) | 0, this._eh = this._eh + o + k(this._el, p) | 0, this._fh = this._fh + a + k(this._fl, m) | 0, this._gh = this._gh + h + k(this._gl, + _) | 0, this._hh = this._hh + u + k(this._hl, g) | 0; + }, i.prototype._hash = function () + { + +function t(t,e,r) + { + i.writeInt32BE(t, r), i.writeInt32BE(e, r + 4); + }; + var i = s.allocUnsafe(64); + return t(this._ah, this._al, 0), t(this._bh, this._bl, 8), t(this._ch, this._cl, 16), t(this._dh, this._dl, 24), t(this._eh, + this._el, 32), t(this._fh, this._fl, 40), t(this._gh, this._gl, 48), t(this._hh, this._hl, 56), i; + }, e.exports = i; + }, {"./hash":50, inherits:39, "safe-buffer":42}]}, {}, [30]); diff --git a/src/HTML/JS/terahashlib.js b/src/HTML/JS/terahashlib.js new file mode 100644 index 0000000..e4f2c09 --- /dev/null +++ b/src/HTML/JS/terahashlib.js @@ -0,0 +1,411 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var DELTA_LONG_MINING = 5000; +var BLOCKNUM_ALGO2 = 6560000; +var BLOCKNUM_HASH_NEW = 10195000; +var BLOCKNUM_TICKET_ALGO = 16070000; +if (typeof global === "object") { + global.GetHashFromSeqAddr = GetHashFromSeqAddr; + global.CalcHashBlockFromSeqAddr = CalcHashBlockFromSeqAddr; + global.GetHashFromNum2 = GetHashFromNum2; + global.GetHashFromNum3 = GetHashFromNum3; + global.GetHashFromArrNum2 = GetHashFromArrNum2; + global.XORArr = XORArr; + global.GetHash = GetHash; + if (global.LOCAL_RUN || global.TEST_NETWORK) { + BLOCKNUM_ALGO2 = 0; + if (global.TEST_NETWORK) { + BLOCKNUM_HASH_NEW = 100; + BLOCKNUM_TICKET_ALGO = 0; + } + else { + BLOCKNUM_HASH_NEW = 100; + BLOCKNUM_TICKET_ALGO = 0; + } + } +} + +function GetHashFromSeqAddr(SeqHash, AddrHash, BlockNum, PrevHash, MiningVer) { + if (BlockNum < BLOCKNUM_ALGO2) { + var Hash = shaarrblock2(SeqHash, AddrHash, BlockNum); + return { Hash: Hash, PowHash: Hash, Hash1: Hash, Hash2: Hash }; + } + var MinerID = ReadUintFromArr(AddrHash, 0); + var Nonce0 = ReadUintFromArr(AddrHash, 6); + var Nonce1 = ReadUintFromArr(AddrHash, 12); + var Nonce2 = ReadUintFromArr(AddrHash, 18); + var DeltaNum1 = ReadUint16FromArr(AddrHash, 24); + var DeltaNum2 = ReadUint16FromArr(AddrHash, 26); + var PrevHashNum; + if (PrevHash) { + PrevHashNum = ReadUint32FromArr(PrevHash, 28); + } + else { + PrevHashNum = ReadUint32FromArr(AddrHash, 28); + } + var Data = GetHash(SeqHash, PrevHashNum, BlockNum, MinerID, Nonce0, Nonce1, Nonce2, DeltaNum1, DeltaNum2); + if (MiningVer) { + if (AddrHash[17] !== MiningVer || AddrHash[23] !== MiningVer) { + Data.PowHash = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]; + } + } + return Data; +}; + +function GetHash(BlockHash, PrevHashNum, BlockNum, Miner, Nonce0, Nonce1, Nonce2, DeltaNum1, DeltaNum2) { + if (DeltaNum1 > DELTA_LONG_MINING) + DeltaNum1 = 0; + if (DeltaNum2 > DELTA_LONG_MINING) + DeltaNum2 = 0; + var HashBase = GetHashFromNum2(BlockNum, PrevHashNum); + var HashCurrent = GetHashFromArrNum2(BlockHash, Miner, Nonce0); + var HashNonce1 = GetHashFromNum3(BlockNum - DeltaNum1, Miner, Nonce1); + var HashNonce2 = GetHashFromNum3(BlockNum - DeltaNum2, Miner, Nonce2); + var Hash1 = XORArr(HashBase, HashNonce1); + var Hash2 = XORArr(HashCurrent, HashNonce2); + var Ret = { Hash: Hash2, Hash1: Hash1, Hash2: Hash2 }; + if (CompareArr(Hash1, Hash2) > 0) { + Ret.PowHash = Hash1; + } + else { + Ret.PowHash = Hash2; + } + if (BlockNum >= BLOCKNUM_HASH_NEW) { + if (BlockNum >= BLOCKNUM_TICKET_ALGO) + Ret.Hash = sha3arr2(Hash1, Hash2); + else + Ret.Hash = shaarr2(Hash1, Hash2); + } + return Ret; +}; + +function CalcHashBlockFromSeqAddr(Block, PrevHash, MiningVer) { + var Value = GetHashFromSeqAddr(Block.SeqHash, Block.AddrHash, Block.BlockNum, PrevHash, MiningVer); + Block.Hash = Value.Hash; + Block.PowHash = Value.PowHash; +}; + +function XORArr(Arr1, Arr2) { + var Ret = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (var i = 0; i < 32; i++) { + Ret[i] = Arr1[i] ^ Arr2[i]; + } + return Ret; +}; + +function GetHashFromNum2(Value1, Value2) { + var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + WriteUintToArrOnPos(MeshArr, Value1, 0); + WriteUintToArrOnPos(MeshArr, Value2, 6); + return sha3(MeshArr); +}; + +function GetHashFromArrNum2(Arr, Value1, Value2) { + var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0]; + WriteArrToArrOnPos(MeshArr, Arr, 0, 32); + WriteUintToArrOnPos(MeshArr, Value1, 32); + WriteUintToArrOnPos(MeshArr, Value2, 38); + return sha3(MeshArr); +}; + +function GetHashFromNum3(Value1, Value2, Value3) { + var MeshArr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + WriteUintToArrOnPos(MeshArr, Value1, 0); + WriteUintToArrOnPos(MeshArr, Value2, 6); + WriteUintToArrOnPos(MeshArr, Value3, 12); + return sha3(MeshArr); +}; + +function ReadUintFromArr(arr, len) { + if (len === undefined) { + len = arr.len; + arr.len += 6; + } + var value = (arr[len + 5] << 23) * 2 + (arr[len + 4] << 16) + (arr[len + 3] << 8) + arr[len + 2]; + value = value * 256 + arr[len + 1]; + value = value * 256 + arr[len]; + return value; +}; + +function ReadUint32FromArr(arr, len) { + if (len === undefined) { + len = arr.len; + arr.len += 4; + } + var value = (arr[len + 3] << 23) * 2 + (arr[len + 2] << 16) + (arr[len + 1] << 8) + arr[len]; + return value; +}; + +function ReadUint16FromArr(arr, len) { + if (len === undefined) { + len = arr.len; + arr.len += 2; + } + var value = (arr[len + 1] << 8) + arr[len]; + return value; +}; + +function ReadArrFromArr(arr, length) { + var Ret = []; + var len = arr.len; + for (var i = 0; i < length; i++) { + Ret[i] = arr[len + i]; + } + arr.len += length; + return Ret; +}; + +function WriteUintToArr(arr, Num) { + var len = arr.length; + arr[len] = Num & 0xFF; + arr[len + 1] = (Num >>> 8) & 0xFF; + arr[len + 2] = (Num >>> 16) & 0xFF; + arr[len + 3] = (Num >>> 24) & 0xFF; + var NumH = Math.floor(Num / 4294967296); + arr[len + 4] = NumH & 0xFF; + arr[len + 5] = (NumH >>> 8) & 0xFF; +}; + +function WriteUintToArrOnPos(arr, Num, Pos) { + arr[Pos] = Num & 0xFF; + arr[Pos + 1] = (Num >>> 8) & 0xFF; + arr[Pos + 2] = (Num >>> 16) & 0xFF; + arr[Pos + 3] = (Num >>> 24) & 0xFF; + var NumH = Math.floor(Num / 4294967296); + arr[Pos + 4] = NumH & 0xFF; + arr[Pos + 5] = (NumH >>> 8) & 0xFF; +}; + +function WriteUint32ToArr(arr, Num) { + var len = arr.length; + arr[len] = Num & 0xFF; + arr[len + 1] = (Num >>> 8) & 0xFF; + arr[len + 2] = (Num >>> 16) & 0xFF; + arr[len + 3] = (Num >>> 24) & 0xFF; +}; + +function WriteUint32ToArrOnPos(arr, Num, Pos) { + arr[Pos] = Num & 0xFF; + arr[Pos + 1] = (Num >>> 8) & 0xFF; + arr[Pos + 2] = (Num >>> 16) & 0xFF; + arr[Pos + 3] = (Num >>> 24) & 0xFF; +}; + +function WriteUint16ToArrOnPos(arr, Num, Pos) { + arr[Pos] = Num & 0xFF; + arr[Pos + 1] = (Num >>> 8) & 0xFF; +}; + +function WriteArrToArr(arr, arr2, ConstLength) { + var len = arr.length; + for (var i = 0; i < ConstLength; i++) { + arr[len + i] = arr2[i]; + } +}; + +function WriteArrToArrOnPos(arr, arr2, Pos, ConstLength) { + for (var i = 0; i < ConstLength; i++) { + arr[Pos + i] = arr2[i]; + } +}; + +function WriteArrToArrHOnPos(arr, arr2, Pos, ConstLength) { + for (var i = 0; i < ConstLength; i++) { + arr[Pos + i] |= (arr2[i] << 8); + } +}; + +function ConvertBufferToStr(Data) { + for (var key in Data) { + var item = Data[key]; + if (item instanceof Buffer) { + Data[key] = GetHexFromArr(item); + } + else + if (typeof item === "object") + ConvertBufferToStr(item); + } +}; + +function CopyObjValue(obj, num) { + if (num && num > 5) + return obj; + var ret = {}; + for (var key in obj) { + var val = obj[key]; + if ((typeof val === "object") && !(val instanceof Buffer) && !(val instanceof ArrayBuffer) && !(val instanceof Array)) + val = CopyObjValue(val, num + 1); + ret[key] = val; + } + return ret; +}; + +function CopyArr(arr1) { + var arr2 = []; + if (arr1) + for (var i = 0; i < arr1.length; i++) + arr2[i] = arr1[i]; + return arr2; +}; + +function ParseNum(a) { + var Num = parseInt(a); + if (!Num) + Num = 0; + if (isNaN(Num)) + Num = 0; + if (Num < 0) + Num = 0; + return Num; +}; + +function CompareArr(a, b) { + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) + return a[i] - b[i]; + } + return 0; +}; + +function CompareArrL(a, b) { + if (a.length !== b.length) + return a.length - b.length; + for (var i = 0; i < a.length; i++) { + if (a[i] !== b[i]) + return a[i] - b[i]; + } + return 0; +}; + +function GetSeqHash(BlockNum, PrevHash, TreeHash) { + var arr = [GetArrFromValue(BlockNum), PrevHash, TreeHash]; + var SeqHash = CalcHashFromArray(arr, true); + return SeqHash; +}; + +function arr2(Value1, Value2) { + var Buf = []; + for (var n = 0; n < Value1.length; n++) + Buf.push(Value1[n]); + for (var n = 0; n < Value2.length; n++) + Buf.push(Value2[n]); + return Buf; +}; + +function shaarr2(Value1, Value2) { + return shaarr(arr2(Value1, Value2)); +}; + +function sha3arr2(Value1, Value2) { + return sha3(arr2(Value1, Value2)); +}; + +function GetBlockArrFromBuffer(BufRead, Info) { + if (!BufRead || BufRead.length < 10) + return []; + var BLOCK_PROCESSING_LENGTH = 8; + var BLOCK_PROCESSING_LENGTH2 = BLOCK_PROCESSING_LENGTH * 2; + BufRead.len = 0; + var StartNum = ReadUintFromArr(BufRead); + var CountLoad = ReadUint32FromArr(BufRead); + var BufSize = 6 + 4 + BLOCK_PROCESSING_LENGTH2 * 32 + 32 + 6 + CountLoad * 64; + if (CountLoad <= 0 || BufSize !== BufRead.length) { + return []; + } + var PrevBlock; + var BlockArr = []; + for (var i = 0; i < CountLoad + BLOCK_PROCESSING_LENGTH2; i++) { + var Block = {}; + Block.BlockNum = StartNum + i; + if (i < BLOCK_PROCESSING_LENGTH2) { + Block.Hash = ReadArrFromArr(BufRead, 32); + } + else { + if (i === BLOCK_PROCESSING_LENGTH2) { + Block.SumHash = ReadArrFromArr(BufRead, 32); + Block.SumPow = ReadUintFromArr(BufRead); + } + Block.TreeHash = ReadArrFromArr(BufRead, 32); + Block.AddrHash = ReadArrFromArr(BufRead, 32); + var arr = []; + var start = i - BLOCK_PROCESSING_LENGTH2; + for (var n = 0; n < BLOCK_PROCESSING_LENGTH; n++) { + var Prev = BlockArr[start + n]; + arr.push(Prev.Hash); + } + Block.PrevHash = CalcHashFromArray(arr, true); + Block.SeqHash = GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash); + var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28); + var PrevAddrNum = ReadUint32FromArr(Block.AddrHash, 28); + if (PrevHashNum !== PrevAddrNum && Block.BlockNum > 20000000) { + if (global.WATCHDOG_DEV) { + var Str = ""; + if (Info && Info.Node) + Str = " from " + NodeName(Info.Node); + ToError("Error on block load: " + Block.BlockNum + Str); + } + return []; + } + CalcHashBlockFromSeqAddr(Block, Block.PrevHash); + Block.Power = GetPowPower(Block.PowHash); + if (PrevBlock) { + Block.SumHash = shaarr2(PrevBlock.SumHash, Block.Hash); + } + PrevBlock = Block; + } + Block.TrCount = 0; + Block.TrDataPos = 0; + Block.TrDataLen = 0; + BlockArr.push(Block); + } + for (var i = BlockArr.length - 1; i >= 0; i--) { + var Block = BlockArr[i]; + if (!Block.SumHash) { + BlockArr = BlockArr.slice(i + 1); + break; + } + } + return BlockArr; +}; + +function shaarrblock2(Value1, Value2, BlockNum) { + return shaarrblock(arr2(Value1, Value2), BlockNum); +}; +if (typeof global === "object") { + global.ReadUint32FromArr = ReadUint32FromArr; + global.ReadUintFromArr = ReadUintFromArr; + global.ReadUint16FromArr = ReadUint16FromArr; + global.WriteUintToArr = WriteUintToArr; + global.WriteUint32ToArr = WriteUint32ToArr; + global.WriteUint32ToArrOnPos = WriteUint32ToArrOnPos; + global.WriteUint16ToArrOnPos = WriteUint16ToArrOnPos; + global.WriteUintToArrOnPos = WriteUintToArrOnPos; + global.WriteArrToArr = WriteArrToArr; + global.WriteArrToArrOnPos = WriteArrToArrOnPos; + global.WriteArrToArrHOnPos = WriteArrToArrHOnPos; + global.ConvertBufferToStr = ConvertBufferToStr; + global.CopyObjValue = CopyObjValue; + global.CopyArr = CopyArr; + global.ParseNum = ParseNum; + global.CompareArr = CompareArr; + global.CompareArrL = CompareArrL; + global.shaarr2 = shaarr2; + global.sha3arr2 = sha3arr2; + global.arr2 = arr2; + global.GetBlockArrFromBuffer = GetBlockArrFromBuffer; + global.shaarrblock2 = shaarrblock2; +} +else + if (typeof window === "object") { + global = window; + } diff --git a/src/HTML/JS/tx-lib.js b/src/HTML/JS/tx-lib.js new file mode 100644 index 0000000..8659b5d --- /dev/null +++ b/src/HTML/JS/tx-lib.js @@ -0,0 +1,10 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://web.telegram.org/#/im?p=@terafoundation +*/ + diff --git a/src/HTML/JS/wallet-lib.js b/src/HTML/JS/wallet-lib.js new file mode 100644 index 0000000..889a7d1 --- /dev/null +++ b/src/HTML/JS/wallet-lib.js @@ -0,0 +1,706 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var PayList = []; +var AttachItem; +var MapAccounts = {}; +var LoadMapAfter = {}; +var MapCheckTransaction = {}; +var CanSendTransaction = 1; +var CurrentTR = {}; +var MaxBlockNum = 0; +var DelList = {}; +var WasAccountsDataStr; + +function SetAccountsData(Data,AccountsDataStr) +{ + if(!Data || !Data.result) + return ; + if($("idBtRun")) + $("idBtRun").style.display = (Data.arr.length ? '' : 'none'); + if(AccountsDataStr === WasAccountsDataStr) + return ; + WasAccountsDataStr = AccountsDataStr; + var arr = Data.arr; + var Select = $("idAccount"); + if(arr.length !== Select.options.length) + { + var options = Select.options; + options.length = arr.length; + } + MaxBlockNum = GetCurrentBlockNumByTime(); + SetGridData(arr, "grid_accounts", "idMyTotalSum"); + for(var i = 0; arr && i < arr.length; i++) + { + var Item = arr[i]; + Item.MyAccount = true; + var Num = ParseNum(Item.Num); + if(!MapAccounts[Num]) + MapAccounts[Num] = {}; + CopyObjKeys(MapAccounts[Num], Item); + var option = Select.options[i]; + var StrText = GetAccountText(Item, Num, 1); + if(option.text !== StrText) + CheckNameAccTo(); + option.value = Num; + option.text = StrText; + } + var CurentValue = LoadMapAfter["idAccount"]; + if(CurentValue) + { + Select.value = CurentValue; + delete LoadMapAfter["idAccount"]; + } + SetCurCurencyName(); +}; + +function CurTransactionToForm(bForce) +{ + var Item = $("idTransaction"); + if(Item && (Item.className === "" || bForce)) + Item.value = GetJSONFromTransaction(CurrentTR); +}; + +function CheckNameAccTo() +{ + MaxBlockNum = GetCurrentBlockNumByTime(); + var ToID = ParseNum($("idTo").value); + if(!MapAccounts[ToID] || (MapAccounts[ToID].MustUpdate && MapAccounts[ToID].MustUpdate >= MaxBlockNum)) + { + GetData("GetAccountList", {StartNum:ToID}, function (Data) + { + if(Data && Data.result === 1 && Data.arr.length) + { + var Item = Data.arr[0]; + Item.UpdateData = Date.now(); + MapAccounts[Item.Num] = Item; + SetNameAccTo(); + } + }); + } + SetNameAccTo(); +}; + +function SetNameAccTo() +{ + var Str = ""; + var ToID = ParseNum($("idTo").value); + var Item = MapAccounts[ToID]; + var element = $("idNameTo"); + var StrTo = GetAccountText(Item, ToID, 1); + if(!element) + { + element = $("idNameTo2"); + } + else + { + StrTo = "To: " + StrTo; + } + if(element.innerText !== StrTo) + { + element.innerText = StrTo; + if(Item && Item.MyAccount) + element.className = "smallbold"; + else + element.className = ""; + } +}; + +function GetAccountText(Item,Num,bGetSum) +{ + if(Item) + { + var text = Item.Name; + if(!text || text.length === 0) + text = Num; + else + text = "" + Num + ". " + text; + if(bGetSum) + { + var StrSum = SUM_TO_STRING(Item.Value, Item.Currency); + text += " (" + StrSum + ")"; + } + return text; + } + else + { + return Num; + } +}; + +function OnEditIdTo() +{ + CheckNameAccTo(); + OnEditTransactionFields(); +}; + +function OnEditTransactionFields() +{ + if(IsVisibleBlock("edit_transaction")) + CreateTransaction(); + SetCurCurencyName(); + SaveValues(); +}; + +function SetCurCurencyName() +{ + var idCoin = $("idCoinName"); + if(!idCoin) + return ; + var Num = ParseNum($("idAccount").value); + var Item = MapAccounts[Num]; + if(Item) + { + idCoin.innerText = CurrencyName(Item.Currency); + } +}; + +function CreateTransaction(F,CheckErr,Run) +{ + CheckNameAccTo(); + CheckSending(); + var FromID = ParseNum($("idAccount").value); + if(CheckErr && FromID === 0) + { + SetError("Select valid 'From account'"); + return ; + } + var StrTo = $("idTo").value.trim(); + var bFindAcc = 0; + var ToPubKey = ""; + var ToID = ParseNum(StrTo); + if(StrTo !== "" + ToID) + { + if(StrTo.length === 66 && (StrTo.substr(0, 2) === "02" || StrTo.substr(0, 2) === "03") && IsHexStr(StrTo)) + { + ToID = 0; + ToPubKey = StrTo; + if(ToPubKey === PubKeyStr) + bFindAcc = 1; + } + else + { + if(CheckErr) + SetError("Valid 'Pay to' - required!"); + return ; + } + } + if(CheckErr && ToID <= 0 && ToPubKey === "" && !AttachItem) + { + SetError("Valid 'Pay to' - required!"); + return ; + } + var Description = $("idDescription").value.substr(0, 200); + var StrSum = $("idSumSend").value; + var indDot = StrSum.indexOf("."); + if(indDot >= 0) + { + var StrTER = StrSum.substr(0, indDot); + var StrCENT = StrSum.substr(indDot + 1); + } + else + { + var StrTER = StrSum; + var StrCENT = "0"; + } + StrCENT = StrCENT + "000000000"; + var Coin = {SumCOIN:ParseNum(StrTER), SumCENT:ParseNum(StrCENT.substr(0, 9))}; + var OperationID = 0; + var Item = MapAccounts[FromID]; + if(Item) + { + OperationID = Item.Value.OperationID; + } + var AttachBody = []; + if(AttachItem) + { + AttachBody = AttachItem.Data.Body; + if(!AttachBody) + AttachBody = []; + } + var ToPubKeyArr = []; + if(ToPubKey) + ToPubKeyArr = GetArrFromHex(ToPubKey); + var TR = {Type:111, Version:3, Reserve:0, FromID:FromID, OperationID:OperationID, To:[{PubKey:ToPubKeyArr, ID:ToID, SumCOIN:Coin.SumCOIN, + SumCENT:Coin.SumCENT}], Description:Description, Body:AttachBody, Sign:CurrentTR.Sign, }; + Object.defineProperties(TR, {bFindAcc:{configurable:true, writable:true, enumerable:false, value:bFindAcc}}); + Object.defineProperties(TR, {Run:{configurable:true, writable:true, enumerable:false, value:Run}}); + if(JSON.stringify(TR) === JSON.stringify(CurrentTR)) + { + if(F) + F(CurrentTR); + return ; + } + CurrentTR = TR; + GetSignTransaction(TR, "", function (TR) + { + CurTransactionToForm(true); + if(F) + F(TR); + }); +}; + +function SignJSON(F) +{ + if($("idSignJSON").disabled) + return ; + var TR = GetTransactionFromJSON(); + if(!TR) + return ; + CurrentTR = TR; + GetSignTransaction(TR, "", function (TR) + { + CurTransactionToForm(true); + if(F) + F(); + }); +}; + +function CheckSending(bToStatus) +{ + MaxBlockNum = GetCurrentBlockNumByTime(); + var CanSend = IsPrivateMode(); + var StrButton = "Send"; + var StrButtonSign = "Sign JSON"; + if(!CanSend) + { + StrButton = " "; + StrButtonSign = " "; + } + if(CanSend) + { + var FromID = ParseNum($("idAccount").value); + var Item = MapAccounts[FromID]; + if(Item && Item.NextSendTime && Item.NextSendTime > MaxBlockNum) + { + if(bToStatus) + SetStatus("Transaction was sending. Wait... (" + Item.LastTransactionText + ")"); + CanSend = false; + StrButton = "Wait..."; + } + } + $("idSendButton").disabled = (!CanSend); + $("idSendButton").value = StrButton; + $("idSignJSON").disabled = (!CanSend); + $("idSignJSON").value = StrButtonSign; + return CanSend; +}; + +function AddWhiteList() +{ + var ToID = ParseNum($("idTo").value); + if(ToID && $("idWhiteOnSend").checked) + Storage.setItem("White:" + ToID, 1); +}; + +function SendMoneyBefore() +{ + if($("idSendButton").disabled) + return ; + var ToID = ParseNum($("idTo").value); + var Item = MapAccounts[ToID]; + if(Storage.getItem("White:" + ToID) || !$("idSumSend").value || Item && Item.MyAccount) + { + SendMoney(); + } + else + { + var CoinAmount = COIN_FROM_FLOAT($("idSumSend").value); + var StrTo = " to " + GetAccountText(Item, ToID); + $("idWhiteOnSend").checked = 0; + $("idOnSendText").innerHTML = "" + STRING_FROM_COIN(CoinAmount) + " " + $("idCoinName").innerText + StrTo; + if($("idSumSend").value >= 100000) + { + $("idOnSendText").innerHTML += "
    WARNING: You are about to send a very large amount!
    "; + } + SetVisibleBlock("idBlockOnSend", 1); + SetImg(this, 'idBlockOnSend'); + } +}; + +function SendMoney2() +{ + AddWhiteList(); + SendMoney(); +}; + +function SendMoney() +{ + if(!CanSendTransaction) + { + SetError("Can't Send transaction"); + return ; + } + CheckSending(true); + if($("idSendButton").disabled) + return ; + SetVisibleBlock("idBlockOnSend", 0); + CreateTransaction(SendMoneyTR, true, ClearAttach); +}; + +function GetJSONFromTransaction(TR) +{ + var TR2 = JSON.parse(JSON.stringify(TR)); + for(var i = 0; i < TR2.To.length; i++) + { + var Item = TR2.To[i]; + Item.PubKey = GetHexFromArr(Item.PubKey); + } + TR2.Body = GetHexFromArr(TR2.Body); + TR2.Sign = GetHexFromArr(TR2.Sign); + var Str = JSON.stringify(TR2, "", 4); + return Str; +}; + +function GetTransactionFromJSON() +{ + var Str = $("idTransaction").value; + try + { + var TR = JSON.parse(Str); + } + catch(e) + { + SetError(e); + return undefined; + } + for(var i = 0; i < TR.To.length; i++) + { + var Item = TR.To[i]; + Item.PubKey = GetArrFromHex(Item.PubKey); + if(Item.SumTER && Item.SumCOIN === undefined) + { + Item.SumCOIN = Item.SumTER; + delete Item.SumTER; + } + } + TR.Body = GetArrFromHex(TR.Body); + TR.Sign = GetArrFromHex(TR.Sign); + return TR; +}; + +function SendMoneyJSON() +{ + if(!CanSendTransaction) + { + SetError("Can't Send transaction"); + return ; + } + var TR = GetTransactionFromJSON(); + if(!TR) + return ; + SendMoneyTR(TR); +}; + +function SignAndSendFromJSON() +{ + SignJSON(SendMoneyJSON); +}; + +function GetTransactionText(TR,key) +{ + var Str; + if(TR) + { + if(TR.Type === TYPE_TRANSACTION_CREATE) + { + Str = "New account " + TR.Name.substr(0, 20); + } + else + if(TR.Type === 111) + { + var MapItem = {}; + var ValueTotal = {SumCOIN:0, SumCENT:0}; + Str = "" + TR.FromID + "/" + TR.OperationID + " to "; + for(var i = 0; i < TR.To.length; i++) + { + var Item = TR.To[i]; + if(Item.ID === TR.FromID || MapItem[Item.ID]) + continue; + MapItem[Item.ID] = 1; + ADD(ValueTotal, Item); + if(i === 0) + Str += "["; + if(Str.length < 16) + { + if(i > 0) + Str += ","; + if(Item.ID || (Item.PubKey && Item.PubKey.length !== 66)) + Str += Item.ID; + else + Str += GetHexFromArr(Item.PubKey).substr(0, 8); + } + else + if(Str.substr(Str.length - 1) !== ".") + Str += "..."; + } + Str += "] " + SUM_TO_STRING(ValueTotal); + Str += " " + (TR.Description.substr(0, 20)).replace(/\n/g, ""); + } + } + else + { + if(key) + Str = key; + else + Str = ""; + } + return Str; +}; + +function SendMoneyTR(TR) +{ + var Body = GetArrFromTR(TR); + WriteArr(Body, TR.Sign, 64); + Body.length += 12; + SendTransaction(Body, TR, undefined, function (Err,TR,Body) + { + if(Err) + return ; + var Item = MapAccounts[TR.FromID]; + if(Item) + { + var key = GetHexFromArr(sha3(Body)); + var BlockNum = GetCurrentBlockNumByTime(); + Item.LastTransactionText = GetTransactionText(TR); + Item.NextSendTime = BlockNum + 10; + MapCheckTransaction[key] = Item; + CheckSending(); + } + }); +}; + +function ClearTransaction() +{ + PayList = []; + ClearAttach(); + CheckSendList(1); + var arr = ["idAccount", "idTo", "idSumSend", "idDescription"]; + for(var i = 0; i < arr.length; i++) + { + $(arr[i]).value = ""; + } + SaveValues(); + CreateTransaction(); +}; + +function StartEditTransactionJSON() +{ + var Item = $("idTransaction"); + Item.className = "smallbold"; +}; + +function EditJSONTransaction() +{ + var name = "edit_transaction"; + var Item = $("idTransaction"); + if(IsVisibleBlock(name)) + { + SetVisibleBlock(name, false); + Item.className = ""; + } + else + { + CreateTransaction(); + SetVisibleBlock(name, true); + Item.className = ""; + } +}; +var glNumPayCount = 0; + +function GetInvoiceHTML(item,onclick,classstr) +{ + if(!item.num) + { + glNumPayCount++; + item.num = glNumPayCount; + } + var idname = "idSendInvoice" + item.num; + var value = ""; + if(item.Data.Amount) + value += "" + item.Data.Amount + " Tera"; + else + value += "No pay"; + value += " " + item.num + ". " + item.Data.name; + return ""; +}; + +function AddSendList(item) +{ + PayList.push({Data:item}); +}; + +function CheckSendList(bRedraw) +{ + TitleWarning = PayList.length; + if(AttachItem) + TitleWarning++; + var Str = Storage.getItem("InvoiceList"); + if(!Str && !bRedraw) + return ; + if(!bRedraw) + { + SelectTab("TabSend"); + } + if(Str) + { + var arr = JSON.parse(Str); + for(var i = 0; i < arr.length; i++) + { + AddSendList(arr[i]); + } + Storage.setItem("InvoiceList", ""); + } + var idList = $("idSendList"); + if(PayList.length) + { + idList.innerHTML = "
    Select the item you want to sign (pay) and send to blockchain:
    "; + for(var i = 0; i < PayList.length; i++) + { + var item = PayList[i]; + idList.innerHTML += GetInvoiceHTML(item, "UseInvoice(" + i + ")", "btinvoice"); + } + if(AttachItem === undefined) + UseInvoice(0); + } + else + { + idList.innerHTML = ""; + } +}; +setInterval(CheckSendList, 200); + +function UseInvoice(Num) +{ + var item = PayList[Num]; + if(item.Data.From) + $("idAccount").value = item.Data.From; + $("idTo").value = item.Data.To; + $("idSumSend").value = item.Data.Amount; + $("idDescription").value = item.Data.Description; + PayList.splice(Num, 1); + AttachItem = item; + $("idAttach").innerHTML = GetInvoiceHTML(AttachItem, "OpenAttach()", "btinvoice btinvoice_use"); + CheckSendList(1); +}; + +function ClearAttach() +{ + AttachItem = undefined; + if($("idAttach")) + $("idAttach").innerHTML = ""; +}; + +function OpenAttach() +{ + if(AttachItem) + { + var Data2 = JSON.parse(JSON.stringify(AttachItem.Data)); + if(Data2.Body) + Data2.Body = GetHexFromArr(Data2.Body); + delete Data2.TransferSecret; + alert("DATA:\n" + JSON.stringify(Data2, "", 4)); + } +}; +var CURRENCY, PUBKEY, NAME, SMART; + +function SendTrCreateAccWait(Currency,PubKey,Name,Smart) +{ + CURRENCY = Currency; + PUBKEY = PubKey; + NAME = Name; + SMART = Smart; + setTimeout(function () + { + SendTrCreateAcc(CURRENCY, PUBKEY, NAME, 0, SMART, 0, 0); + }, 50); +}; + +function SendTrCreateAcc(Currency,PubKey,Description,Adviser,Smart,bFindAcc,bAddToPay) +{ + var TR = GetTrCreateAcc(Currency, PubKey, Description, Adviser, Smart); + var Body = GetBodyCreateAcc(TR); + TR.bFindAcc = 1; + if(bAddToPay) + { + var Item = {name:Description, To:0, Amount:CONFIG_DATA.PRICE_DAO.NewAccount, Description:"Create acc: " + Description, Body:Body, + }; + AddToInvoiceList(Item); + } + else + { + SendTransaction(Body, TR); + } + $("idAccountName").value = ""; + CancelCreateAccount(); +}; + +function ChangeSmart(NumAccount,WasSmart) +{ + if(!IsPrivateMode()) + { + SetError("Pls, open wallet"); + return 0; + } + var Result = prompt("Enter smart number:", WasSmart); + if(Result !== null && Result != WasSmart) + { + var Smart = parseInt(Result); + if(Smart) + { + GetData("GetDappList", {StartNum:Smart, CountNum:1}, function (Data) + { + if(Data && Data.result && Data.arr.length === 1) + { + SetSmartToAccount(NumAccount, Smart); + } + else + { + SetError("Error smart number"); + } + }); + } + else + { + SetSmartToAccount(NumAccount, Smart); + } + } +}; + +function SetSmartToAccount(NumAccount,Smart) +{ + var OperationID = 0; + var Item = MapAccounts[NumAccount]; + if(Item) + { + OperationID = Item.Value.OperationID; + } + OperationID++; + var TR = {Type:140, Account:NumAccount, Smart:Smart, FromNum:NumAccount, Reserve:[], OperationID:OperationID, Sign:"", }; + var Body = []; + WriteByte(Body, TR.Type); + WriteUint(Body, TR.Account); + WriteUint32(Body, TR.Smart); + WriteArr(Body, TR.Reserve, 10); + WriteUint(Body, TR.FromNum); + WriteUint(Body, TR.OperationID); + SendTrArrayWithSign(Body, TR.Account, TR); +}; + +function CheckLengthAccDesription(name,Length) +{ + var Str = $(name).value.substr(0, Length + 1); + var arr = toUTF8Array(Str); + var Len = Length - arr.length; + if(Len < 0) + SetError("Bad length"); + else + SetStatus("Lost: " + Len + " bytes"); +}; diff --git a/src/HTML/JS/wallet-node.js b/src/HTML/JS/wallet-node.js new file mode 100644 index 0000000..00d6a4b --- /dev/null +++ b/src/HTML/JS/wallet-node.js @@ -0,0 +1,542 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + + +function SavePrivateKey() +{ + var Select = document.getElementById("idTypeKey"); + if(Select.value === "brain") + { + ConvertToPrivateKey(); + return ; + } + var Str = document.getElementById("idKeyNew").value; + Str = Str.trim(); + if(Select.value === "private" && (Str.length !== 64 || !IsHexStr(Str))) + { + SetError("Error: Length must 64 HEX chars. (Length=" + Str.length + ")"); + return ; + } + else + if(Select.value !== "private" && (Str.length !== 66 || Str.substr(0, 1) !== "0" || !IsHexStr(Str))) + { + SetError("Error: Length must 66 HEX chars. (Length=" + Str.length + ")"); + return ; + } + if(Select.value === "private" && PrivKeyStr !== Str) + SetStatus("Changed privat key"); + else + if(Select.value === "public" && PubKeyStr !== Str) + SetStatus("Changed public key"); + GetData("SetWalletKey", Str, function (Data) + { + if(Data && Data.result === 1) + { + if(Select.value === "private") + SelectStyle("styleContrast1"); + else + if(Select.value === "public") + SelectStyle("styleContrast2"); + SetVisibleEditKeys(0); + UpdatesData(); + } + }); +}; + +function CreateCheckPoint() +{ + if(!ServerBlockNumDB || ServerBlockNumDB < 16) + { + SetError("Not set ServerBlockNumDB"); + return ; + } + var BlockNum = ServerBlockNumDB - 10; + SetCheckPoint(BlockNum); +}; + +function UseAutoCheckPoint() +{ + var Set = $("idUseAutoCheckPoint").checked; + var Period = ParseNum($("idPeriodAutoCheckPoint").value); + GetData("SetAutoCheckPoint", {Set:Set, Period:Period}, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function UseAutoCorrTime() +{ + GetData("SetAutoCorrTime", document.getElementById("idUseAutoCorrTime").checked, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function SetCodeVersionJSON() +{ + var Data = JSON.parse(JSON.stringify(CONFIG_DATA.CODE_VERSION)); + if(!Data.BlockNum) + { + Data.LevelUpdate = 160; + } + Data.BlockNum = CONFIG_DATA.CurBlockNum; + Data.addrArr = GetHexFromArr(Data.addrArr); + Data.Hash = GetHexFromArr(Data.Hash); + Data.Sign = GetHexFromArr(Data.Sign); + Data.Hash = undefined; + Data.Sign = undefined; + Data.StartLoadVersionNum = undefined; + var Str = JSON.stringify(Data, "", 2); + document.getElementById("idDevService").value = Str; +}; + +function SetCorrTimeJSON() +{ + var AutoDelta = parseInt(document.getElementById("idDevValue").value); + var Data = {Num:CONFIG_DATA.CurBlockNum, bUse:1, bAddTime:1}; + if(AutoDelta < 0) + { + AutoDelta = - AutoDelta; + Data.bAddTime = 0; + } + Data.DeltaTime = 40; + Data.StartBlockNum = ServerCurBlockNum + 10; + Data.EndBlockNum = Data.StartBlockNum + Math.floor(AutoDelta / Data.DeltaTime); + var Str = JSON.stringify(Data, "", 2); + document.getElementById("idDevService").value = Str; +}; + +function SetNetConstJSON() +{ + var Str = JSON.stringify(Data, "", 2); + document.getElementById("idDevService").value = Str; + var Data = {MaxTrasactionLimit:CONFIG_DATA.MAX_TRANSACTION_LIMIT}; + var Str = JSON.stringify(Data, "", 2); + document.getElementById("idDevService").value = Str; +}; + +function SetNewCodeVersion() +{ + try + { + var Data = JSON.parse(document.getElementById("idDevService").value); + } + catch(e) + { + SetError("Error format setting data"); + return ; + } + Data.addrArr = GetArrFromHex(Data.addrArr); + GetData("SetNewCodeVersion", Data, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function StartTimeCorrect() +{ + try + { + var Data = JSON.parse(document.getElementById("idDevService").value); + } + catch(e) + { + SetError("Error format setting data"); + return ; + } + GetData("SetCheckDeltaTime", Data, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function StartNetConst() +{ + try + { + var Data = JSON.parse(document.getElementById("idDevService").value); + } + catch(e) + { + SetError("Error format setting data"); + return ; + } + GetData("SetCheckNetConstant", Data, function (Data) + { + if(Data) + { + SetStatus(Data.text, !Data.result); + } + }); +}; + +function RestartNode() +{ + GetData("RestartNode", {}); + DoRestartWallet(); +}; + +function UseAutoUpdate() +{ + var Data = {USE_AUTO_UPDATE:document.getElementById("idAutoUpdate").checked, DoMining:1}; + GetData("SaveConstant", Data, function (Data) + { + if(Data && Data.result) + { + SetStatus("Save AutoUpdate: " + document.getElementById("idAutoUpdate").checked); + } + }); +}; + +function UseMining() +{ + if(!MiningAccount) + { + SetError("Not set mining account"); + return ; + } + var Data = {USE_MINING:document.getElementById("idUseMining").checked, DoMining:1}; + GetData("SaveConstant", Data, function (Data) + { + if(Data && Data.result) + { + SetStatus("Save Mining: " + document.getElementById("idUseMining").checked); + } + }); +}; + +function SetPercentMining() +{ + var Data = {POW_MAX_PERCENT:document.getElementById("idPercentMining").value}; + GetData("SaveConstant", Data, function (Data) + { + if(Data && Data.result) + { + SetStatus("Save Mining percent: " + document.getElementById("idPercentMining").value + " %"); + } + }); +}; + +function MiningSets() +{ + var name = "edit_mining_set"; + if(IsVisibleBlock(name)) + { + SetVisibleBlock(name, false); + } + else + { + SetVisibleBlock(name, true); + document.getElementById("idMiningAccount").value = MiningAccount; + document.getElementById("idMiningAccount").focus(); + } +}; + +function SaveMiningSet(Value) +{ + SetVisibleBlock("edit_mining_set", false); + if(Value) + { + MiningAccount = Value; + } + else + { + MiningAccount = ParseNum(document.getElementById("idMiningAccount").value); + } + GetData("SetMining", MiningAccount, function (Data) + { + }); +}; + +function CancalMiningSet() +{ + var name = "edit_mining_set"; + SetVisibleBlock(name, false); +}; +var WasHistoryMaxNum; +var WasLastNumSound = 0; + +function CheckNewMoney() +{ + return ; + if(!$("idUseSoundHistory").checked) + return ; + if(WasHistoryMaxNum === HistoryMaxNum || !ServerBlockNumDB) + return ; + WasHistoryMaxNum = HistoryMaxNum; + GetData("GetHistoryAct", {StartNum:HistoryMaxNum - 40, CountNum:40}, function (Data) + { + if(Data && Data.result) + { + var arr = Data.arr; + for(var i = 0; i < arr.length; i++) + { + var Item = arr[i]; + if(Item.Direct === "+" && Item.BlockNum > ServerBlockNumDB - 60 && Item.BlockNum < ServerBlockNumDB - 20 && Item.BlockNum > WasLastNumSound) + { + WasLastNumSound = Item.BlockNum; + $("sound_coin").play(); + } + } + } + }); +}; + +function DoRestartWallet() +{ + SetStatus("

    Restarting program...

    "); + if(!WasSetRestart) + { + WasSetRestart = 1; + setTimeout(function () + { + window.location.reload(); + }, 10 * 1000); + } +}; + +function SetArrLog(arr) +{ + var Str = ""; + var bFindAccount = 0; + for(var i = 0; i < arr.length; i++) + { + var Item = arr[i]; + var tr_text = GetTransactionText(MapSendTransaction[Item.key], Item.key.substr(0, 16)); + var info = Item.text; + if(tr_text) + info += " (" + tr_text + ")"; + if(Item.final) + { + var TR = MapSendTransaction[Item.key]; + if(TR) + { + if(Item.text.indexOf("Add to blockchain") >= 0) + { + if(TR.bFindAcc) + { + bFindAccount = 1; + TR.bFindAcc = 0; + } + if(TR.Run) + { + TR.Run(TR); + TR.Run = undefined; + } + } + } + var Account = MapCheckTransaction[Item.key]; + if(Account) + { + delete MapCheckTransaction[Item.key]; + Account.NextSendTime = 0; + } + } + Str = Str + info + "\n"; + } + SetStatusFromServer(Str); + CheckSending(); + if(bFindAccount) + { + FindMyAccounts(); + } +}; + +function SetAutoMining() +{ + setTimeout(function () + { + var Select = $("idAccount"); + if(Select.options.length) + { + SaveMiningSet(Select.options[Select.options.length - 1].value); + } + }, 100); +}; + +function ViewNetworkMode() +{ + if(IsVisibleBlock('idNetworkView')) + { + SetVisibleBlock('idNetworkView', false); + } + else + { + SetVisibleBlock('idNetworkView', true); + var Mode = CONFIG_DATA.CONSTANTS.NET_WORK_MODE; + if(!Mode) + { + Mode = {}; + Mode.UseDirectIP = true; + if(INTERNET_IP_FROM_STUN) + Mode.ip = INTERNET_IP_FROM_STUN; + else + Mode.ip = SERVER_IP; + Mode.port = SERVER_PORT; + } + document.getElementById("idUseDirectIP").checked = Mode.UseDirectIP; + document.getElementById("idIP").value = Mode.ip; + document.getElementById("idPort").value = Mode.port; + if(!Mode.NodeWhiteList) + Mode.NodeWhiteList = ""; + document.getElementById("idNodeWhiteList").value = Mode.NodeWhiteList; + } +}; + +function SetNetworkParams(bRestart) +{ + var Mode = {}; + Mode.UseDirectIP = document.getElementById("idUseDirectIP").checked; + Mode.ip = document.getElementById("idIP").value; + Mode.port = ParseNum(document.getElementById("idPort").value); + Mode.NodeWhiteList = document.getElementById("idNodeWhiteList").value; + Mode.DoRestartNode = bRestart; + GetData("SetNetMode", Mode, function (Data) + { + if(Data && Data.result) + { + SetStatus("Set net work params OK"); + SetVisibleBlock('idNetworkView', false); + } + }); + if(bRestart) + DoRestartWallet(); +}; + +function ViewConstant() +{ + if(IsVisibleBlock('idConstantView')) + { + SetVisibleBlock('idConstantView', false); + } + else + { + SetVisibleBlock('idConstantView', true); + document.getElementById("idConstant").value = JSON.stringify(CONFIG_DATA.CONSTANTS, "", 2); + } +}; + +function SaveConstant(bRestart) +{ + try + { + var Data = JSON.parse(document.getElementById("idConstant").value); + } + catch(e) + { + SetError("Error JSON format setting constant"); + return ; + } + Data.DoRestartNode = bRestart; + GetData("SaveConstant", Data, function (Data) + { + if(Data && Data.result) + { + SetStatus("Save Constant OK"); + SetVisibleBlock('idConstantView', false); + } + }); + if(bRestart) + DoRestartWallet(); +}; + +function ViewRemoteParams() +{ + if(IsVisibleBlock('idRemoteView')) + { + SetVisibleBlock('idRemoteView', false); + } + else + { + SetVisibleBlock('idRemoteView', true); + if(CONFIG_DATA.HTTPPort) + document.getElementById("idHTTPPort").value = CONFIG_DATA.HTTPPort; + document.getElementById("idHTTPPassword").value = CONFIG_DATA.HTTPPassword; + } +}; + +function SetRemoteParams(bRestart) +{ + var PrevHTTPPassword = HTTPPassword; + var HTTPPort = ParseNum(document.getElementById("idHTTPPort").value); + var HTTPPassword = document.getElementById("idHTTPPassword").value; + GetData("SetHTTPParams", {HTTPPort:HTTPPort, HTTPPassword:HTTPPassword, DoRestartNode:bRestart}, function (Data) + { + if(!PrevHTTPPassword && HTTPPassword) + window.location.reload(); + else + { + SetVisibleBlock('idRemoteView', false); + SetStatus("Set HTTP params OK"); + } + }); + if(bRestart) + DoRestartWallet(); +}; + +function RewriteAllTransactions() +{ + DoBlockChainProcess("RewriteAllTransactions", "Rewrite all transactions", 0); +}; + +function RewriteTransactions() +{ + DoBlockChainProcess("RewriteTransactions", "Rewrite transactions on last %1 blocks", 1); +}; + +function TruncateBlockChain() +{ + DoBlockChainProcess("TruncateBlockChain", "Truncate last %1 blocks", 1); +}; + +function ClearDataBase() +{ + DoBlockChainProcess("ClearDataBase", "Clear DataBase", 0); +}; + +function CleanChain() +{ + DoBlockChainProcess("CleanChain", "Clean chain on last %1 blocks", 1); +}; + +function DoBlockChainProcess(FuncName,Text,LastBlock) +{ + SaveValues(); + var Params = {}; + if(LastBlock) + { + Params.BlockCount = ParseNum(document.getElementById("idBlockCount").value); + Text = Text.replace("%1", Params.BlockCount); + } + var result = confirm(Text + "?"); + if(!result) + return ; + SetVisibleBlock("idServerBlock", 1); + SetStatus("START: " + Text); + GetData(FuncName, Params, function (Data) + { + if(Data) + { + SetStatus("FINISH: " + Text, !Data.result); + } + }); +}; diff --git a/src/HTML/JS/wallet-web.js b/src/HTML/JS/wallet-web.js new file mode 100644 index 0000000..c582e93 --- /dev/null +++ b/src/HTML/JS/wallet-web.js @@ -0,0 +1,276 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var MIN_VERSION = 1020; +var COUNT_BLOCK_PROOF = 300; +var MIN_SUM_POWER = COUNT_BLOCK_PROOF * 35; +var MainServer = undefined; +var MaxConnectedCount = 10; +var MaxTimeConnecting = 3 * 1000; +var StartTimeConnecting = 0; +var ConnectedCount = 0; +var NETWORK = "TERA-MAIN"; +var ServerMap = {}; +var ServerMainMap = {"127.0.0.1":{"ip":"127.0.0.1", "port":80, "Name":"LOCAL"}, "terafoundation.org":{"ip":"terafoundation.org", + "port":443, "Name":"TERA", "System":1}, "dappsgate.com":{"ip":"dappsgate.com", "port":80, "Name":"SUPPORT2", "System":1}, "t1.teraexplorer.com":{"ip":"t1.teraexplorer.com", + "port":80, "Name":"t1.teraexplorer.com", "System":1}, "t2.teraexplorer.com":{"ip":"t2.teraexplorer.com", "port":80, "Name":"t2.teraexplorer.com", + "System":1}, "t3.teraexplorer.com":{"ip":"t3.teraexplorer.com", "port":80, "Name":"t3.teraexplorer.com", "System":1}, "t4.teraexplorer.com":{"ip":"t4.teraexplorer.com", + "port":80, "Name":"t4.teraexplorer.com", "System":1}, "t5.teraexplorer.com":{"ip":"t5.teraexplorer.com", "port":80, "Name":"t5.teraexplorer.com", + "System":1}, }; +var ServerTestMap = {"127.0.0.1":{"ip":"127.0.0.1", "port":80, "Name":"LOCAL"}, "dappsgate.com":{"ip":"dappsgate.com", "port":88, + "Name":"SUPPORT2", "System":1}, }; + +function StartWebWallet() +{ + if(NETWORK === "TERA-TEST2") + { + MIN_SUM_POWER = 0; + ServerMap = ServerTestMap; + } + else + { + MIN_SUM_POWER = COUNT_BLOCK_PROOF * 35; + ServerMap = ServerMainMap; + } + $("idNetwork").innerText = NETWORK; + OnInitWebWallet(); + ConnectWebWallet(); +}; + +function OnInitWebWallet() +{ + var str = Storage.getItem(NETWORK + "NodesArrayList"); + if(str) + { + var arr = JSON.parse(str); + for(var i = 0; i < arr.length; i++) + { + var Item = ServerMap[arr[i].ip]; + if(Item && Item.System) + continue; + ServerMap[arr[i].ip] = arr[i]; + } + } +}; + +function SaveServerMap() +{ + var arr = []; + for(var key in ServerMap) + { + var Item = ServerMap[key]; + if(Item.SumPower >= MIN_SUM_POWER) + { + arr.push({ip:Item.ip, port:Item.port}); + } + } + Storage.setItem(NETWORK + "NodesArrayList", JSON.stringify(arr)); +}; + +function SetStatus(Str) +{ + var id = $("idStatus"); + id.innerHTML = Str; + if(Str) + console.log(id.innerText); +}; + +function SetError(Str,bNoSound) +{ + SetStatus("
    " + Str + "
    "); +}; +var CountConnect = 0; +var CountWallet = 0; + +function ConnectWebWallet() +{ + StartTimeConnecting = Date.now(); + ConnectedCount = 0; + for(var key in ServerMap) + { + var Item = ServerMap[key]; + Item.SendHandShake = 0; + } + if(window.BrowserIE && !IsLocalClient()) + { + MainServer = undefined; + return ; + } + CountConnect = 0; + CountWallet = 0; + SetStatus("Connecting..."); + LoopHandShake(); + setTimeout(LoopWalletInfo, 1500); +}; +var Stage = 0; + +function LoopHandShake() +{ + Stage++; + SetStatus("Connecting: " + Stage + "..."); + for(var key in ServerMap) + { + var Item = ServerMap[key]; + if(Item.SendHandShake || !Item.port) + continue; + CountConnect++; + if(window.BrowserIE && CountConnect > 4) + break; + DoNodeList(Item); + } +}; + +function DoNodeList(Item) +{ + console.log(GetProtocolServerPath(Item) + "/GetNodeList"); + if(window.location.protocol === "https:" && Item.port !== 443) + return ; + if(Item.port === 443 && IsIPAddres(Item.ip)) + return ; + SetStatus("Try: " + Item.ip + ":" + Item.port); + Item.SendHandShake = 1; + GetData(GetProtocolServerPath(Item) + "/GetNodeList", {}, function (Data) + { + if(Data && Data.result && Data.NETWORK === NETWORK && Data.VersionNum >= MIN_VERSION) + { + ConnectedCount++; + Item.GetHandShake = 1; + Item.BlockChain = Data.BlockChain; + SetStatus("Get: " + Item.ip + ":" + Item.port); + var bWas = 0; + for(var i = 0; i < Data.arr.length; i++) + { + var Node = Data.arr[i]; + if(!ServerMap[Node.ip] && Node.port) + { + ServerMap[Node.ip] = Node; + console.log("New: " + Node.ip + ":" + Node.port); + bWas = 1; + } + } + if(bWas && ConnectedCount < MaxConnectedCount && new Date() - StartTimeConnecting < MaxTimeConnecting) + { + setTimeout(LoopHandShake, 100); + } + } + }); +}; + +function LoopWalletInfo() +{ + SetStatus("Get wallets info..."); + for(var key in ServerMap) + { + var Item = ServerMap[key]; + if(Item.port) + { + CountWallet++; + if(window.BrowserIE && CountWallet > 4) + break; + DoWalletInfo(Item); + } + } + setTimeout(FindLider, 500); +}; + +function DoWalletInfo(Item) +{ + if(window.location.protocol === "https:" && Item.port !== 443) + return ; + if(Item.port === 443 && IsIPAddres(Item.ip)) + return ; + Item.StartTime = Date.now(); + Item.SendWalletInfo = 1; + GetData(GetProtocolServerPath(Item) + "/GetCurrentInfo", {BlockChain:1}, function (Data) + { + if(Data && Data.result && Data.BlockChain && Data.NETWORK === NETWORK) + { + Item.Name = Data.NODES_NAME; + Item.GetWalletInfo = 1; + Item.DeltaTime = new Date() - Item.StartTime; + Item.BlockChain = Data.BlockChain; + Item.MaxNumBlockDB = Data.MaxNumBlockDB; + console.log("Get: " + Item.ip + ":" + Item.port + " delta=" + Item.DeltaTime); + } + }); +}; + +function FindLider() +{ + MainServer = undefined; + var Arr = []; + var MapSumPower = {}; + for(var key in ServerMap) + { + var Item = ServerMap[key]; + if(Item.GetWalletInfo && Item.BlockChain) + { + var arr = Item.BlockChain; + if(arr.data) + arr = arr.data; + Item.SumPower = CalcPowFromBlockChain(arr); + if(Item.SumPower < MIN_SUM_POWER) + { + console.log("Skip: " + Item.ip + ":" + Item.port + " SumPower(" + Item.SumPower + ") < MIN_SUM_POWER(" + MIN_SUM_POWER + ")"); + continue; + } + if(!MapSumPower[Item.SumPower]) + MapSumPower[Item.SumPower] = 0; + MapSumPower[Item.SumPower]++; + Arr.push(Item); + } + } + var Max = 0, MaxKey; + for(var key in MapSumPower) + { + if(MapSumPower[key] >= Max) + { + Max = MapSumPower[key]; + MaxKey = parseInt(key); + } + } + Arr.sort(function (a,b) + { + return a.DeltaTime - b.DeltaTime; + }); + for(var i = 0; i < Arr.length; i++) + { + var Item = Arr[i]; + if(Item.SumPower === MaxKey) + { + SetStatus("Find " + Item.ip + ":" + Item.port + " with pow=" + Item.SumPower + "/" + MaxKey + " ping=" + Item.DeltaTime); + MainServer = Item; + SaveServerMap(); + break; + } + } + OnFindServer(); +}; + +function CalcPowFromBlockChain(BufRead) +{ + var Sum = 0; + var Arr = GetBlockArrFromBuffer(BufRead); + if(Arr.length === COUNT_BLOCK_PROOF) + { + for(var i = 0; i < Arr.length; i++) + { + Sum += Arr[i].Power; + } + } + return Sum; +}; + +function SetAllSum() +{ + var Item = MapAccounts[$("idAccount").value]; + if(Item) + $("idSumSend").value = FLOAT_FROM_COIN(Item.Value).toStringF(); +}; diff --git a/src/HTML/PIC/B.svg b/src/HTML/PIC/B.svg new file mode 100644 index 0000000..592a4ec --- /dev/null +++ b/src/HTML/PIC/B.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/HTML/PIC/T.svg b/src/HTML/PIC/T.svg new file mode 100644 index 0000000..54360bb --- /dev/null +++ b/src/HTML/PIC/T.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/HTML/PIC/TeraLogo.svg b/src/HTML/PIC/TeraLogo.svg new file mode 100644 index 0000000..e3b819b --- /dev/null +++ b/src/HTML/PIC/TeraLogo.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/HTML/PIC/Tera_logo.svg b/src/HTML/PIC/Tera_logo.svg new file mode 100644 index 0000000..15a5801 --- /dev/null +++ b/src/HTML/PIC/Tera_logo.svg @@ -0,0 +1,6 @@ + + + Logo2 + + + diff --git a/src/HTML/PIC/Tera_logo2.svg b/src/HTML/PIC/Tera_logo2.svg new file mode 100644 index 0000000..c3edbad --- /dev/null +++ b/src/HTML/PIC/Tera_logo2.svg @@ -0,0 +1,6 @@ + + + Logo2 + + + diff --git a/src/HTML/PIC/add-icon.svg b/src/HTML/PIC/add-icon.svg new file mode 100644 index 0000000..11f385d --- /dev/null +++ b/src/HTML/PIC/add-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/HTML/PIC/address_book.png b/src/HTML/PIC/address_book.png new file mode 100644 index 0000000000000000000000000000000000000000..335b270f26d9fd0c86557bed59880bec876aedb5 GIT binary patch literal 2608 zcmV-03eWY4P)kQS5v|l#sgA8v1#6ww4z;xo6=@wBEir`bdx_A1v``RR zTfiwwHZ_~D`%eGZw{clR0t>``XYS0q_ndR@Is5KC_nh-qRF$D1A|{bYd|5=U2hIRS z4JlL}b^#kis?)o=x*i*fZ_qa|Y0{+Q!!X%nYC=qN#{%RMnS#-+$j)`$OQC z;nn%W5Rs=+snpf|{qf_+kBr4)%Ye`BLuQrl`_o+4Jw-$|4U3jTKvic4L9i6Sj2JQE zd+b|zfT@j*jqz+Y`|n}Vt^^|D1I;C4-zhvB5&7I8@*(hKb8~aLs;X-IVbXC>sOtJ4 z2&MrWi-srE*4B=I{GmLqh;TD7rKla}`~D3gBC2}ta4B61RaFsLRy0&OYSgGt0XRS_ zFaw~fs_LgLEiF9-uG-q#5!Tv9*LCk@@NIV3p{ikVKbOlH0LK_}Ul@kdfRVkuy?%mOeVkB-QB%XRi~9}fQb~p%UZidL^g=XY7tpY{&4TG z*8U{&0(TA|zo4MJ=XvL6v)K;dR^V7*r>eF9g=q3CQh7qR8vz^Rzzk4 z+sihF#+zpJ`hk@5NHa5n4dU`gL&^BZ;nS}t>+6z>51^L6;qN*3i@T_ibZcbNMSC<~Rd7Yh|eThWk z7~tt>uD?`QS5FUuU|CaBQx?GY{XIbttcb_s7Zt`-^;A`z?s=XCa2#g|u%{dY9N@H~ z{_lV_(Q|(=7cF{25#Ki7_nQDj0|GP657JNt?mthFC=U3YSzTSd6<7i=apJ_IDk>^YjeeBrr4)z$TDfZpETiwl=tSq6BXccH3&mAuzDvWUJ>M1GJ; zr51ahcZ;en2MELP1YisB7J!IM<%1ybMfMIm9_;AocoV={dou8G;7wJ%WYeZiz1G^% zBJyBa+5^V(yo*)!Me<4ektOugRP~{{y1FB>+3f0~@d=S3t-$+0V}Y<|&z_%)$O>RR zaFg%*{WrKVW)$$KF=kqOd;2?)@egwl(WwJ`i^wbN1KZcFTi4@x-l#C_cNCWak9Tx* zyl1WbC2*~^_730o7pz^ob|-M*KohmKwWWX*$UT=#Ca1ps`s;5e5{a3{n3q)b z(O4{YzqR&NpcWVh5QgCeuIsKAksUyTh@7OV>s8hBeSdRg?4oiEFu)6iPESwINyS9h zb+542Hb-aVh!WZQbUOVAKzn=pTE}rt10Djpfr|>tN2n5!&ydf?j#JfVGMUVjAP6=` z>s$xiRE_~o5Cr$Qu6qpm*SW}Ad#UgH?*oX)`M}wO$j`Ob{xcqrf4{Z0wF{UJ%&)7f zJGQd2vOY>7&s5b6uw7L*hGF<(M@Pqd(fr0*J6A*=Ek}6(CrXyTan@O9-Ck8y)nJTi z5RsLd$8U@=qf~V!`z|ZqlTN4SdY*Upm@#91wsh&zTy&8C7_|Z6y6!oy>;6bpCzh)` z>_=@Bz*;*QSkBPj1^y}`zY4=}GqBlloK0)itoctenT(~==~@vP2aHqIDde}={@`if z_vct^9{|2xG=948`x_nTPX#X{f06aqM#*1fPx`+9n&)}9sp?_|$2e8Jt8lC4ayhKE zY4YdC9C)2zXgG;P;tXR}t*of1 z=o^IRBZC2^7WH$$?x?*7w5sYiTUuIr!Z2(cXo6wDp!?1N`b&u-QXkcb_CkGq{fUm_ zJX|_HO!&uOLQqsI08K zV=tmH^HlXVJ|g9TEq#4`gO(~yOH0eHAPBrL49^phw6*pU`5?O}tJHCbkX6+=YuB#* z?_f+0^p~zzMy(j_ACedztOKqJf?&w?oxzAAvT7ff&qDHE>X1TJcZi5TcI?;<1AL{g zDemNQxeN>uN{EQKuDgyX11rMQnM`J0NwMm%AqoyRlCQ4<><)t9XjRoAW1&PMQD=;4 zLLSRZX&Yd1txr`!iubgE`lAZ;o=;{|97%iN5b|g#G;T9t6Q6 z5t+e3l)(=X(yBVApgip78z{h9I~tfvKFMj|gFSgTkpngWYjU~VeT5QD0sjM7U>TB! SHi$w10000 + + + diff --git a/src/HTML/PIC/chains.png b/src/HTML/PIC/chains.png new file mode 100644 index 0000000000000000000000000000000000000000..9d6504103886b9d484061ac0b66dd1dc15fd6a60 GIT binary patch literal 1617 zcmV-X2Cn&uP)) zdH|Aj7dR(qastQ+peIN;fx`&`i>@&T=nzf-EV^!bgG$3Qb%gcwEX#>4y*Hy_3aO*K zPw(&3lX4KT>{Sj}1q=WKz`_7904xju1Hi%nFaRtJ00Y3n05Aaimajj555$Ol2cXvy zW%tF8M2u50hGO)UmpqG+iE;bu+vghwz^&rX#W*Wbx=th*Ghcw{?NRvy@go&uVEKq8 z0I^{Jsw+PM<@akoYAwd7%OD)=LHW|k9_?EslZ#o867m_3O1UoM9OJJAQEN7G8Uq0QvMw0UiI1_#T++PwGGsfd!D$}a1^{ux6rTF?m$c&y5 zi?Pj&QsO+E^qscS0!l0*j{a{?=IP*qxKeFo>!_1>{wgZpq1&<;8~M-$0AQu(MOap7 z{5sB8s`#DUL37plmMHOM3JYLRVli*?@WurZL;^r1)@ra=_K;06y~?0K@UrGGdL=;v(Hv z)w_qTkUGMjN*Jk-FQeBkhO#VXq*Sv*SeZ$QzrVHRb;NU@G%k^J5~tGu)S(Gvz;SP-*4@+q)x2kv#fPpT^ zDGN!eEfCrw1`rdM$`1(u%I&=y$e!*CDWrV;i9zx2Zfaow^dLM%Zg2CFnbx?@)i=R> ziI1V*(?+DyYu{BJj0F%=NUAuyER3s9_K7?tmmmHGN> zEK_0t>Idlju(qoBb=SU=fQ4fK1Hi%nFaRtJ00Y3n05AY73_yG3p8x{@brjpV + + diff --git a/src/HTML/PIC/console.png b/src/HTML/PIC/console.png new file mode 100644 index 0000000000000000000000000000000000000000..7934e0394b8c622fccef181e3428487956ace5f6 GIT binary patch literal 821 zcmV-51Iqk~P)U zF(gP;lUTvN>p;((FXvwsTR+K){cOMYz3<+87X$x0$TXasoP0{t^dk{5-7ckEIc#{(ifPxeBHr#6z5$n;TqSUSc+zC2<^|6Vcm)gM)dI zAID;2Qc8@+k;g*c9x5aPvTGWiPNjg0`a8EwIdC>PAU*5P>`7-Qg^qu=kdPN(zw@bK`1?b%WV zRPd{-D=e4GEU-?Hh~T;|wzszd0C5~+b8{1|RtvuGA z0zwE7QI@&y`?=sI0UdXDceuX3MifN=fFwzfrYVvnaio+HjKVKfKsi?mC_*MY&%@5n zPDZxZ>tQ;bW{EhC1J`wNc6PS%ZXp38%FdMnde(}FjZnMYMyJ!s*}C1X^;ugR=0HRk zjYev?+4w!=;X|LvZ0iKaukMPF5|LR)Vl|G98g7s3YUN}mc2Y0jc|W|p9@yj zhQLEz1VOMus5Suw#u$Piu+D)xQ&GRyNC6d`h*su+8PG<=bzKBOkXr&93g>_h-}iIU zo9$R8vwp9U0(wBDfGzW)mgJlx48!IM*j~^lp`N|UuC4;L20O|ls(VERs1&F| z_N=P>(_WzeyH!vlwMq2@`5mb#?b9{t1_vCDoSm$5&(D^f%$ws|8{zM`cAdnQz1=LESJmg z0CHbRwmJG7z_Y*SL{&$B0+q$|K|rc!4A+iF`wfBS1*RT=wJx z2!So|uH%p0nc3;?%3)^Ovum$Oq(ofOQmbpaXS)9NuaE8#RpoOw^I5h34**C2e*Wdx ze*K!^a2Ty#)PfJK7%-;{6h*J`p8I-L&AIquxK!<#p67z_qj zYiC>maCmsg+qZAY^ZY`^5kRO?_e>1z@9(p>w^tP&V<^iK=N$X{`<$Gd;JuHrAR>70 z+1=gclb z5o_Gj?rpZvhJgqm0jd(}y^n#@?!8_wDpu8|oFXFh`~4Z^^8mc}c<*t})eKhaUfT=^ zbkj7}^QNXZN}KMSV>ld==Q+JzFZz2C0PlSq%d*5f2O{|3+YH!fW#jvJsI-(%CKHa1 zjxffsy1F`}ybWTW{)T~0r-Lg?M5NAwItZJM(rz~bXoFBy#^W(XQADeoZ`uXsBKjK_ zl-43hTu*=)*}Yy5Yc1B=nJmb%3}Xx{D=RaswA*2wOnY$Xgnpj!E}C<*{N zolZo&2tXS|Tlpe@&Ae*OP?LtvIjl8&`^`7lBq6DLQ~S@$jCSy9rQw1s2zX!BfO0ye z-@k`D1%~c=hVl%j;Lx>#J5>xq_mce??o^nV+k`g%HS#f+Ek^9}YP_J|0{9B0{&@?f<^DB?-XRZ(HB5U0(YlvB{FErm7(gs$Es> zsH#OVriE)U+9KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=00004XF*Lt006O$eEU(80000WV@Og>004R=004l4008;_004mL004C` z008P>0026e000+nl3&F}0002&Nkl5Ujcr`X@Va7Q)mn#3;`DOki23@& zIdiknkGUJl62GRlCp-3f<7ztX`WA=h4*JlI7+2E>497K$Ik%9Sev@VTEqk6=>O~=t z4TfV{< z8viH?Bp?v^h*Y@Kh91)1-pA}Xv)5gw-Mibna=e!}JNv$KGta!wJMYXA#u$WbZ?Es? zk9w3&&U5`Tv~y_BOou(E5F!D%v2Dj-C1d6+=3+>j6h?9qH^#?tC3*=y_%ZU+;dm^X zXyqUVoe2q<2EZo|lS)j0(&Vg`YjWTz4#1$-5l|E?S-cWsv8aCL__1(kOC4kovMBOP zI-THy#Al`HlmVJFkes-QXyg*c#zs-Q>^UrYvR1FEE*BsgvjOnUg|TfcLLuK(6j)4IC21y$S9~`TEH}>AQ4bS z*9Y=YU^+Pv-q}^;E};DH)S_TcMJ1BSG3fdnBz=+0@;k zb}Jh8*m;uBw73$|)fp@q0BcMRfRG|eac5Uw$pC!xL7SBm*~)y*2!uLXN*V!i3_~d* z2TGrVL?Fq39NW9#c6IdXHGIBr*kzY5BA#_%$0xg8owvQ;^iWutugP(XZvN_nX`Z5Y9xy0O?8<`rT>W}G`*9MIcGu7 zF4tWW?JaLRZQC!~jJP4?5_6TuEDYp64YxFJbYDHC71(~+_V|KF@Y~7L*fTVYg*A`j z+1jV1NEASUybF2=#>6rse%7Ke;+KE z>QhiDzI7|^-~F|#b92)=r)~RX+d~iDkJnedz-z&`Xlz*H`V3=U-vx4 + + diff --git a/src/HTML/PIC/down.png b/src/HTML/PIC/down.png new file mode 100644 index 0000000000000000000000000000000000000000..1a5eda824ed2fb16e2764992b0944ddcf53caa89 GIT binary patch literal 1785 zcmVDAcUByAdt?Y3!lclI)K zjt@JtnVn2?+t@|O7bfS-f6nB5-~a#T%$!3=2!a1ISgi?Ei%kKw#-@N;V^ct_u_>U| z*c4D}Yzn9~HU-oglAZCufdh`yr%yX?HyJx@*|J4MB9Q_B+l>oZH#Ga-dFuxO@fdC) zu0|*b#vbU{+c9Eos35s--#(AK!TD%YQ?qo}-FKDk1Trd>_qxq|PXrJV00trgW2Ji{ z1_G7pOfSp#tn{3I4E|dP5{dbkYzdj_B(IBcl~-Q*3xu8`FsID z2$X(+auhAW6lQ}ki7=5|tfQiC2m$G0bekkOp{gp9$v%}pXB4IIqfKO%rb#ZVcDozd zgGc+0-uLjsk4X7^9&>-s+C6Iv#uyke5MyA>hynxCJJH8nNGrlv2Tr748Ey1LZ~096VB zVEnR@Ej^=m&?Dvd2awLBapXuZC*YGrwCmgD#=PZwAQA2U34-1o9v%`m(+g+|Z!1r% z<;XA2XR7qD9u=eS(ssb>@c|$l?meh#oS#*)#oa48ZP^!DFwoQ?I3MZj`%Ptxp*0j< zRsbx7O3t-RWRvI3Lh9=q;C8!l?AWllb}dyTuC>duoU2N}u3fu|4kn&hNH1hZj*oCp zqYr+c-<~`c)1hKzDX%=RtTqODK$0Z*JU(2!G=qtWaRTSh$KySJtVDiA0RXUfZ}&8D zdit;P=h^hk6k3{F;c{8$gE_ZNp0Ah-MxV;b%a{WJe-N2$7QMZPIe^dN@$RoyLw;2P z03aUk{1L$W!^1-&olc{zwXI@4kj1-Y@+EDSNvnrLf6nLife}ORk;5wI+Mh0|{^iw@ zU$p=L$YqOhjq|boWS{DANN8ye!T1a@FO8MaFr^SI%ch?9_3nC%j2#nKul}Qf^T+q> z*`xd?0%Tb(IH2vAzd4^99Xrl_UO#+ZAA}IlG!2|{aKTabuW3G1<~{Vhcf#-WJo#UhlPf;7I4eK0iiJI`jbXlvV6_N;-TT0|zB zM!rxelLi)-PQNbz#u$G2^@yfv{Jeu)FRq9Dx�~W1T0eYTAkZ{ytTboM>roUD8Jg zfm}|(Li#2&O*wCm)0$pckvDPyso^8(`8$;nAJdwCYEp*A?3 z_M12(8lDCZu3q~G2M_(s0el^gc7D3v@eNe9Cr(7Wz60>l;NSpPathkQOXq`uP)isN zNkTH&uW`Yra@pbw)r@VR>P>xv+q*|owNuGtzv^+(JP5WV!YaM z4Q$AsB}=Cx{4b;cZY91p@;EoQS?lL_0s;h%pUp*tt+g ztos`RJ{cHH@_aszaCj?PLt#jggn?4t&wx92Zq#@NHuPXi$rg93ns%l?*{{~sx#9Er zF)=ZY)b;C}6Sc?V@r8{X53o5GsuuhAzi|(kWAxs8?sW%(K^hz!0DzYhv91p{bRZpT z5DAcohe9o(&lzKGMNvMLUwge%{}aM;as4vtno$ZN___t?L>(v{ zyV#Z1x^Wr8X#4iU+R#@j2V5G`(@%&B73&1qzpR)k8=o4s$f8T|wRZb#OZ-{ya- b)ENH)Lfo7%`aFX%00000NkvXXu0mjfdhtve literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/glass.svg b/src/HTML/PIC/glass.svg new file mode 100644 index 0000000..426d6b0 --- /dev/null +++ b/src/HTML/PIC/glass.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/HTML/PIC/info.svg b/src/HTML/PIC/info.svg new file mode 100644 index 0000000..e4ac3cb --- /dev/null +++ b/src/HTML/PIC/info.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/HTML/PIC/invoice.png b/src/HTML/PIC/invoice.png new file mode 100644 index 0000000000000000000000000000000000000000..aa1ed4ada388e65dd65dfd7ad3c7558633789633 GIT binary patch literal 1174 zcmV;H1Zn$;P)4TfV{< z8viH?Bp?v^h*Y@Kh91)1-pA}Xv)5gw-Mibna=e!}JNv$KGta!wJMYXA#u$WbZ?Es? zk9w3&&U5`Tv~y_BOou(E5F!D%v2Dj-C1d6+=3+>j6h?9qH^#?tC3*=y_%ZU+;dm^X zXyqUVoe2q<2EZo|lS)j0(&Vg`YjWTz4#1$-5l|E?S-cWsv8aCL__1(kOC4kovMBOP zI-THy#Al`HlmVJFkes-QXyg*c#zs-Q>^UrYvR1FEE*BsgvjOnUg|TfcLLuK(6j)4IC21y$S9~`TEH}>AQ4bS z*9Y=YU^+Pv-q}^;E};DH)S_TcMJ1BSG3fdnBz=+0@;k zb}Jh8*m;uBw73$|)fp@q0BcMRfRG|eac5Uw$pC!xL7SBm*~)y*2!uLXN*V!i3_~d* z2TGrVL?Fq39NW9#c6IdXHGIBr*kzY5BA#_%$0xg8owvQ;^iWutugP(XZvN_nX`Z5Y9xy0O?8<`rT>W}G`*9MIcGu7 zF4tWW?JaLRZQC!~jJP4?5_6TuEDYp64YxFJbYDHC71(~+_V|KF@Y~7L*fTVYg*A`j z+1jV1NEASUybF2=#>6rse%7Ke;+KE z>QhiDzI7|^-~F|#b92)=r)~RX+d~iDkJnedz-z&`Xlz*H`V3=U-vx4F%}`^dys+xwAWS?zwYkb{UT2K){WrrfRGzvCM-g!7z*l@q=U8 zx}6mjm%=_T5V+phSe2ZZc&4bn+*y8R?GrYrlYH;hgBv(h2X)%hhST_3vD6G%&6Q*dtEK>vM_}0A(ZSc2_;@g4 zUemEpNlpfr+YJ+#>ol@4?M6pOVa(-{*vL7uAR!^b5CjR7mXt_S3+0Xkgq$2i1;T~^ z{w-8PK<|OaPoB)`!X?GU5fH$|X^D!8iX;y@9F7oMq+@I(A>gK+gycoJ$&{cr_SfeC z!MgS9B@aG(`ZUC*H1_)LCHVB>Hs1~e0&we|cIwph`Al`Yuez~WUv=ffLDjoJ?p{#4 zE9fz@_@3j3!RztDugRbAb7B%E-IJtdus_%F=sx-GJg9gb&y+yM>TPhj_PnToRy(DD z&*$S9)<+JI`mnd*ObC4Lx)Y@W^n`MYsH7S_W>r$aiwbc6L4kpPt-#xsI{4DnEZT{e z!@-?SU`$9=P{4}{_~jLtz6oDGe;z_Wunl$If_*2C$$7~4(L<=Jsg7QO0{j+GL+p?3 zqK9%YC*{bFhf~1m8XGGxo6VYVXZzsGW~CSh6?lLOoce18>Ra2|F4*mMy~SctC6Tsj zYZwKVO2&!00l%N)*no!t)<-MA&~e{iQ$v{T#FD4_)jQH;I#7LriDC~3R$1-}It0EhHgTsS@5p#T5?07*qoM6N<$f;c@D$p8QV literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/key.png b/src/HTML/PIC/key.png new file mode 100644 index 0000000000000000000000000000000000000000..3cf460e1126ce5c67b2fc0d4166eb4bc6f409e20 GIT binary patch literal 1621 zcmV-b2CDgqP)xa?aXJaW%DaHEUTZf}$c! zMX=xs$c1|^_g=Vgzt1`S-g7U?lr=u?=3y^;;eF3}e$Vs!J-_oFPE}Pr&Wp!mzC`wm zl({P{)+n?)Y4sj33KK}0wdCyIPXQTbo4I|8NeeS4$tksDbG#u)bD=&wa71 zaOFD49cK}9RcpjKPSq6PIT?x^gA$8Ew9kPq?{(Cl{2XnKb%$4cT>TbPVys2TeYN4a z1y-xMtZ-Q=3J&)q*MZ z@wh;;oA}L7EqVj!y$Ct%)4;*&Ac!Kot^rj4>F7Los(H(S(|5MiR=GR9Ju2j=2eRug zJiV|4Z!UiF5UU??i~&%Qb1!A*7eMj+2u{#}qaT%*!SO2YHo0)NzH9q8=kETYZPxL@ zoF`2CvnEVH)K!Ivxur-GxuvvZ7^?z0DjvNk`3O`br}1e2w+Xx;(Og6zqB*37619>u3TX@Y!o@M(*&U4WB?y>^)b%fGsB%q2K^w z;Si*>G^FX$sLrHBL6E?5EQVM#M0F5B(=`X~wfK8h?5HWG#TFV~apcU42pj~y1Nux8 z+_ig&wN)#n$Up$WU=T*xq&Y&3gjmuwr$z>%=ymtOakB$1Pq<}zPcZJlLaP=9X_`Uq5c4|7T|LR;Hd8+V2BLq;adHamJf9?JUwB%K7Wvk#XN;P29XE|!%c z&ry<=3ny8tj~vN{1uvg+*;dI3rNW_|>roz(a3dAm!9%y(cnOon` z6VHgwgb#xsEiYVSHLApXSCV;!mUFYkLd@M-A1~f@ZCR30JPF!4TJYfl;E!&YNz4@j z->rdnU)ihW++?*<2kW689)iGYMcbMLRFm?CMhpIM0Q}MQ55SF?26Qv4naoJfB<5Z> zsw%HTq!*|^tXxPIl{+QJ@@E?@@(Yr1r3$tLo7MjBj~_aKdAH<~lx?sDSNsoRuy0p3u&Dk*(;Qu34qV6;xm zgg$x(zJ_j?Y&MwE3EbI5-9#a99>u$_4>Ipg`WmSWK1XLXi?F2~9dk=t@aQ2oOjhi6lsmf`BMkumGZhf^QMpfEs-AS4#!fI*_eLb@?} z008%dzoRSJ)y5j?LkLnue$l8>gMt~^0Dzt$H5loG!;pa}4Avj74_dBo0s;Ne`XHC1 zHV~U&V~n4_`57VxamLos=M2tA7Y#Br;MSu;83sWZG7?A)3dED3RDIA_UnnE~G7Sa+ zze>nBebBe2Ty5-u#sne;sHv)^;sepp0%~fhs%vX$t3#B5HUvD-41)ry=>pXu5N)8k zI#f*qs;L3|et`_QfqF!=FVw-r?0ZGVNFU@!CI>^oU;WI zuEJ2Lkizg}Bvl1ZlKx`x&BFvk@*(;Mll>V*zjz{1gwtew5Qy;}_}v`s^TRv%G%@h2 zGuj7?3B&|p@MIELO;rv2v!03!cJRmgkx4(&@TBjc8OXtm*NhYhnD|xmE%QeT)CNh! zVHm($^8fX@jHjG56@Kgs3|$~93}_eVABrIY9T|&^CQwK?|F6aWZQ+7JA;?Jb*Y19_ zfC?mF8BL)5eaILzncze4^~GRR(U`9!fO=>j=(m2pfccIF9!UN+`bH|y{|gUjAQF$& z2T@hf7+>V+Kr+bSzv)yD{DpC#|Mx0iNB=6L2mXIee3SmPJdB)gbBtwYY&!6dUH84o zpLqQ*!mnKZ7sfw({x0$}jbFyUas3j}&w}5$ex~uu_&2U!BKleI8`sY?ei{G9^-DxQ z3;q)>?thL_YwZ_kiLtN9##Yi)KQnkP~EJpVsf zBoZ01Hs5C`%w=;)muGBgeQ%F6ctOx~a?db?9iIkbmop1;%rP+VY*`7k(`&u6EPw+r zCtSW;sG50fV{v7|SV~QXCpo#s>j^b~-w3n%{8TY*?+&42FPd^#9F70OoTq4N8 zX{j9~BASvmF;!W+f5I#>tl`E)=jZc0%GT>VQcHat_3Xfy;5u$mZ@6d;d7@=c)5*!{^;l!%=aeG$b_+0n+#YuJPn0(b z6pka}UX=n7{1V^v}lR z`^SdZfvjnx8^=Rl#Pc3vtvISV=2agS#B1LJJ85iXYU*)O(3FEHR_gh9yDus2NaNE@ z?b5N$rhq?{Y|%#*Z0o{jt5zE7DZ0oAw=nVe@D0^9pVLARbBw1%Xe9k9p}Dz7v3F&8 z;7I(k)PVZV_G&78bW2IPszSJ}rGRNjfxhzj6-&I=SSe&@cb68MXe#2R@KJ4NJ0b%P zYf71z9l`P>TbJ_`6^+&)J`4B@vG-x(Rd7P zZSsm1kBV&Qi0K`ihFJ3EkK*|VwI$o!2dwILD2%?oU}S~5l8O@S-pz%MDz5e4Xt|l#0rnO zI3)jL`WpSSo<=DFyro|;A{CZJdEHNxIBqYD$sP3XTW?;nBVCxBj?ML79}Vb%@aD){ zyb!ezvh*l%+n6Rcxhlt-iHKE93<$7Jyen}mU)w@t7*1)klh_)AcXl?>R%xP=i*&w1 zwQ?5I_gKUF66b~mUuOw=<;lf2ZL31`PSN)Pl|4L#9}BzY1URU@vrz(N!x=7@tEUV9 zHin9^Kx3Yo1)tL?<6=>M%$vK*7w^u2z-507X?0Uh?!#n?(pDBgSX)J4b@Ig{hhBs`B06VQyX`kjIYFtLm{WE8GL8 z!8PwCnh-i*FIbKA1d|i1cbWIw3A;Xu$d-b7E+QfcC8=Ja#=2`!;1ZY|O{yZmLh?B@g(ZUtMEk$%8@v+PBLaBU2x1 z-VB|OW;v$j?Cczo?>PVG%n0Ecvr`|cd+Sq3aaF~qg||(O`VMxIjjX~OW;t8Cjl1ig z%+jBPZCn>KkP?>^H?_@_>+J<&<>gez0(6tEbj!DEu$;ZOA?3_P$xNEiSR(fK&#rFa zd_Jo6m0QYW^u~2|c3PF(=3yVKlYS$ao-1hTR6Idyo#^iF=0G4^gz9oBa(Co{EEOLq z;~F0*C<$}Fy?5`X%i!s2eCxr=B87XmtYn0y?R89g)6~7s+E(0e*0iz97&e1Sdrazv z>uAOFUh31iHt21I?71oKojj4aA2KYM*%=)_{=j;seqyxSTa#(Y#pB&ozd{k<1?|G| z4%_(`nJy_p-2sdGu;&7)PNuV!cCIQ%xVlPELl+u%K?JI z?dse=j-y{D*DFj)+5=EbQY16DYE#$WpL_4GwHOmgzWbNutfylY&*~tBb4H4pB@LmI zWqjeYT*Y|7(rA0zO19_Mh-^KrFV6|^?NM8ngmrkCPflu#@M8=W4w8~WJavOt(_JR}hC z*cU-+V)hU&* zxBE)TH}xdsm?6iS_RQhS<}2xBl^dtZ7LDMqx@Ifuw$FsFwsCbGodphN#^FXvM5?Rz zfyLrK_GjH{hAY5KZzl+b=^e1kB0R(;pcdl#ifw8PPD`efYJ(~^N%4>Vj*@v109IBm zL*%_szB6Fz;_R|*Js6Q&IbC+y76E-azP_FAQO2FOnEel&KmhY6A6u*gJ)wK)g)Tqp zT3uDIc<1gN5L);8<;$V5D7(*p%?nGYoZL#wYS4`E-&~Wr5w$Io(cQ6nC`{+feU;V4 zPwxPNl1;gX^y*Fen@^3@9=Y0Ae#L_p-@*Q@6-haL`tLUZE758Gap<`ZekP*kz}Qh= zQeSfY(uw&sshrL#kK~$?LmOR+Fa?Q@Hd<%SbA_?9tEy%Xs6M$CiwpOH6KvguhUBHa zcpR8!JSwH7MKelHZ4o7nvybZP`cL$w-@NI1NJ2u-WO>ha?%1a{#M*b&l`8WWw(nnA zi%NUB2I`2)PmkIjcHFD2GZEbXf;DMk%mQW32a!Tiv4T6t79?FBe&Vu-BRf8~Fej7n zs1D!BDQ3Bf>)DoF4TlNCuvd|#4vIL=kf1**n6Y>pzDyf=tMu9(UfW2awIL<0_B7`7 z_--lM27L}VuFkBiR3>pNwOPV>^7d6BRsFn;Q?-cs730)u_437C1L(?`&v$cDuWLyZ zZ>~wu&zu#a@?denPDNDA~|iB(lZr6CXg>Rp&pg z;#MU!^43c%&B7^EcAO_xLj;j0=m7GWDIp4`%GN*|IA_7OEqPNHR=Uo*Q70cMldC=$ z_;sG#n)7r-vJv$mj?wdE<6-t1e$H~O1C}{D4@>4A0LNzLxH%=BrLeg-Y|ybakHU&} zTIPgK?V?!l5ii-Z9?!qz=ofLj-L7ve5Il3pq>XmLh*pR=kYWKUo?glYMHHCD$~=FR z5UcuhuG9G0;9$-unM`h;J8t}v-NW<>6JLHSB)cJf_?=aQ%VB#bR{0w7)JrOYI*9Ww zej#u{)})@&2g(KJ%r~i3Eo%_%4+qAuzP`=wa~w5?wm??YY^PJtR(ypzP%6m)=7O)BJ11fUji^h4;S7QLVOX94gUlvC!x(gC5H`#J_RSZ|i@!cb!l2(I zY?=Y=dsD8q_E1w+AQ`HOP=^yy8d^|IEd*LyOB;>a4Yg%4p?k8imq^qS07& z4XmaH^v4A=1VZ%#NffMu*`6O2c{2l;ADiuuMIu8(LlL1G2v(pkQe9V97l}e6(P%hN z0S^jivI${uW{}cXi|-z0hB4PY?dI`oG*iTKmoKRA&7&6z|* zlIdgynaK`9sw32qzv{yX{ti@MKX%a1G-l8b&^+Ww-ZC!*g$(?r`JVYR1#3$Pq>*{R zZKH<=PbZQ7W5bDI+WD+Yhh(`TZ{NENXWFJR1f&Hz!pDp;% zS-!j`NK_)5Ok%T$EDD88Mv%zgNI>;TMC|u|zJmFI#+c6jKKo9JPW{RQOD8aW4Paq# z5}85>rn6y&|4pa*$ghm))E`y8&HhzJANl{9_%8irdw4nDpYgVx_t7DLesw>Z{Ds&5 zBK*eXe_{Nq=bs|K()exs2iI>A{VMo_>sK1TjsM{KEuvoqe{lUudeg9e`QEo%ke*Eg z7!-Pf0)PnJWZB*R!i^}N;m(_0;u;^WOXG4oAa(d;a1Qud`{BBdyLWBCXQz^Um*(Xr zz_9?Ij@P?D_qc1z^9rUD56ZN;uCA`&bXmhs3Ln$=-4Nw!@WFk*1SA~Uf0!xX7q;h0 znpc%8q@~5MeRh2We=L1)((b6t!s`XkV+u10=qspa8i(t&73d;HfN{1IqK&gJaP>1o zq0+0dz3Nh>L*%Hn?0@Tk(Om#PK3-j1ah`>3Q$$Vy~pI(78qsQhWy*Rb#Eb7QHCU z+?6bL{P=M(qvTDAy0JNs#2A6OQ0Nzs)1aV(z-A-mge{T+Nr0+jHNL%p&0#Aadm9H? zTs~9P%z{(X!%Yj^_o=kd*!BQp8xOTt?^8c;bTH+f&3TSqE;IRg$FMp&E|mwCQ*(2d zW$gYMX$;Nva`qI?@QmS3t}V6kS>dd>wjiaSeQT6nD( zS38g2L#OUcjK>RH-k&qRctZr#+Tul6T3;6ukWAU#Vn0D#T3FVKi;Y&e)mzmI2IrC> zu5Q-?il3Z2$KoG}kUVr!RzS2yxR1KG4ih_kzw=Z2_`{G*!W2sIv6$8`=(UvyF>`^d z#rKY!hHefLP*=O}V2|aW5HDyzLiu6=wRi&?0prbo+aP?m!kq>Lr7%l;9GG+@qujw& z`HQfGCNz-|eZ-qUpwR@|!J6@^evk^My-Eo=Dbgk=h0q(Jk#nz&uGr7Q5TJvg`}x|d zlNCg`uEB(tXl&Any*pHT>JQ=>t3DZ)N40lP_nxv;K2X_D#bo1mXWR6lbN9yQQ-VWw z_@VC{DjDcYQWUAK05JbE1rl`mrBN25byHfF{uP4eWMEBeDlM&ORC*xMrUx`jo$D` ztyXwMl(Lp$kzKjH#$&-#yFHbeO(#m;B-ZF3-IP$Hd}wM@yCv~v72avo@kZmwb(#}rx${VRJY9{b38@s-J_HfJ+2gZ7NZ%a*(#+}bVHA%1)XX3?yZh_);M3CLU}`V zuAH*HhFj?*$Ot)dVOHk65eD204O2zw+dX`%1DR9_FG5)MiK65(%r(+;7T(YB)&3(! zDZ6lM$6C#PG8BZiL`3IpI6pfy^4yxx z7?1Ey-0>VNnRmH8Zp+IfVW@Whwy??0t~hn+v|~pFEckbrabk`n`JT_J-Pnnjtj^n@ zx@`dV^eTKE)9Bcm8!wOqJ7`KrkBsC#h}4*AUT>L^s~5;jTMB(8{sm%ts;j8VUUlhq zl&17GVzq1VsHn)h3$3YPYqxKOvbL)^GaK*37L?sP=LXBj@p5(bdm33htt_fD{jNTm zMW*IXPQJP9x@-U9YqhNgl0wOqS*^b4jFy%b9}n?~xw?mxJY5fMKP}yZ7^RHj($eOg zS;+t$&l z8+jF}9PRg|FiMTgQ#gbWCk6s-U7R%MFeqNLBK!l-AoJuJH!qLBVk?2q#6>zY5@%Y# z2eYm{^x5-yIWJMp@r?RH<$Ky2v?M;+E?=et}^T5e*i5 z#l^+t+x(KsUbYzNSvl*y5Z;Q3Etket$p!9`IT`yAy$55l(nTYk$=4S;NK4=(4=1d? zEEUchIG`?AXw)<(?T`B__3C>pD8^KeP>;`yhChBkUU>de9MD+xBs#7wLd2k3Yc|H_ zpXysiW?H8Sw#J*1PEjS&z3UXPW?`F$?*mWkMdLu!0dH>B9vIDXmLzU2;{6{)!7pe5O zweB)9$=3VfrmDga0OoPNK(P;D9_J12Ix5iEWL)KGm_fTBS%Y4#oI3%M@)cqoZtK1| zi>=*svdjFUj?;1df|8N~9eEJar?ShSglNS#`Jlb$uhSDQ;Mjopmoj}Njmr=!W9lul zFuowSbF$Am{G)s({y`Yqp7Zo-4HJYpUGCG+)&G!2tQp$8>YzH#a7jA-2RZV zO5V9&cu($Ef*3K+1{#sgaVSv;ArQzJaM?Ox|Pue~rRRBw# zTWc0B6t2LuTDC@A@iXoakvP1$owI?HsPd_ONdSLEYX4@1`zdgfa{ElED%fU7`KWZ+ z<$;b%&uSHMsa-wX`wM!Zlp)Qnnom=4I{CLoK7MST|2wGHU{UW4^MS%_Rk1l&&7SsR z$)z$QL*ga>Q@0(b!p-_?SFf~8o80`HuqSb3YWJB{9p~2)ql>M8O@WP#jd3v@(qJ&S zQ|Z7bEo}_$*|W#F*Rs?$%wpbs^qO23zxFj-zJZzRESYL}Yo}H1GmXGFJTpff1+n>Wg9NUYjgB$M#cWT;p7o}QeulP%?Jx26kC=|*Ij6+EQ z*;F)O^tywU;E@=~^m+u)zqv2Cg1uQV+~8uFT$JfSHJ!Nod}gy2>k=1D+;!!s4v$}| zJEz?pcmfo35hx0Pb1KEw*Aot=%dJvg1bfIx-2SY8S6){3%us7g%zE<7KTjtP$!;4g zXSm(>C@=b(Mpf5{iIA8d^OMilxwh!-_<~>Yf$3GNdkzV&0EaCLq^N7>lGD|;MwvJ$ zM&a4XMPkzNSCT$i9=ivvy>6YUZ0L1a(|+|ycKzwcBJL?JTPseaSKM)O$sW0}P3ZI9 zke1nwtw(NI*D9(>%)U8{b7JD_ z#yt;Q86vG--@e@Tp@P;dNxNNM<@Ux-K>tk~D6ghWb_rG9^AUg3B0~Y~Z5>;4@xq2I zN*m!?a6tMDaSG-o0V`W^>BiajFQ`;+ORl+&+GUFmA&>F5#b0(TmT-U(?}&FJOdb`U z8cpk8O|W>^Uv=l*7de%Pwe~F|4++WzQOPdnD|eN5R9d)U&SFPSq+(u~NF2-;y$I1C zuzyGHXpy@q1voQySEBsO?Aczwxf?oaI5zvFA$J89#SMsb*rARRrleFL0;?6lb(Wwl zj~}O{?kTL?BA00es}PGb&zvoh7CLD*ItgN*OpAVG(HJu25Y^Do@b+zn;in^ImRd&5 zSkTK_m;M8i)HF50(&Vv0rf|`WHDLSuS>U#G9nOi1YX_`t%(t9Gj9B(Qd^a;OvHJ8W z_!(|Wr2(>hzVq&Rya!6ASNRE_qi9HVUv4(Wu`QH>_jtW!OnL1#KljcwayDZ9!Zz&u zz258@&y=Kb8~n1=Fy^!6sOr&dV@ZeRa~TbbLL JRhoEn{tw?h@I(Lr literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/monitor.png b/src/HTML/PIC/monitor.png new file mode 100644 index 0000000000000000000000000000000000000000..6f245e0e4cf4b4335ebdb5cd1006dd62a086626e GIT binary patch literal 4078 zcmVKLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000FUNkltdwLiq^(-S6r{yVrSudC$w9<}L5N7Z(X
    bQ05Rz(=7tE)rT_4<4R$g*59OGuVwj1z=u zpwf;M1qL)tL({YZK!1NfV`F2FU1)1-EBp5CE4gmywN2pi<;!$;cUzMBd_GdCRN04b z*|LSXxw*19C%$kvOlN23!zZ9=8aHm-up|ux0^GlUzx*~YinbhX`K+|LO2DbGtE#G8 z6@4a?afNf@v#U>62`GwUNt#ZlZO4iYxWPH`xk|v!fFw!ye7+SYkWQydaBat1896ZK znr~GGqR}YT)z#G0)F24LL(gnBn=Qb-dFoZZJ2}c*$6sf7|Ie=YR$K$Bs-mhYi9~`_ zDuv(g$LsZ)8%a8yc9npE>lkX|?1>AglOku;3+y@d2H)%*vE@@$m1HuBs;Z7PAm+QY z>x!ZvNfNPGjHRU|GMP+C?-*(;xuz(J`5QorJEKFt z@Z8-O;KkBcmWl&6NRFRmo?hx?hk zaECx3;5f7S8@-#^%nh#GvsP5Znx;`z zRb@LXc4Nf`+~Az}TpO@DN+c2qOH#kzPcoS-E3CG*)|SI9U%BJ7C z@^ZZ#k6S*ggQc$P2!enI5UpZrZf<6Le0)`(L~h=^x$4gc)H9$4+B=AHIFFbC&#(oDVz!H!E;y}^^ zWPnsor~*95i5J&^_FDm*ZU6uP07*qoM6N<$f|HD=%m4rY literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/network.png b/src/HTML/PIC/network.png new file mode 100644 index 0000000000000000000000000000000000000000..06e0949028791063bbd58946c1b3f019e53ff816 GIT binary patch literal 1396 zcmYjN2~bm46#YpI61E_MV?k^vQ4w^)5)x3B9~L2mK?TBE1E?sLP6O3Y9aEBu2#BLW z>lRjP6tF;uqLgAKxFE_R4N@e61VK`jKp+qdCi(sCpJ94u-nr+Vd+vSnUeT_oFiSIg zGXMZA>ER*KaOVGeOffLdD@t^5((j6l4TT`c>%Slpi3ov_OeVv9r1bRkggLDE`uZ*# zV8UcF|6jrexP;AcEbAl^3E@;Kby-9R;)jt!p}-0M}KtAcva z@1$4h84-(jM7^RrYw~(M0AOCyLuj!_S*p^+!*X}qe7n*olvB|e4=V(Xo1C2TZ_i{> z2(=KzdvCG23nVgg>Tcn;iIrpAR9(dS5%VcVe5>#$!Cy>{nskJn%7I987ffh$DXW^u zkCC#{ZNM)Y2XQ#XV}l=x0Q^E7s>)q?LdVD{+Q-T>!-Y`Wlx+;CGOl9bA&sy%Betv*kld!a|uNu3SONn?Q zDA#{v#7e!kg81}3tbXOFPJnVw;(N$6BfC4?N-8_~0LO6`OECGOFz6z5+M=+&fbv1A z-7d?$;Z(Q|t2f=R_nrxn#N&cv*gcgvz0aJp?F&c&1zwJxi;s|$o$tk0JWLsEUob8) z29r}p&65`9jS=@ZDhsr4+GcWx%6r1KGxddx@BLkpbZzo!)hSiV8d^yLj}eDz;~d`p z;O@PPHnpzGy3uo8E15Q+ox-#ZB80ty{M5Q;iNFR2qJ8d;ZBr{2JIqA$Adh{;e9|AkJ5o*W|f3qwF>7W+PJDe>b(dpOF=skkZcW_cP` zAn6@+sg1MSOH3$^6**E>_HKOPRqHT0u3vi_trp^NB148eCJtEbm3Fo%ellw9UToEs z(K8H@!8l8A#dbGQa)j?Qj!Q6H)D(G`iB{p1U8OX39dOCse=#pjT}cmjIhGVat8w)n ziO7gx#s=xgIG}HK5g%}wf+ZOVJTYcK>Xwq_+$Pu*Qd5;_J+Cm4Vm4nhC!Zh5##9AI z^zmuuCwdQ+5sd&E1WW-G0a(EYtN}FW+_Fkr5dG%q+~{y%Fsse4Yay+Og4C|Fyn!=u@+1 zmYp#%Dtp#edy$t+`f;CzydMu + + + diff --git a/src/HTML/PIC/right-arrow.svg b/src/HTML/PIC/right-arrow.svg new file mode 100644 index 0000000..369a958 --- /dev/null +++ b/src/HTML/PIC/right-arrow.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/HTML/PIC/smart.png b/src/HTML/PIC/smart.png new file mode 100644 index 0000000000000000000000000000000000000000..3b90aa4bf156034bdc0f98fe30c3d43f31ca412a GIT binary patch literal 7693 zcmZvBcT^K!(Do*w1PHwf2tiutp@@J;2~B#h(n1v!L_nnzTIeED73rY#CLp~^7eSDs zp!D9QxA5in{`I}*yl3~$oU^<4?A*CC^E|T~t*4_#PRdLQ006oALuCWJ#{4&+M0nXP zhaSQ!B0EhrW#Hz&Bd7IK68;K_$3t^3yngsULv`SZ+T zS5`Fg`Mne9>+xvn#p#}$;MXp~`L@tlE(2Gsm^@Cy8dmjWJLz&_k_q)pshwJbr2&b| z4XIr*o0~JIe;e%D85>$})tzM3cM`wVzF%jEr=~pAC~^msE2%NS{S4uan=DMK(3*1je1`|Jeg9(e7Al?gU4`wP9Eku)I@rzG zMPbsU)|BIC#Z=Jm1n*2+CQqL66io)SM({E@R>zSWwP?FcO43>SuEI zSIHUnu42e3q>NztX2nJijbq2*5bxg)idmTg9qa3?AHH+LVAIdXWr#j`@olnd6sM45 zWoq8qzCh4Q7gy;ec%<`qZZ_pN{l;v%LSF7wbZLszEsX1`?a$pDO3Sjz2UBnq7?(PH z2c)t#F5JBl%cP}S39o2SgXdt4|gwxYdxz@dTnb>W;>Z3vfasH?Z2w@uZc3l@N<^jae#GTXr4sqEafTrE@EjE*rEu$blD5OlHRT<6I8&;zB7-Qr6uh0#)H-pTSswl-)AF6cKu%*JDcy7xehrkV zM0<9 z)_IwpX{B-Fq|20SAb<#rC65@9E2f6gZgtcp;I3MbBQ+oxxlR~%1FQ3%mAmcuAEUVD z0G%S#g&TILRBrIxYcE&4TzB!ER!dkic7*Kk%bpgTwHK>PPR{Lfp5dP#-=z&kJ)guwP^vtAF$6n{ z^js$H&!Q~v-_8>y=S`**Pi3>0o5{Z8CuQ+*jnb5V{kBMXcxLnddBDx){5J~RTC-S8 z!Ey4NFO8?zu})z z=KW|KJH?`4Iz_LgJ?z}X|AYd|;e5g-V{fHR!^H!_sG+Pn{UFfsVK?IGox?MgsR^MU zTlR{%4%UPoVt=JcN&q{03$l~qb8R=MUn}UU=F)`jV8WHY{#j+{fYIxJ|Au)N$|gC? z%9TQC#-i(N0TfDjp;$Q0*-*UW{>|a7?U&WlB7)!4)YMo!y*TU1|Af=HpYHD5A)=Dm zx8vX-TEE_R7{Q6$gpM@-5tLlG1Oc-R=|*Y?j%j@m5BzvgzA>y_SP~8c$rSIKVX^JS6hy_1bBmS=GcW~N-+UA$@UN8n+S*K;S5qU# z`EpkRJ|equ`1<#$e`r+0*1 zE@>EU6lh@Z7sQ5e4idQ9)dRPg(P^XW<+(|Qul@bW4RDeJ%7R?5g6W=iSlCOc%-Fn| z$pi%>NW7b^Dl6R*uEe^O2AjYza0Z_KQ8-56C96xutT%L zS6Jb2s;;4V(944NnxCjNU&Z|EUJYBaTek18N?kzo8Lsf565(h=5U>_!Cb4lWT~sFc z?F4r>+}@%kN}0Jc6FO!9l6Xy;{`LqLBX}@H7otEVoaR92jrf_g9XKWiUit-$t^6V+ zx=v*dc4jtMG}Le_7Ua+zfyRyJudNoqs_MG>#mS4$5(svA5{{l?q-Z+!7BHTdYDjG_UHgGb@S7T=#HmZzhpQ2JONX{uHs&n<*x?1l{CQ zBDD63oXdBjL0aRI8)JS#rnjT~wSqL5ZjRKdWP?W~{-lK)(6`P&G43Aou`S)B3{WVD zL3j;9mv-;d3-(H924<@(Gfj~#Mn=79gFtIPet730R4K={o(Ce>)OX->CdQidiV9XW z{bM%zy<4O~)716IT<`MwU8D3Y#YPvAxSkou5qoZ!g1YM>`@>k!W36r-3oU4lEzNYS zT@swhR`kJhmV8QKbf*wSFKd$*8zGjNNwc2!#Yo7^o}K3rGhmAsJZhC3l{uszcOv!7 zXM|;@J})O(YX2dT;~`a7CKT8VKL9MObh^^S!k?1RPlF4_;LN{sl6 zj25*U@D5DC`gxr8wkvf~395)HY(5;KXB~$|8Gs%sftL|q|9*>!A+7!LCBM3wT3T9q zeRsEaXXXnCIIIvodNhJQZIh4nZ9i`moozdLmRD0>FPW~z6Bid}`}i@`{WQkgw7AZe zjvzL6k*ex1rS3_=?~f9!iV_R<)SMn$(*Wx?Cvhzv+R#ooqR?j{g38^|_%Y-`C!rlY&haibdzW z?fbm=PpJH9*W0fU==%#Qs)zU3;8+4Z{+>%+natQns$l5t_pt7L8jKQ>NjWg^0mW^Z zaLqK6gb{?WaPQ|4IWkq%T4L}bxgZl3ll$b7jW&Ul$W?`r-~O4{dsFydg~2__&|mzo z;UHop41zZc6@?%SQ)HD3V6v`cOg30vUWUudv-|q`dNf*kH2>N6YsE_`&t<3)KYiCi z)jAuXOaup#P4AYUmy~c_0m{q7{UcMo)~0;MplO-cIV~-ATJ`{dl#^rQ28Evunzq%n zV0hy65Cj^0s9dV91rMXQVMbsClhg2h1B)cZ=n^2(9<5mfw2y>IuMHBt#+%_<#|-OM zRtHh!>P0c`p-^NaiPqhnE1m~86VftOY@fiLcq5m11D$R6RmgZq)McCcA0aKB+l9ka3FGQIOsOIMeZ3JPbX z2orwABplI=M#93bt^$@GRno@$vjT*{Q?A`E5*bG2hYg zap%&(zOpHT&Xx(wD|4y|1r^e{e_`?R^3p3dLI?;f-Qr-SP|DTYkApjcxtBuUJ_jj? z=8=png#UUPG;CMhU{@!qt){oV#2jzdBI;mI7%|&^EgBG-Wo2d-_3PKK^tGv}sUaHn zsHm%qd(Z3w0xXriIXd|YWq%a*F<})EbX{j>Qb&Fd28V`xKQ1Uh71h*;Kj`p2qveXC z1%l|dY%L@eWGO~9U~(C5JCVqZ4!@-bxL`*|ZfpOYyG2I)1YnSsjt(kU@4vzY>&|I! zXRmDer;(gago%hCoNagx(bUw`<4@5Kr^k^R1AVYDn^Z?p8JU>D!NDRIH1J>b+W&rk zFQ*7$r(0~q&lIn!r=hQ>2NW7aH^17m^YeS(ylh-X2%*BVGOWh;&Ni$)sdYU#W_gTS zuijx}Jy8p2Yi+$9q5vct;LX98H-%!Oyy9XK{uEN1n~SMjBYtWakxF+P-WtpHp#L5u zjkv>u4wPfZFH<)ltP}sH0ZmA;A2hN%Jw5%6V`yk7_=Bvk!Q{KIg$i)E14icauYhU0 z>ZAVF*jjAJLB~$x(85CZJMty6hFAV7r%xo9Yinzjeg7=Q2v>c$w96QkB|<)61}1H_IPpRur<0W!1%{rK9oKVoeGadQp7*y%3)Z zXV*dIfpar6u`^$ub+5(VZv5QP5ET*vg27-pjg7a4hllkyLkwcxy}Om1lG5{nX`u75 z1nI4Ld<@BP-{aD<G=KZtbXF*|lh_7==nsV8cfS7&p5@!!(YlK$sc;Zz^)zY^Z; z*$cWrQUsps?yL2+hvf&KeR?dvf2TzIevVP``I=Xp6y9r@_g}@VGGO`ZSCw(erE+ecIP8^9Wnp@bs1YVTUXlDMpZXFO!(M4_AuE4J6`cAD`aY`b9x0Zb<-ge`;8KWT=$ZWwgd-6`z{U#PV5ND7=F2kuO<8X5H`o^I}{z0*TB8J#@=I#PVPS^fMje>oH!Zk?Sr zdU$*x8*shSPHpw9&O)Ur6U}sXjVtmHjX;GYCQ{?~P{-Bl2v|3ZKT{CvRzSIRwT3b> zn&CO|l69U@6d`PgNHY1}8>PeDKm@;VcROzRCe)FWrnIaqZf~QDgdIJyCiq{{;m*c) z)by;z-~2o*eZsu&eMucKc}Wd)IDKB|Pvor8;VKr_?iKKvw5$H0wLLHZgK*nWkP&s4 zUV!P|l5kLN%~fqdO0>yG*Nnnc^w=07_Q(vO} z%j@)v3?+U2#3+)k1>{fHy2rm8%gVI8vmK%+3l^X>7N^xYQ?bS!OMPA}e(%mcB%NmE zHZ@sDsEts6I6Qma>KSC+V$|$=ic8KCN?{IBfDd*OV7`!H`oj}VGX4_FCfQ;hmm6?`$?geWmy`9i`UmE`5V7l-CRB8VIe@k`r&Tl#`j9D?||Yooawmn zk0zhnWmk>v$r4pD>TFCJUm})QR-*k1lYu7_a^L%De>2Nu>eN!H?4A$YK@+XFdXLrb zJx3On}rz8+T@4$W5v11)Gc36te*TCS~5*F-D0~o9; zO&tiZs9eOHd^Zxo#}{H!N;st2HRm22MAB0juP%Rcvi9IAI9@gE;^Lyn92L)VVdb?& zm4+727{>a5;09bS1Y_ThhTJfTyhr8p?SrS1Nf&V0T|N7Y&tsb7|bv0ZE$>Z4- zJ5g`+>g1$}WuqsdLU`i)nQ#5Wnz9!z&(TDugg?}^wYBvSbax(c^70Z}l&7-Cd#Kxm zPl6gAOJ>}saSSbBg42Vd`n*Y`8i(ah^+<77k0Xm4=FGyr?>(6pcD%+$#&h2&f*xV@7y_%k! zWGKAB1HB_e`DFJ`?B(g+Aq_N9Jv-5nr>f%QD%`3QKpqtNmo(vgcsU9_2ppb+5khzS zv)ZfXL&h7sa_Q-bBz~sdVS+i!O5e_JIGSPay4x(~n{QHjFzYpf9?5zDEPr|w)(O|p z)Ku9uYqh3K=nIRaWCsH++p;`tb1M1+I#hYl=EReq!!`G!w?-!?u@GX4sM(His^qjZ zwQ~Tt0TUh35#7drlwD64xL>h;nN$O_wF(Fy}rFfE-y`mqJk3W;Ss*vWQaDJD%5SJ zegTghR}OI__Y>48E4$VXL#W7^RD^G?BF=BguHQhjt)w9@UAQT#YielbE+)VD(04x& z7ZIT>EG*3PgXT`S{+OMGMRs@YaaVmK$i(j{wzISI)UKY-oCv@Ksx`Zl%5#zd6BFD; zB^K3DO1V_-e*-Xjj~y+qj>gH0?iQYuch-dlUda&cMmeiKadq{W?*QRxf4}gL)DzXP zPK;IaOBKQdK_Q`qqm6N<+qY8!>vKI=EI)VG^p%v9?El#dO0yAwOW-!QwtTNew7Se9 z^bp~Az}nq)5BN90J2sQ8=Abdn{oqY40e~SLH}xk`YEy?U43C}rQaU+V?w^BgnL-ED zKNXz{q>yg^c0{G$$!}$kBRZ*0VKlO^hI;yX0Tskq`9xQ(q zB#({EC)sgaF+HiTt({LXwO&x_4lgb$f~w~0OR{QJl;PV?)qLvi?(Qz>xJ&@|#KXfw z<6=Acx@JeMNe2m&PTD+vr(AKtEJ4bGiNZ-{42$|Vk8*Gdn&RKk>VMB$#_FdBIk5Yu zIdUjXWa;0^km%Nr-@pH}>FHdX)yst_jY66p0x-2r_y?}}0)UrZCtEJQQ95hEPmn<~ z((?A0=Qnw;g3=@oDNb(+H=?3+7rN!6{qwaf|JT7kJYiIt+(i?vwe|I=$|<#S5Y?{TKJNV zk9Q(G^zSEBlLo@`^77IbR;szc&Q*LV8bOnZGd?lhEYDg( zY;gb51|;j`{*o>vtAZYZ!otG-e*E}Rraw~i5$Fg~1wz8bKK5>J3o$HS=^= z!&+GwKLITfQCYQvnYNM{k3g2n;nYY82?9XMXFq3McEKag(fmIO?Bm14pAwUeVjy~P z79bbI$2>Jt_%@_F<5^oYo_;~u*TAEl6E5dpUYrMq%-@t`CtkN2g9a1^2>?B7YqoKu z)=LQv2k>q?9)#gk9sf;Zx##|{)O!{W;Wn}L*MCbe4oE2}sfnLIkJvEJ?96Wq3Jc@C zs@el70Ha$%_D`MVFK@}+TzTO?F#~h)b^V<5Pd^<0W?>!TM=fiKGQqAGJZ4WsED`2q zH(gwUX^&!fq7Pqj&};_26q-qK#BjmuXbZyQ>xgqC1~Pdq!{$#fsi6b~{?KDCvDOU1 zpt<;tf~u!v`}qDfFNd7N$;k=N0weKxYGi7v77y<2?bS0e=@n6e+z}=2a@@od*aojP zinP0BY8f@KH>|L(IFnNPozuR~wZnzQp4h9r_$N~pJuM5dB5hHrsSI)>+R~6HyOLuC z6T*TJGe6w*>71?)dp4!q8IY8ely~W|slWumOtUB!MhHTZrNTY~+LA2@5bQ!|A&48j^fPPpRVL^P$rx5e^mTTf)jryM0f}FQpxB!L`$eS81cR zyI(OSx-5sAuJq4F##V2G_9rcx13#Oo;qOkaz>~ape>4hO)%4$q75x8&-GlubkSY0_ zVC$fs5BOiH+}xWJqzn>i4qtEn zUlZJ(Ik-6a;wK;_g^&_LqEbep_hiH*WbTRyA@AZRc=%lX_v02&SJ6?fK-q@=KZQbV A_y7O^ literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/table.png b/src/HTML/PIC/table.png new file mode 100644 index 0000000000000000000000000000000000000000..d2772834df556cf20332f66cafbba416b9b38530 GIT binary patch literal 494 zcmVz zzl$0{6vsbtmm`H_f&|i}I@0AQ6>h=0>;2u~4j~0QCBu!HvF-ej*xRmnA*H_>UsJxi( zAPBs;)^0`(tf*yZ8VrX+k|d#$^JZDbdc8&|#cxl)u0q@?~Xiw9mj7@^}0l k1X=F<0Z4DYlW#8n0DKb29j%#Ipa1{>07*qoM6N<$f=}4v2mk;8 literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/tera-sign.svg b/src/HTML/PIC/tera-sign.svg new file mode 100644 index 0000000..c49e53c --- /dev/null +++ b/src/HTML/PIC/tera-sign.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/HTML/PIC/tera.ico b/src/HTML/PIC/tera.ico new file mode 100644 index 0000000000000000000000000000000000000000..bffcf5650b9d2d46a1c51ff8c87a56f8421077e7 GIT binary patch literal 9662 zcmeI1YiL|W6vyvAnpfT3n4mSKb~j3}r4pjptRGA_!9)`UjUR$vT8L1p^@S(|MRZfC z7}P*p^@E^L5w%8JDuOQzrV@pseo*n#v)(%7qh*SMcB1*jRzW92C~T z|9lPf_4O5Hv)Oo0PfsEjw3VyAx3{;Hv=5Q@A?nKfbfrH@99a~!PspZh%bu(6xKFna z+Tx1UV=vUz)wQCfrDa1Vli8e$#>U1i)Ne|s)9YigSY>N#YjJyfds|aeQ?FN_y3Im; z8X6iNtgEYQBR;RsX=^?nk5|;!*Iz3i>St_tZ8tYJ-=kPHe`X9Cdn%PmhQr|Y@9{6%3kdizWtA2||@MqfxKlPUD4*`mAv zu7tfHqkbHrtshoE0`7y~!B1cHe@yC?yW^gWJw)3%@Cy6`Haq)hzX}$3?M&LLpluV3 zfX$BLy&GbnV{#CJeD6W06~b=clsQqI+u>KR`BY2~L8ZID`!j8tiwoc#&^-IuQ`@I- zF%-i(I0%0Fs{b3Fhb6`*pTn>UK7=5D@1c{1Y3s(=GLm-1b2Iz^LGe6;P8BSMCqXgV z`pD)DP%MA^od#PW==)Z`TcO0nX_M$Jh3zm3ws^jyeJzxLz6*UPHhs7viu1g4Xe$=sW-y!s}pLH}d@zTmdS8rg#s)YY?<=X{^0)%)aG~*ITBKa`}9C8-n(h&(XOQ zw2nGK@!7_#F&qxikcB4K3D>J{CFIKa@jUMwfzV;f%V+> z#_TQAUokxmLGz_CUJs?P3O<0K82#Gi>sdGx{?pu>anL^km%ta`=TG%o6N8|=ZuG><7~xBxPIYL#@|;zGZ9{!CKInWs5`ey#tgtI$s|F<+rVm zX*-DCb&yxi`i&L4XTTE>v?lhTqnt7Ko1k-9@yq5@u-MOkzV+BvE;qr)VCKv#M`?Qr zszGPSN_ZcaK=EG&Ly&8|m^$TbKP;P#7;Qd?L3_ONS#l}p>@_)I;`Pb{=&XhlazC@hH`6v^ zQO@27KY=%1cUgPvqp)bEwr4|6@qo_%pqy2%Tm;kJ1IFP*v<`RUKcdg4yPbFdv! z^D#zSO#Dt2uCA_LSyNM!?&#>4llz%1zL~V~J6lA|M7N+bJI`)~c`nTJJX-?_NAE4H za=>vi13X=Iv#$^Eq=HOzBdJg5scTs8J9*=YERy7+8P+d2xr3Lj$LwCKmJiR5=RM@ag=mR9A#8C5=U8;k70oK^Qxbc?3XGJ^BbdE b9^!qn%0`YPC(5Il>GDW+qCCc*^zHIrO3mUB literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/up.png b/src/HTML/PIC/up.png new file mode 100644 index 0000000000000000000000000000000000000000..31a48c6cd22c69becd0bc37c593ce6df3b6f569c GIT binary patch literal 1632 zcmV-m2A}zfP)H$RK~!jg?U~DSTXz-5Kj+>nTXGc3a#Q0ZjNAATKcF!Qllmb` z>6A203Ik;Y3x*|2c9}q+ErsFE+_?+*2UtL9;{d~wZkVC}11-aj$4qR=d06sO&wE%% zSGtm=gj#aE@tOI}?{%c}{r=AP9^Ls#RF$JJ$F<)Dz6Jd1&h5LuKawDTaTH%#1ONWi z)Wyrd2aaoh|0v=BNUt;Cxc2M7UoTynm$}(FKKsXK`st^CFR1F}JGbxtv!}u6aRwaM z9u<*4jE;_avoo_4OGV~p=j6o~M?xaDe&+^i;8487_fnWD3o^QR(z(}3~BK;9I9%blMmQ|It z^#?>EVHOt_4d924YroxP{KFG)T>Cok(`%{MWMt$E?B(}}4Gs|>ies8)+s~9rMK(4v zoIn3XE>2B(BJx|uwZ{&N0S-yPaqY7ra({AS(wm%|VrOTYLZJYFXZww)NZy__~iqql1aWidifb+1}YgRqG8P+#e=->U7&|Y&^_R z@hT(|E0%~{1%CP52mn7*)#QyEH!ah&$YnQc%MI|VilP{XK_oIjxIc_#T8Ib$p69W? z{($JIC<_aV0^D|7`{t1oa9sNh;3uh6O5#Itve`|_l}h9E1K4{d56cQ+ z7zTx6frpPacxmh<#xIPkhHhw}z^TDxB30A+EJ zLOQd~U@XSftFH?1PVJSvHv}Blz5(1#C9g?5K1?>3#j8|mps9gw$fPb6tqCSbrUkrj z{xA6Wg$c&S#=M%8M!F{8xb`^_xi@}c+?$@R>b_VkG=cRWUbKY>jlH0RI{i{V*?i32 z{w}XxT`(h&NL)ldbX;2wO~BWEBr-6VO1@^6ibZyIcL<(*T{=y=r(TVkbl>#3_Lk19 zA%>7lrYzt(@S{T$0Di8jiCeecvaFCrZadd3hn9!8wRAQf;Dc4DlT|7e(&;tgL&IFY zas}WQj%z1AHvz}B-voY~N~Yw6;TOnl|-uY zPIK<;Icl#O!=3yOyn{HdeO^TFz5Mb8Z)SSVESE}Hril?5Ks~Q11D^VG56?gOnvd6# zEzb*NphelzvY_gLDhmsX=EooZWh7t7{|@*@I|2u8B^=lOATkj7?%Ut|wiS(@ZZ3TR zSp;?6JlA@b8U*!O>gi~ijSQcB@;89*-MM}D!`A%+84!`B{k?tb-s(q9hZ5LtyWZHZ zk2*sZzw7K%{T}f{SiqOs`5hpjs$U0Q2l^YK5Pz(y(q_FrSM|qj{W^`Gwx__qfqQL< zc5|^M)pQswK!PBGrh(q`d+qXOts?;uF#(fmmdrNIXz7Dw+EuqE;6SC;`{RyHRm=Z3 z0THokpnc#^n?K9P3;-zy+UK2@fugE<&m<5a;-6$|2HJu2Gtnw1-!#yIr``^<*RrNh zlUdI$ccoFDTKgb@>ZFG^%00iGe%^K@{|`J*J0Wn~c0%B|?S#N_+X;c=wi5!!Z6^ed e+fE1^xBU+{RDoT|&T<<70000C}0}OeFU0-fC3>vLx2QBNJ4Dy+I#p|uf5(~?>RfuKOE8!#T?=% zJ!z!Td*3&|-+S}k6MQ}&KQI;mJtNv`Z zOP~X)0A>-)64dMGNQe9n*&*$UGr=MfL%Y#=1hYV)n|8TPj6ai`-u;}E|XY_RL zSO9E0s=)N=)9+rtetn>(riPlD8Y~tIk|a%<_i{1MNMe|g;Q@U0CVXbl4Nyc-Bv3^I z#U!AL240Im+l;9K&^D<+u~_U}ym)Z{AeYTD*w@3zNP^^OlF{@yW8+!IQW=Iv#)yt) z7|ImLA~PBZ@ryZW>MEhAfhrg%vVbB9s2Hdwfhq-@Dgef$bD+P!e{U=nJJav?bNR|u z?9$w*6;1@jhHR@swmDGjjZ`+);5gnxo!v&DQl+bNC;fZ3Q+Mu(Cj^!aQ#k$4v=LOehJg5?DnL1rV92twn~m_Bp)y z#-sFp_9=7P+m9Gl0N~?~KW5XWO^*SeOeP>2hSA&A)dfIHeSpfry}0BFkjn(J0i#3x z7`Y6!W~flWEp;*+}w|OJK zzU)HgFF6qek;Z8)TyfEPy!-3}c&*@8!Kn%;l7U%(29Je$w~Kl0Gl@o{oVaumO5jx9 z|9p&+rgPpBJC~kTbt7>8kpksdEVe(B$)H+o)Y=t-?`@^oDRIi_XMC+*XPmtZip-^Z~@Zk z^q0Y45P;_9CO&xn0hTPB4?sRY@dr(((*T@x=9#>;`57u@u*(xapVUZ-b?a~El3UN^ z`afLBz`y{8ZgA}MDeRA1zF4%`u1-7qIBa!uO^X10f${;!{shdOF+5zkN^=zJ4T= ziGMuuFm9_K#uaW~yAG3~^2*CE191O+_YrD-leXmn6qAB0U`MOUkWP&wiX!!Ob+dp6 zAABwKr!60iQ(+OYs3MYJ99jhcz2R^;57<0zH*?zNalzRu2u2U^)YBbIt8eA!KfMH- z%|fA=Cs)Yw)GM1BgVNF)*kTC6r3)(Q&+J38D=6i30CYn@tkfA!3;O6sFF_#^ ziR{nk@~Dc6*&?GEMXDSXoUr61YW&rBJT9CrCmyd8PpyYV^A?l#_EEdgf|fsQuhBuW zmq?`I0JOHY3Zf{^J@~dCcv6k0WO8G8eQpM$1FX6Gdd805MfFJ*29g?|_Pl_l-9*EJ3bcdg96=H&B+86^ zo@MCEQFes3Gj~oqR;v}O)#}gXaso%$mJbQ&hTazrM*wiSyd;JPkyMG>?pcertdsWB zeCRm?K?GsxM4xg2L{$LMK(-6?ygrKd?0imLu!^D+o_OM2(&;4Q<2er?0otSjKyM@* zDPbV{eF4IKLH_!;`-rt|W6s$=w48xpGSCV-rBs8fULmluYbtq%@1uk8vICsXs9ok$&TsHxWy>S+a=H9>CW*rZ(xG4| zl1iqX7PF1k)>fhk75ULxX1e_NymizaS5H$@1IIK3uvb-JwaW-c93Ol8yV$emeNH%G zDlfkHHam7~*$BkGi$Ez7?&}*(Cfi(2H|uV>3*9hK6a}l@imHm}I_P>C!_Ywx$YnJU z3`7wmlYp$4Xl!U;=gtp!=bcZv_ugyY(6rLsd_#QgUXaeF!b5{`92G8f10>OeuIXgP z#>t2Vf+S#)1O!1q6epS>i5Q}YVHn6VxZTz4+4BKgxBl}#sZ?S)ko?X9rBW#riN=^Z zrIk`iLlgCbAP__msVt(ICcah@O(=?jNrqCfOfg@iSSYf4*JteBz5P?*LSTe%i6d`D z-Gf6hFhJ8llne|*K#~;9iVT85zK~};HBM|WO0c(!P&jBrqv32c8jbY#NA|^s<6TT# zO5@)KKdQiRJdPx)l(j5{LY{mfPprR>p588cd%KIh;m}ZTxM%lpVt99{RO|wRK05UK!FfA}LEio}vF)}(ZF*-9hEig7ZFffgXxkCT| z03~!qSaf7zbY(hiZ)9m^c>ppnFg7hPGc7YQR536*G%`9cG%YYTIxsMjT)}_<0000< KMNUMnLSTYlC(@<> literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/wallet.png b/src/HTML/PIC/wallet.png new file mode 100644 index 0000000000000000000000000000000000000000..87965177aa3da345950422d5dca6f71984c232fc GIT binary patch literal 5515 zcmV;66?E!}P)KLZ*U+IBfRsybQWXdwQbLP>6pAqfylh#{fb6;Z(vMMVS~$e@S=j*ftg6;Uhf59&ghTmgWD0l;*T zI709Y^p6lP1rIRMx#05C~cW=H_Aw*bJ-5DT&Z2n+x)QHX^p z00esgV8|mQcmRZ%02D^@S3L16t`O%c004NIvOKvYIYoh62rY33S640`D9%Y2D-rV&neh&#Q1i z007~1e$oCcFS8neI|hJl{-P!B1ZZ9hpmq0)X0i`JwE&>$+E?>%_LC6RbVIkUx0b+_+BaR3cnT7Zv!AJxW zizFb)h!jyGOOZ85F;a?DAXP{m@;!0_IfqH8(HlgRxt7s3}k3K`kFu>>-2Q$QMFfPW!La{h336o>X zu_CMttHv6zR;&ZNiS=X8v3CR#fknUxHUxJ0uoBa_M6WNWeqIg~6QE69c9o#eyhGvpiOA@W-aonk<7r1(?fC{oI5N*U!4 zfg=2N-7=cNnjjOr{yriy6mMFgG#l znCF=fnQv8CDz++o6_Lscl}eQ+l^ZHARH>?_s@|##Rr6KLRFA1%Q+=*RRWnoLsR`7U zt5vFIcfW3@?wFpwUVxrVZ>QdQz32KIeJ}k~{cZZE^+ya? z2D1z#2HOnI7(B%_ac?{wFUQ;QQA1tBKtrWrm0_3Rgps+?Jfqb{jYbcQX~taRB;#$y zZN{S}1|}gUOHJxc?wV3fxuz+mJ4`!F$IZ;mqRrNsHJd##*D~ju=bP7?-?v~|cv>vB zsJ6IeNwVZxrdjT`yl#bBIa#GxRa#xMMy;K#CDyyGyQdMSxlWT#tDe?p!?5wT$+oGt z8L;Kp2HUQ-ZMJ=3XJQv;x5ci*?vuTfeY$;({XGW_huIFR9a(?@3)XSs8O^N5RyOM=TTmp(3=8^+zpz2r)C z^>JO{deZfso3oq3?Wo(Y?l$ge?uXo;%ru`Vo>?<<(8I_>;8Eq#KMS9gFl*neeosSB zfoHYnBQIkwkyowPu(zdms`p{<7e4kra-ZWq<2*OsGTvEV%s0Td$hXT+!*8Bnh2KMe zBmZRodjHV?r+_5^X9J0WL4jKW`}lf%A-|44I@@LTvf1rHjG(ze6+w@Jt%Bvjts!X0 z?2xS?_ve_-kiKB_KiJlZ$9G`c^=E@oNG)mWWaNo-3TIW8)$Hg0Ub-~8?KhvJ>$ z3*&nim@mj(aCxE5!t{lw7O5^0EIO7zOo&c6l<+|iDySBWCGrz@C5{St!X3hAA}`T4 z(TLbXTq+(;@<=L8dXnssyft|w#WSTW<++3>sgS%(4NTpeI-VAqb|7ssJvzNHgOZVu zaYCvgO_R1~>SyL=cFU|~g|hy|Zi}}s9+d~lYqOB71z9Z$wnC=pR9Yz4DhIM>Wmjgu z&56o6maCpC&F##y%G;1PobR9i?GnNg;gYtchD%p19a!eQtZF&3JaKv33gZ<8D~47E ztUS1iwkmDaPpj=$m#%)jCVEY4fnLGNg2A-`YwHVD3gv};>)hAvT~AmqS>Lr``i7kw zJ{5_It`yrBmlc25DBO7E8;5VoznR>Ww5hAaxn$2~(q`%A-YuS64wkBy=9dm`4cXeX z4c}I@?e+FW+b@^RDBHV(wnMq2zdX3SWv9u`%{xC-q*U}&`cyXV(%rRT*Z6MH?i+i& z_B8C(+grT%{XWUQ+f@NoP1R=AW&26{v-dx)iK^-Nmiuj8txj!m?Z*Ss1N{dh4z}01 z)YTo*JycSU)+_5r4#yw9{+;i4Ee$peRgIj+;v;ZGdF1K$3E%e~4LaI(jC-u%2h$&R z9cLXcYC@Xwnns&bn)_Q~Te?roKGD|d-g^8;+aC{{G(1^(O7m37Y1-+6)01cN&y1aw zoqc{T`P^XJqPBbIW6s}d4{z_f5Om?vMgNQEJG?v2T=KYd^0M3I6IZxbny)%vZR&LD zJpPl@Psh8QyPB@KTx+@RdcC!KX7}kEo;S|j^u2lU7XQ}Oo;f|;z4Ll+_r>@1-xl3| zawq-H%e&ckC+@AhPrP6BKT#_XdT7&;F71j}Joy zkC~6lh7E@6o;W@^IpRNZ{ptLtL(gQ-CY~4mqW;US7Zxvm_|@yz&e53Bp_lTPlfP|z zrTyx_>lv@x#=^!PzR7qqF<$gm`|ZJZ+;<)Cqu&ot2z=0000WV@Og>004R=004l4008;_004mL004C`008P>0026e000+nl3&F} z000WMNkl7X!b050{KhAdK==4tDIpA4f{K(Pi?I(`UuYRl!{MncP@JBVe0ek^C z*5By+-0Y!!%p9ELyWcs;w4|Kh`Og zPLG{9KL6pz=D-WjzqnbKG2j^R?C_Ss&&(X0WdB3^7--h%AM9snq(RonX)UcXf8j%R z?ir_AtB~gf4;`NIZ@)Qr4ET$mbOb8EQzb-x`Ox7RKQ%kS*tQXd#+oz-`*Gf}cw?FO zzJDIXuwbOMl;wqG>H~c&TyOEf>;!MWIrqCqj!u6EICbLq{PNuvlpnSdzkcPf*GJq-;`6~d_`YJRB8(g`3{qrY|&wukHJMidum;*BL%T5SNfY#qiqAxRU4w=^*|8UuA|eN{jh-ZDT^Nx+0{JGTI!L3#Dx zzRM3@{%`DRF984k#^vmn?g=3gdE)0k`#9%{1r|aJHDgsf0Mz?y)Ej+ZFtnwK_a5hj z;gKduC81WU(irTg=;RCz4^XXDaNbd^ruZ}gfi&?L;JqWQq;X#=3EoFhP^qPSc<}}c zHsif2gD*Wue zX)ay51jyzPIyP0a{`;an-`QFP{QY}vxn~6GiScV+{35GMEwXk84FNF-W*Cq-K}32x zDhL7;X1H={C$W#J_T~-7+H-_}k%*8LN~O#zfI<}k%;G#g_4rDKdZVA0zw}p|)2JD& zEG_frUwgH8?{^+Qz*qj`2fgdxer!K~``Wv`>t`RE<*Toqy6f}b`s^%!_w7?3dA{49 z|K5|I!AZ1jQwTjjTeY8i`WgC~V`QBSD*_kK%&}wN3_%Si!o@SE*s*VxU`Fa3m(I>H zzIVE}z@@WuY@M9OI{||Wr{87w)B(&41TLPA>6CCVLrIMwPLb!7 zw&I;5D?(Wk9C=XE#1pz$w`gQE*hristlJ=gIL3R_6g9(%qX>b-yIyWt2z>DV1v*l2 zZF!aPS`}5>5JGo2pk^#xyUfy!1+vu+E30k1bEJOFco89S(NHau&B`QCy(^<6WJSO` zhpHkXF}a-(g7(%*oWn4jbEsO3pa_j-lTLn(rFIAJz)FWVcc5gKps}+TK`@FCV%SS| zF>zoqWQ8iOG_VMv>|-Td;+PmMhXySnXT41@GgRZ|bb~2$&of5Q2q^^~-BtnMjSsTB zLkLq+2P;{Ia}a{!U3A1rOuV=w5f&9MWFcS{BjFQ|2qZ4f6=_u|g7zY^xYXj!Q)gLR zUfGoY|LcEmxx5Js-4j9>OXuW~AOz6iP-Q%Q9y6?%?HD-r`^0x&XkFkL==S_Kt3> zBdawUyAKdKZW9O0y4pn15<6ahiV zgK^@W%SrAUuo5EHGdd4i^1so}mBdG5^FnbY0mSDq zIlYUp@yuRe;DEW)@AKrZ9OmTr;%lIX4^7ZlOESb>;v%hfvK*wW$fedA{hHT7$yUtFZtTL{Dm z!PXS3Q09!0ILHcRWU!w{ADN|+tX1GOv_u#!taNB~3a0mNr!myz$_Fg1J`iJ;nJm@F@Plk|^LqSrqn6w$ufbT80T?7cCaIQE zBB&t>iE}s?>p+^sr9)7B;y~j(k(0Vf+@<6gDJfNHr-)(>g*?Rj?ILHjljEG=U6;ap zn$R|akN{pWt}eD%Tx!u;Y*FMz)b-_JYie^1uU<-J>SL0}6|6U{0M3eg0pV^ARMg=5(keF>mT4`oQgrg(QO`SvnGy_A z=TK7whjVg^3=t`56iVrAz2kV#L4#mQQqJSVA(9a^ka$nMnzDE6AoWTb1!k$eN}IJC zh2*w;sF}gct}$ATD%nb#kmu!_h&ZB9#SE%RLRQ4+sKv8#u4{%miRa+dd-4!&x!IEziUJYA3wYN(U&LC}SF0gTNRy-sp$d?9_v7{mBx+Fa@8c`4ta0))50CQolUIA! zzkXMzrFVS3lER-(z^L??ce6ukqLaI z(v5&$52N0ZQbbaq`Pf#j{{A04OaI_Fd8dP_^1<0Tw(gnkN#%=Y-er7ZCSnES+WV*3 zvh#uRnCSTM+&rVZrVu9-s$4&Rnz4zg-g~60=ig&=_f+qAdF{e!Mt4u)ydy7)vi~&R zJH$B_uU??msPm=2{3@?qVGw9V#G0*lzyq}-qa63b^4PS}6tx66>K%++sZgnb{qM z%+?K9Z}?9$0^M)B?cQB~;IP{$`+jKlWB-BU(_iX8b>LG6?vM8W0|2`N{PoRG6!ZW9 N002ovPDHLkV1mSlj^+RW literal 0 HcmV?d00001 diff --git a/src/HTML/PIC/wallet16.png b/src/HTML/PIC/wallet16.png new file mode 100644 index 0000000000000000000000000000000000000000..31811f6d70021cf06eca8f3bfc06f1c8fbe81ec9 GIT binary patch literal 461 zcmV;;0W$uHP)CfpVbkm`mlY=hK(xro4Y(=DQQWcWYr0wO)_r3H(ODRYPU$|Vj z%k%Z#MZ|H8bxLB*O7Y|3NYrSu{)lao`HCh8BUs00=a%pLD-niapw()jP$=O3`fBbV z2mz%OT-RMmkjZ4=`vJz|vBns3LO^Q>!w^9bECmh*1K75cD5g^Abe@qm0E$qXIbiUz z2)5lv6vZeO_q8$?pIkn_XWi86a|eqA{5~8G(e1tyIEQNW66Nv%dcB@@VVWjBok;}c zCp};gM`6pO(MT)Nw`jNDaB_MGm)5h{EHyoXN8}$ff*?`!JWs1e1eDZquFWlzR2|&i zKKzRI@~WCrqB$dAAd~P>84G>b-PzWI_Zp2Slu9`W^@uNLau51$(ilD_o~L8lu%Fjm zQC>;Xj7bw(@Md{K)F{@UZX(;40u}M^KhxR--vSH(KrGOG)Qz{+00000NkvXXu0mjf DG(^sL literal 0 HcmV?d00001 diff --git a/src/HTML/SOUND/click.mp3 b/src/HTML/SOUND/click.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..9fd11796997a4faea1f31391a303a0c145e1370b GIT binary patch literal 1088 zcmeZtF=k-^0p*b3U{@f`&%nU!lUSB!YNlsmpl4`c2$qEq|9=M@K;lA}o_T5cKo(FR z1JEQEVTLpuU?whb1{e5`3xI3}Ix-pPNHYTv2L@DN3>IO3|7ROvJRCI8KSvlCxN4R= zZV_)_%vao4FIVKmz>ok^9(c^KCx>CZtmfbM)%T|S>lf`;4RdK*-*=-;L+a!qfqTU( z9;%D+f4IWkw6J%c%cG{?i9DUNAF=rCsa*fkEA@%Oq-nX^>r&PN7DDYm%>zVrrg3vJW;zJG19&g$83FV}`n;Nb8`P*8L`qq;M4)071Y z3JR(Vd(t%m)r5Ap+_k>_Mt9qeg(35-q&|t&Khjm1uNs=nF*|(2j=M)ZyP9&o21QMB zTDZ_?MHr(6=c7OYkqIRx6&6ZNEsYCBR&@A?8ePA)ox{arnvSS7SJmml_GZ^TAKzb} zcia8{bstAxS7SX(OFh$2;sMA*Qq2b#7?%KJM1g_9qyd=1h}S;&RDwKIF`PUE06~e6 AKUODG~XNdj5OOJTusvl3?HjAp?DV)#I8O0I0RC z+-)$|#3j(;5-8NazMdA8U6+>sm`3(aw#UY?KL7y$=m2p36x1mSrx=}Ldy4ld&rf;% z|CFEd?v%b$CQsQtg>uTt;>W?=JqhmGiScjXR1T-j<2Y&@u>bDCRm`G!AHG%LHiKZz1O5kx?nm#8LDqfkIT;;vA z(~4vvrzhN~R3kuB6J^Vg8|&6yT;iCoMcf*ZCIsoDWtN#oP>dK>C3s`(F^M~rxS8Kl zzW+AK!ymt&D8ZA4j%J9*}f(sE9<)NVWXT@NjvIIJ7@p zJhy6s;fbWEUs};^8xOve-Wp=5*sH10fnSS>zq~gnyIi<+&Gi%EzNtT38|HaAA?)6c zjnG=2+~5k4BULW#7%fV>_KEF!`8xRV9pb8jgvBJFL^Ho+56E))5oK$!1a9*~VrR5l z^g(T4SJ8vU!$w=jdyWC`N4DJR{J-2LLpJKf^Roq1<3Ub{upF)SR5`P6KhW3}j_GH2 zUX8*f5Wa|#t2LWuS{~y4%~E4RlAo5p`5_)x>FbJ4n6Rr|uO^5^UWJ zW{dG2+vVJ`t?>pGODvP4PIsSpFFi8J8BFV1aJt3Twuc-?|NUjRfhFT@bvy`_&Ck6Y ziF=rm>YRZ%WJPn-o=4;UIfTc9l->FV^3yX$zg|;H7YF9j8_OuNANCS4g{5yqgl`~Q z=X-DMb+$KbQ7B%gDS4OPSs`Um&8GZghfS`#&AVoayaUQ^bjOz5G_0I&q6NU{`f%5t zvjpZ)w|!uDj9NZO>k0+1>CEYq1awpbv^;<+61D;LGuJ&ZrO$74{k#C<6;l{1)LbOX zqIQCgI$lvLoE3kqvFIGNAooR5WI8o*HOGSRsm8!ODVZ+IwtPicovKZsLwL!%Be3rq zEyzv_<0=JTvIvC2rEg_eif{^CnACryzCw?Qm5T;P!;Qd=Z2-)*xleQh1l9&P{4-b~ z2E=X)B~Xsf8Eb#5TQR|xDqN>9odz*Q)iZt6{v7m-8`nVh?zX_bz4-|HT05`tg9b>@ z%w>pq(-`sBp`p-$28gYoB8vP-Q|)!olYLCo6omi;%5F=?uKfs1M{TxxBLobbjVmBMHYa&EpOhZnRwk1ifwm5dG|pNaGivrDH+CT8s=YQG12 zK^yrqm8l@?9BXXa8KYp^V7*v?7xzck#&R_ei^si=T?`0o*k+G{?kgBB;^NqR92Gx4 za~J$Eni1-zbyYAkyU_4$77#CsVt;%jYx*OHo=3bM2kO!9*6`<$F#6$z5m+gupRiOEMZbJ zVW3<_>_W$G;Y*wCE67ZN$x9F`nM?U@x@FcZ!eI}Jt*x(-u?O~&gJbp1qTB691KQ9a zXB7`%#HBuYvxg2Dn`if;M!l^! zgLHjwuN!&ubpMILOhL5eAxf3Cw-O|Km{V<5ZU`DZdO_- z(eOs=r^%r`*Ci&LE?TJX&+gj5%y@kL3z;;pj}5`X!9mm=g7>hvo0ntbnxlkd6=ZpP z=2Of(&eMZ~Xd+-qy_-TV=4a{rK`j7^mI~#P@bcu08`eI6SzjEMH$$@^qWN!eG6qQ5zy;Z&GA z#~t^>B*R>(&6(FPyR|B2EF?CW_6!ew9SYU8sBb5QLz?%R1PNA=0vroUtHx{)YRn4@@R zAf0t|GfHCOJULJJ5Zb`TL&}rYEa<|feQX1Zus-jz~egqzO0#z^S3p{`r!Ni5Ue8BSZ1$xLW4X zS2RJd!v6tZB)CqL?QM=d!q@fAs&T|5fT&VB4`HHFh(~7}6XLOmNfXXU0$9;Xs=`_+ zKwDo~>znz!eXPU#7`vPu7eb$n>f+39lku zFlRIlyB5o>@ha&`)8!d1yiWVWdULtqN{Ieij!t_Y?{EE839IByWzfnMAyI0jo$INn zl5nn1UA@c9pOxG`vW(sjqKQtaH8Sp1)to{1B zbrxUJ5s$?VN5Ut4#Z(T%2vO?d>SptziRHd3jlw~nvI}gTIZ@6Yo0%Qt94ncwO}rpo zPSwy?Qz!&nLH;=OBR%||$Kf)+nfQ$j7j0E4`k+^RWa`q6Dhswas;`=)IW7)j#(lDq z&ncMwtu?bJnfw_beIR=eoAg)J_WmO`Jlb7slG}t~?lj#EW*1nDk~^rxJ0}pQDVv54 zN3ye+IOn(lvf?dRoIBCl?E5mcS%l+MwgZ&$M1&>T$FTBa5zIQ27aC|QFZMrc&TE86 z;D7S}9Wjr2qx;qyK4cJRcokvBc1A~mc_i~)BQ(f-tSOaVEMnNy(}H2o`cr|KB%UWH z7Heyna5<99m%w`-mPxJtKZxyph@8zk| zXAm-?A4{vSA6oe;3(ZnEU25_uiQ?((z3FN7dpSvBv!rW7b2~X23IAUQ@%L z(ZV#J)GxU{1NjXF(}_cVkd3xDKs%tgeYv=7=VG{A8nn=V%^pq(_1((B-psHebT*+!wS#RT2 zzanc5#*y%G=42tVB$xM@z@>WU$@EH#?gu~Hg&xTHe0y<0@pm{Y4W|C9b*wJ!_T+N5 zob;F0oRp|3_Z1|xkZVJ9na^iiENxb1_KWYX{mz-LFWI&x&*isXjvMsfFBMSX0>Lq< zZuDLavuI_~UXagbWhYOO2D1`)X{4juq=v^C*YiYwO+w_nxf~(Eer86 zdFnG+ly;xazXgu50>Hq{ULKnC=u}6E*5^SgnYJT?B99o^7(ZMDQ-hVItj_X82J@nn zeh(}N(J&D3LtGP|UqnQ)W)`dnLN42Bl7_t}H;F#9D=7?{Z(_=?`F72JWl4mfFZ zsZDn+GPevC-}c^i`ZZ%Gzi}^0IiYNZVeq@+&3Gk*jb-Mfy@b>O>QIB7Jn zZl%W=SL$Ax_5^Q=>mS!-B3{{uY4tGwJA%KT^0OpHT1HQj=sqM^@0 znu+pThq9U1x$Yv3-rGg$@m7oII6UJ528&}?<`k}4qzi-Qs0dEvEa9<3q@`3A9Se2N zI4+pqfeBkSHxw^GZ6$(ri5H;jSQ*g9Ca6542~n~#WT6Q$DWuE6k9J8!6lj=CWP(+Y zC8Ej$$eS>5h;p7iD_rAc(jG$7bQ2$6CZd;_*vY^yV*Db49k~!AsKUDk*N9PvR~oU4oTfK?*yG zg3vm7sXUC&y~1%k`R|k2@7w8RD)$I$E9t08p1ko1{|zU*?iU&kvGDt#0s3zS{Ez$m EA19^<-T(jq literal 0 HcmV?d00001 diff --git a/src/HTML/SOUND/soundbt.mp3 b/src/HTML/SOUND/soundbt.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..a84997102cc52355bab129beefce1d4c77988786 GIT binary patch literal 1197 zcmeZtF=k-^0p*b3U{@f`&%nU!lUSB!YN2Onq-SVg0G5Ri{~t#jVG!TBXp_BT1;Zpy z6NV`<5D9@}hCTTcfNYs$iDQNhKnCkE!`}ZQOEsq%-BW9N5F^5`=~e%^`u_j_|Nq>Z z^`qfq#2hQ`nadW}@3B8y$Y59he+p0i|3C8oKQ;ExKghpA;D_DbSubXlzhGbp*><~W zp>wdJd&sP(bEUY~-Pbt8d?)EAL(7zxPIDQuBpLX$D^5P#wm_+how>#85obT|5`mkV z*Q>9*aNamQ&Ewp}mv8%B2;ZO`Yr2Z+8evhrc=X z#OPK|MnU89nV+9)zOy{@G%nD8MX1TXV{gwy_n3>TOU0yZ6+XG~MBeo)yZ%4+IP%A> z`p~+cGcGVJaSB*G!EVu~Gw~9O|6Ek4-f~egW#1B`{R_A%cT|P%a^E^VQbU4AHqYbS znx`|ESkA4@IdF`pX2QwS3``3SOln{{uQ21pNhkiZ3J;EQ@N~p%YH+wLWhlX{)xqJ! z6T)#;;_RB3Gn_q9KMu7yEokEtNO;gDl9t%=Akm@Wu~f?$Gg*TbEQgvF2uxxxNeJn4 z%4}eG#>2C4V;f5vr;db6Pinx!Ny5+Am?a`AQu`R!F|*0>vN4I=eV*W0AlUBa!&~v$q);co@`7n-xrgk`x6J3jfV)i}d#5 zZsf5t>Di;n#igvo*nPy!$YVy1Tb?`Tikh~ECuKtHa{fQgIP$eL`p}}EvmXkySuxyQ zk-);O^GkDy^NBk%oQkX(0|Xlmux=}fpZ4THkSM2~aNN|Hfo3TW9y-?A^_VCdL>3%g z(xhzI*7A&xe?lueTbd}#v^m?(>{UO*$IHOj(4gwfZ!>WLhs@6W&05~iCLM`-XEZJ7 zp`m)!S_g#~g`k9qf{ji`59=$XGBr9lylh}f{Sf)d=+g8a5s@nP#-}R`6cme?8WJ1K z>gK)J!XY#xf`^Mmb4hEGfjVp3s)#AO7)xdp9k$yT-lglsmPR-A@yuxmye^bt1&1it{SS~|6_?Ghk)gZ2jc+-1`0d@0KFJA A!vFvP literal 0 HcmV?d00001 diff --git a/src/HTML/blockviewer.html b/src/HTML/blockviewer.html new file mode 100644 index 0000000..c67aa65 --- /dev/null +++ b/src/HTML/blockviewer.html @@ -0,0 +1,131 @@ + + + + + Block + + + + + + + + + + + + + + + +
    + +
    +
    +
    +
    +
    + + Transactions on block: +
    +
    +
    +
    +
    + + + +
    +
    + + + + + + + + + + + +
    TrNumTypeBodyJSONTxIDBytesPowerVerify
    +
    +
    +
    +
    + + + + + diff --git a/src/HTML/chains.html b/src/HTML/chains.html new file mode 100644 index 0000000..dd30074 --- /dev/null +++ b/src/HTML/chains.html @@ -0,0 +1,1457 @@ + + + + Chains + + + + + + + + + + + + + + + +
    + + + + +
    +
    +
    +
    +
    + + +
    +
    + + + +Use sound alert
    +
    + + + + + + + + + + + + + + + + diff --git a/src/HTML/console.html b/src/HTML/console.html new file mode 100644 index 0000000..651ccf1 --- /dev/null +++ b/src/HTML/console.html @@ -0,0 +1,515 @@ + + + + + Console + + + + + + + + + + + + + + + + + + + + + + +
    + CONSOLE + +

    +
    ...

    + + + Mode: + + + POW: Delta BlockNum: + +
    + +
    +
    + +
    + +
    +
    +
    + + Name: + +
    + +
    + + + + + + + sec + TX process: + + +
    + +
    + + +
    +
    + + +
    + + diff --git a/src/HTML/dapp-edit.html b/src/HTML/dapp-edit.html new file mode 100644 index 0000000..9f038d0 --- /dev/null +++ b/src/HTML/dapp-edit.html @@ -0,0 +1,1048 @@ + + + + + Dapps IDE (simple) + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + + + +
    +
    -----------------------
    + +
    + + + +
    +
    + Log from node: +

    +
    +
    +
    + + + + + diff --git a/src/HTML/dapp-frame.html b/src/HTML/dapp-frame.html new file mode 100644 index 0000000..e46d385 --- /dev/null +++ b/src/HTML/dapp-frame.html @@ -0,0 +1,594 @@ + + + + + + + + DAPP Loading... + + + + + + + + + + + + + + +
    + + + + diff --git a/src/HTML/history.html b/src/HTML/history.html new file mode 100644 index 0000000..f832703 --- /dev/null +++ b/src/HTML/history.html @@ -0,0 +1,253 @@ + + + + + History account + + + + + + + + + + + + + + +
    +
    + +
    + +
    +
    +
    +
    +
    +
    +
    + + History of +
    +
    +
    Balance: 000
    +
    +
    +
    + + + + +
    + +
    + + + + + + + + + + + + + +
    ...FromToDateAmountCurDescriptionConfirmBlockTx
    +
    +
    +
    +
    +
    + + + \ No newline at end of file diff --git a/src/HTML/mobile-wallet.html b/src/HTML/mobile-wallet.html new file mode 100644 index 0000000..d903f57 --- /dev/null +++ b/src/HTML/mobile-wallet.html @@ -0,0 +1,716 @@ + + + + + TERA Mobile + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + +
    + +
    +
    + +
    +
    +
    + + + + +
    +

    Welcome to TERA Wallet

    +

    ATTENTION: Before using the wallet, save the private key.

    + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + +
    + +
    + +
    +
    +
     
    + + + + + +
    +
    + + + + + +
    +
    + + +
    + +
    + + + + + + + + diff --git a/src/HTML/monitor.html b/src/HTML/monitor.html new file mode 100644 index 0000000..900c1f7 --- /dev/null +++ b/src/HTML/monitor.html @@ -0,0 +1,832 @@ + + + + Monitor + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + + + +
    +
    + + +
    +
    +
    +
    Blockchain Power
    + Adviser: + Miner: + <= + + Nonce: + + Block start: length: + + + + + +
    + + + + + +
    +
    +
    +
    + +
    +
    + New diagram + + + + +
    +
    +
    + + +
    + + + + + + diff --git a/src/HTML/network.html b/src/HTML/network.html new file mode 100644 index 0000000..d76edb6 --- /dev/null +++ b/src/HTML/network.html @@ -0,0 +1,530 @@ + + + + + Network + + + + + + + + + + + + + + + + + + + + +
    + NETWORK
    + Max nodes on level: + + +

    + +
    + + + + + + + + + + + + + + +
    LNode1Node2Node3Node4Node5Node6Node7ConnectedNot connected
    + + +
    +
    +
    + + +
    +
    + + + \ No newline at end of file diff --git a/src/HTML/password.html b/src/HTML/password.html new file mode 100644 index 0000000..559babb --- /dev/null +++ b/src/HTML/password.html @@ -0,0 +1,339 @@ + + + + + Password + + + + + + + + +
    + ENTER PASSWORD +
    + +
    +
    +
    + + diff --git a/src/HTML/stat.html b/src/HTML/stat.html new file mode 100644 index 0000000..76143a2 --- /dev/null +++ b/src/HTML/stat.html @@ -0,0 +1,382 @@ + + + + Counters + + + + + + + + + + + + + + + + + + + +
    + +
    + +

    Performance counters

    + +
    + Filter: +
    + +
    + + + + + + + + + + + + + + + +
    Counters10 sec10 mintotalDiagr
    Total
    + +
    + + + + + + + + + + + + + + + +
    Errors10 sec10 mintotalDiagr
    Total
    + + + +
    + + +
    + + + +
    +
    + + + + + diff --git a/src/HTML/tera.ico b/src/HTML/tera.ico new file mode 100644 index 0000000000000000000000000000000000000000..bffcf5650b9d2d46a1c51ff8c87a56f8421077e7 GIT binary patch literal 9662 zcmeI1YiL|W6vyvAnpfT3n4mSKb~j3}r4pjptRGA_!9)`UjUR$vT8L1p^@S(|MRZfC z7}P*p^@E^L5w%8JDuOQzrV@pseo*n#v)(%7qh*SMcB1*jRzW92C~T z|9lPf_4O5Hv)Oo0PfsEjw3VyAx3{;Hv=5Q@A?nKfbfrH@99a~!PspZh%bu(6xKFna z+Tx1UV=vUz)wQCfrDa1Vli8e$#>U1i)Ne|s)9YigSY>N#YjJyfds|aeQ?FN_y3Im; z8X6iNtgEYQBR;RsX=^?nk5|;!*Iz3i>St_tZ8tYJ-=kPHe`X9Cdn%PmhQr|Y@9{6%3kdizWtA2||@MqfxKlPUD4*`mAv zu7tfHqkbHrtshoE0`7y~!B1cHe@yC?yW^gWJw)3%@Cy6`Haq)hzX}$3?M&LLpluV3 zfX$BLy&GbnV{#CJeD6W06~b=clsQqI+u>KR`BY2~L8ZID`!j8tiwoc#&^-IuQ`@I- zF%-i(I0%0Fs{b3Fhb6`*pTn>UK7=5D@1c{1Y3s(=GLm-1b2Iz^LGe6;P8BSMCqXgV z`pD)DP%MA^od#PW==)Z`TcO0nX_M$Jh3zm3ws^jyeJzxLz6*UPHhs7viu1g4Xe$=sW-y!s}pLH}d@zTmdS8rg#s)YY?<=X{^0)%)aG~*ITBKa`}9C8-n(h&(XOQ zw2nGK@!7_#F&qxikcB4K3D>J{CFIKa@jUMwfzV;f%V+> z#_TQAUokxmLGz_CUJs?P3O<0K82#Gi>sdGx{?pu>anL^km%ta`=TG%o6N8|=ZuG><7~xBxPIYL#@|;zGZ9{!CKInWs5`ey#tgtI$s|F<+rVm zX*-DCb&yxi`i&L4XTTE>v?lhTqnt7Ko1k-9@yq5@u-MOkzV+BvE;qr)VCKv#M`?Qr zszGPSN_ZcaK=EG&Ly&8|m^$TbKP;P#7;Qd?L3_ONS#l}p>@_)I;`Pb{=&XhlazC@hH`6v^ zQO@27KY=%1cUgPvqp)bEwr4|6@qo_%pqy2%Tm;kJ1IFP*v<`RUKcdg4yPbFdv! z^D#zSO#Dt2uCA_LSyNM!?&#>4llz%1zL~V~J6lA|M7N+bJI`)~c`nTJJX-?_NAE4H za=>vi13X=Iv#$^Eq=HOzBdJg5scTs8J9*=YERy7+8P+d2xr3Lj$LwCKmJiR5=RM@ag=mR9A#8C5=U8;k70oK^Qxbc?3XGJ^BbdE b9^!qn%0`YPC(5Il>GDW+qCCc*^zHIrO3mUB literal 0 HcmV?d00001 diff --git a/src/HTML/wallet.html b/src/HTML/wallet.html new file mode 100644 index 0000000..2d55ea0 --- /dev/null +++ b/src/HTML/wallet.html @@ -0,0 +1,2063 @@ + + + + + + + TERA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +
    + + + + + + + + +
    CONFIG
    SEND
    DApps
    EXPLORER
    + + + +
     
    +


    + +
    +
    +
    +
    + + +
    +
    + + +
    + +
    + + +

    +
    + Block: + DB delta: + TX delta: + Time delta: + Wallet ver: + Max: tps +
    + + + + + + +
    + + + + + +
    + + +
    + + + + + + + + + + + + +
    IDAmountCurNameOPAdvSmart
    + +
    + + + + + + + +
    + + + + + +
    + + + Style: + + + + +
    + + + + + + + + + + + + + +
    +
    +
    + Log from node: +

    +
    + + + + + + + + + + + + + + +
    + +
    + + + +
    + Web + ANN + Twitter + Telegram + Discord + QQ + +
    + diff --git a/src/HTML/web-wallet.html b/src/HTML/web-wallet.html new file mode 100644 index 0000000..a6c2fa7 --- /dev/null +++ b/src/HTML/web-wallet.html @@ -0,0 +1,669 @@ + + + + + TERA WALLET + + + + + + + + + + + + + + + + + + + +
    +
    + +
    + + +
    + +
    +
    + +
    +
    +
    + + + + +
    +

    Welcome to TERA Wallet

    +

    ATTENTION: Before using the wallet, save the private key.

    + + + + +
    + + + + + + + + + + + + + + +
    + + + + + + + + + + + +
    + + + + + + +
    + +
    + +
    +
    +
     
    + + + + + +
    +
    + + + + + +
    +
    + + +
    + +
    + + + + + + + + diff --git a/src/a.sh b/src/a.sh new file mode 100755 index 0000000..e74c3d8 --- /dev/null +++ b/src/a.sh @@ -0,0 +1,6 @@ +#!/bin/bash +EXT=js +DIST=ts +for name in `ls *.${EXT}`; do + mv $name ${name%.${EXT}}.${DIST} +done diff --git a/src/core/api/api-exchange.ts b/src/core/api/api-exchange.ts new file mode 100644 index 0000000..b11574d --- /dev/null +++ b/src/core/api/api-exchange.ts @@ -0,0 +1,40 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://web.telegram.org/#/im?p=@terafoundation +*/ +import * as crypto from 'crypto' +global.HTTPCaller.CreateAccount = function(Params, response) { + if (typeof Params === "object" && Params.Name && Params.PubKey) { + var TYPE_TRANSACTION_CREATE = 100; + var TR = { + Type: global.TYPE_TRANSACTION_CREATE, Currency: Params.Currency, PubKey: global.GetArrFromHex(Params.PubKey), Description: Params.Name, + Smart: Params.Smart, Adviser: 0, + }; + var Body = global.BufLib.GetBufferFromObject(TR, global.global.FORMAT_CREATE, 1000, {}); + return { result: 1 }; + } + return { result: 0 }; +}; +var MaxCountViewRows = global.HTTP_MAX_COUNT_ROWS; +global.HTTPCaller.GetBalance = function(Params) { + if (typeof Params === "object") { + var arr = global.DApps.Accounts.GetRowsAccounts(ParseNum(Params.AccountID), 1); + if (arr.length) { + arr[0].result = 1; + return arr[0]; + } + } + return { result: 0 }; +}; +global.HTTPCaller.GenerateKeys = function(Params) { + var KeyPair = crypto.createECDH('secp256k1'); + var PrivKey = global.sha3(crypto.randomBytes(32)); + KeyPair.setPrivateKey(Buffer.from(PrivKey)); + var PubKey = KeyPair.getPublicKey('' as any, 'compressed'); + return { result: 1, PrivKey: global.GetHexFromArr(PrivKey), PubKey: global.GetHexFromArr(PubKey) }; +}; diff --git a/src/core/api/api-wallet.ts b/src/core/api/api-wallet.ts new file mode 100644 index 0000000..8659b5d --- /dev/null +++ b/src/core/api/api-wallet.ts @@ -0,0 +1,10 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://web.telegram.org/#/im?p=@terafoundation +*/ + diff --git a/src/core/base.ts b/src/core/base.ts new file mode 100644 index 0000000..246feb0 --- /dev/null +++ b/src/core/base.ts @@ -0,0 +1,390 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +require("./library.js"); +require("./crypto-library"); +require("./terahashmining"); +import * as crypto from 'crypto'; +const os = require('os'); +global.glStopNode = false; +const MAX_TIME_NETWORK_TRANSPORT = 1 * 1000; +var GlSumUser; +var GlSumSys; +var GlSumIdle; +global.CountAllNode = 0; +module.exports = class CCommon importasdasd { + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + global.SERVER = this + this.VirtualMode = bVirtual + this.KeyPair = SetKeyPair + var PubKey = SetKeyPair.getPublicKey('', 'compressed'); + this.PubKeyType = PubKey[0] + this.addrArr = PubKey.slice(1) + this.addrStr = global.GetHexFromArr(this.addrArr) + this.HashDBArr = shaarr2(this.KeyPair.getPrivateKey(), [0, 0, 0, 0, 0, 0, 0, 1]) + this.ServerSign = [] + } + AddStatOnTimer() { + var CountAll = 0; + var CurTime = global.GetCurrentTime() - 0; + for (var i = 0; i < this.NodesArr.length; i++) { + var Item = this.NodesArr[i]; + if (Item.LastTime && (CurTime - Item.LastTime) < NODES_DELTA_CALC_HOUR * 3600 * 1000) + CountAll++ + else + if (Item.LastTimeGetNode && (CurTime - Item.LastTimeGetNode) < NODES_DELTA_CALC_HOUR * 3600 * 1000) + CountAll++ + } + global.CountAllNode = CountAll + if (!global.STAT_MODE) + return; + var StateTX = global.DApps.Accounts.DBStateTX.Read(0); + if (StateTX) { + var Delta = this.CurrentBlockNum - StateTX.BlockNum; + global.ADD_TO_STAT("MAX:DELTA_TX", Delta) + } + var bHasCP = 0; + if (CHECK_POINT.BlockNum) { + var Block = this.ReadBlockHeaderDB(CHECK_POINT.BlockNum); + if (Block && global.CompareArr(CHECK_POINT.Hash, Block.Hash) === 0) + bHasCP = 1 + } + var MinVer = global.MIN_VER_STAT; + if (MinVer === 0) + MinVer = global.UPDATE_CODE_VERSION_NUM + var BufMap = {}, BufMap2 = {}; + var arr = this.GetActualNodes(); + var Count = 0, CountHot = 0, CountHotOK = 0, CountActualOK = 0, SumDeltaHot = 0, SumDeltaActual = 0, CountCP = 0, CountLH = 0, + CountHash = 0, CountVer = 0, CountStop = 0; + var CountAutoCorrectTime = 0; + var SumAvgDeltaTime = 0; + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + if (!Node || Node.IsAddrList) + continue; + var INFO = Node.INFO; + if (!INFO) + INFO = {} + if (bHasCP && CHECK_POINT.BlockNum && INFO.CheckPointHashDB && global.CompareArr(CHECK_POINT.Hash, INFO.CheckPointHashDB) === 0) { + CountCP++ + } + if (INFO.LoadHistoryMode) + CountLH++ + if (Node.StopGetBlock) + CountStop++ + Count++ + SumAvgDeltaTime += Node.DeltaGlobTime + if (Node.VersionNum >= MinVer) + CountVer++ + if (INFO && INFO.BlockNumDB && INFO.BlockNumDB <= this.BlockNumDB) { + var HashDB = ReadHashFromBufDB(BufMap2, INFO.BlockNumDB); + if (HashDB && global.CompareArr(HashDB, INFO.HashDB) === 0) + CountHash++ + } + var StrChk = GetCheckAccHash(BufMap, INFO.AccountBlockNum, INFO.AccountsHash); + var Chck = 0; + if (StrChk.indexOf("=OK=") >= 0) { + Chck = 1 + } + var DeltaTime = Node.DeltaTime; + if (!DeltaTime) + DeltaTime = 0 + CountActualOK += Chck + SumDeltaActual += DeltaTime + if (Node.Hot) { + CountHot++ + CountHotOK += Chck + SumDeltaHot += DeltaTime + } + if (INFO.AutoCorrectTime) + CountAutoCorrectTime++ + } + global.ADD_TO_STAT("MAX:ALL_NODES", CountAll) + global.ADD_TO_STAT("MAX:CONNECTED_NODES", Count) + global.ADD_TO_STAT("MAX:HOT_NODES", CountHot) + global.ADD_TO_STAT("MAX:HOT_OK", CountHotOK) + global.ADD_TO_STAT("MAX:ACTUAL_OK", CountActualOK) + global.ADD_TO_STAT("MAX:CHECK_POINT_OK", CountCP) + global.ADD_TO_STAT("MAX:COUNTLH", CountLH) + global.ADD_TO_STAT("MAX:HASH_OK", CountHash) + global.ADD_TO_STAT("MAX:MIN_VERSION", CountVer) + global.ADD_TO_STAT("MAX:STOP_GET", CountStop) + global.ADD_TO_STAT("MAX:AUTOCORRECT", CountAutoCorrectTime) + global.ADD_TO_STAT("MAX:TIME_DELTA", DELTA_CURRENT_TIME) + if (!Count) + Count = 1 + if (!CountHot) + CountHot = 1 + if (Count >= 20) { + var SumDeltaAvg = 0; + var AvgGlobTime = SumAvgDeltaTime / Count; + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + if (!Node || Node.IsAddrList) + continue; + var Delta = AvgGlobTime - Node.DeltaGlobTime; + SumDeltaAvg += Delta * Delta + } + SumDeltaAvg = Math.sqrt(SumDeltaAvg / Count) + global.ADD_TO_STAT("MAX:DELTA_GLOB_TIME", 100 + AvgGlobTime) + global.ADD_TO_STAT("MAX:DISP_DELTA_GLOB_TIME", SumDeltaAvg) + arr.sort(function(a, b) { + return a.DeltaGlobTime - b.DeltaGlobTime; + }) + var SumDeltaAvgM = 0; + var AvgGlobTimeM = arr[Math.trunc(arr.length / 2)].DeltaGlobTime; + var Length = arr.length; + var Start = Math.trunc(Length * 0.05); + var End = Math.trunc(Length * 0.95); + var NodesCount = 0; + for (var i = Start; i < End; i++) { + var Node = arr[i]; + if (!Node || Node.IsAddrList) + continue; + NodesCount++ + var Delta = AvgGlobTimeM - Node.DeltaGlobTime; + SumDeltaAvgM += Delta * Delta + } + if (!NodesCount) + NodesCount = 1 + SumDeltaAvgM = Math.sqrt(SumDeltaAvgM / NodesCount) + global.ADD_TO_STAT("MAX:MEDIAN_GLOB_TIME", 100 + AvgGlobTimeM) + global.ADD_TO_STAT("MAX:DISP_MEDIAN_GLOB_TIME", SumDeltaAvgM) + } + global.ADD_TO_STAT("MAX:DELTA_TIME_HOT", SumDeltaHot / CountHot) + global.ADD_TO_STAT("MAX:DELTA_TIME_ACTUAL", SumDeltaActual / Count) + global.ADD_TO_STAT("MAX:MEMORY_USAGE", process.memoryUsage().heapTotal / 1024 / 1024) + global.ADD_TO_STAT("MAX:MEMORY_FREE", os.freemem() / 1024 / 1024) + var SumUser = 0; + var SumSys = 0; + var SumIdle = 0; + var cpus = os.cpus(); + for (var i = 0; i < cpus.length; i++) { + var cpu = cpus[i]; + SumUser += cpu.times.user + SumSys += cpu.times.sys + cpu.times.irq + SumIdle += cpu.times.idle + } + if (GlSumUser !== undefined) { + var maxsum = cpus.length * 1000; + global.ADD_TO_STAT("MAX:CPU_USER_MODE", Math.min(maxsum, SumUser - GlSumUser)) + global.ADD_TO_STAT("MAX:CPU_SYS_MODE", Math.min(maxsum, SumSys - GlSumSys)) + global.ADD_TO_STAT("MAX:CPU_IDLE_MODE", Math.min(maxsum, SumIdle - GlSumIdle)) + global.ADD_TO_STAT("MAX:CPU", Math.min(maxsum, SumUser + SumSys - GlSumUser - GlSumSys)) + } + GlSumUser = SumUser + GlSumSys = SumSys + GlSumIdle = SumIdle + } + GetNewMeta() { + return crypto.randomBytes(32); + } +}; +class SMemBuffer { + MetaMap1 + MetaMap2 + CheckName + constructor(MaxTime, CheckName) { + this.MetaMap1 = {} + this.MetaMap2 = {} + this.CheckName = CheckName + setInterval(this.ShiftMapDirect.bind(this), MaxTime) + } + GetStrKey(Arr) { + if (typeof Arr === "number" || typeof Arr === "string") { + return Arr; + } else { + return GetHexFromAddres(Arr); + } + throw "NOT RET!"; + } + LoadValue(Arr, bStay) { + if (!Arr) + return undefined; + var Key = this.GetStrKey(Arr); + var Value = this.MetaMap1[Key]; + if (Value !== undefined) { + if (!bStay) + delete this.MetaMap1[Key] + return Value; + } + Value = this.MetaMap2[Key] + if (Value !== undefined) { + if (!bStay) + delete this.MetaMap2[Key] + } + return Value; + } + SaveValue(Arr, Value) { + var Key = this.GetStrKey(Arr); + if (Value !== undefined) + this.MetaMap1[Key] = Value + } + ShiftMapDirect() { + if (glStopNode) + return; + if (this.CheckName) { + var Count = 0; + for (var key in this.MetaMap2) { + Count++ + } + if (Count) { + global.ADD_TO_STAT(this.CheckName, 1, 1) + } + } + this.MetaMap2 = this.MetaMap1 + this.MetaMap1 = {} + } + Clear() { + this.MetaMap2 = {} + this.MetaMap1 = {} + } +}; +class STreeBuffer { + constructor(MaxTime, CompareFunction?, KeyType?, CheckName?) { + this.KeyType = KeyType + this.MetaTree1 = new RBTree(CompareFunction) + this.MetaTree2 = new RBTree(CompareFunction) + this.CheckName = CheckName + setInterval(this.ShiftMapDirect.bind(this), MaxTime) + } + LoadValue(Hash, bStay) { + if (!Hash) + return undefined; + if (typeof Hash !== this.KeyType) + throw "MUST ONLY HASH ARRAY: " + Hash; + var element = this.MetaTree1.find({ hash: Hash }); + if (element) { + if (!bStay) + this.MetaTree1.remove(element) + return element.value; + } + element = this.MetaTree2.find({ hash: Hash }) + if (element) { + if (!bStay) + this.MetaTree2.remove(element) + return element.value; + } + return undefined; + } + SaveValue(Hash, Value) { + if (typeof Hash !== this.KeyType) + throw "MUST ONLY TYPE=" + this.KeyType + " in " + Hash; + if (Value !== undefined) { + var element = this.MetaTree1.find({ hash: Hash }); + if (element) + element.value = Value + else + this.MetaTree1.insert({ hash: Hash, value: Value }) + } + } + ShiftMapDirect() { + if (this.CheckName && this.MetaTree2.size) { + global.ADD_TO_STAT(this.CheckName, this.MetaTree2.size, 1) + var it = this.MetaTree2.iterator(), Item; + while ((Item = it.next()) !== null) { + var Name = Item.value.Name; + global.ADD_TO_STAT(this.CheckName + ":" + Name, 1, 1) + } + } + this.MetaTree2.clear() + var empty_tree = this.MetaTree2; + this.MetaTree2 = this.MetaTree1 + this.MetaTree1 = empty_tree + } + Clear() { + this.MetaTree1.clear() + this.MetaTree2.clear() + } +}; + +function ReadHashFromBufDB(Map, BlockNum) { + var MyHash = Map[BlockNum]; + if (!MyHash) { + var Block = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (Block) + MyHash = Block.Hash; + else + MyHash = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + Map[BlockNum] = MyHash; + } + return MyHash; +}; + +function GetCheckAccHash(Map, BlockNum, Hash) { + var MyHash = Map[BlockNum]; + if (!MyHash) { + MyHash = global.DApps.Accounts.GetHashOrUndefined(BlockNum); + Map[BlockNum] = MyHash; + } + if (MyHash) { + if (!Hash) + return "=ERR:NO="; + if (global.CompareArr(Hash, MyHash) !== 0) + return "=ERR:BAD="; + else + return "=OK="; + } + else { + if (!Hash) + return "=OK=:NO"; + else + return "=MY:NO="; + } +}; +global.GetCheckAccHash = GetCheckAccHash; +global.ReadHashFromBufDB = ReadHashFromBufDB; +global.STreeBuffer = STreeBuffer; +global.TestCreateTr = TestCreateTr; + +function TestCreateTr() { + const FORMAT_CREATE = "{\ + Type:byte,\ + Currency:uint,\ + PubKey:arr33,\ + Description:str40,\ + Adviser:uint,\ + Reserve:arr7,\ + POWCreate:arr12,\ + }"; + var TR = { + Type: 100, Currency: 0, PubKey: [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0], Description: "Description", Adviser: 10, + }; + var Body = global.BufLib.GetBufferFromObject(TR, global.FORMAT_CREATE, 1000, {}); + var startTime = process.hrtime(); + var StartData = Date.now(); + var nonce = CreateHashBodyPOWInnerMinPower(Body, 1000, 17); + var Time = process.hrtime(startTime); + var power = GetPowPower(shaarr(Body)); + var deltaTime = (Time[0] * 1000 + Time[1] / 1e6) / 1000; + var DeltaData = (new Date() - StartData) / 1000; + global.ToLog("power=" + power + " nonce=" + nonce + " TIME=" + deltaTime + " sec" + " DeltaData=" + DeltaData + " sec"); + return { time1: deltaTime, time2: DeltaData }; +}; + +function CreateHashBody(body, Num, Nonce) { + body.writeUIntLE(Num, body.length - 12, 6); + body.writeUIntLE(Nonce, body.length - 6, 6); + return global.shaarr(body); +}; + +function CreateHashBodyPOWInnerMinPower(arr, BlockNum, MinPow) { + var nonce = 0; + while (1) { + var arrhash = CreateHashBody(arr, BlockNum, nonce); + var power = GetPowPower(arrhash); + if (power >= MinPow) { + return nonce; + } + nonce++; + } +}; diff --git a/src/core/block-exchange.ts b/src/core/block-exchange.ts new file mode 100644 index 0000000..149b353 --- /dev/null +++ b/src/core/block-exchange.ts @@ -0,0 +1,1376 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +require('./library'); +require('./crypto-library'); +const TX_PROCESS_TIME = 100; +const TX_DELTA_PROCESS_TIME = 300; +global.CAN_START = false; +global.StrWarn = ""; +global.SUM_LIST_LENGTH = 2 * BLOCK_PROCESSING_LENGTH; +global.CONSENSUS_TIK_TIME = CONSENSUS_PERIOD_TIME / 10; +global.CONSENSUS_CHECK_TIME = CONSENSUS_PERIOD_TIME / 20; +const PERIOD_FOR_NEXT_SEND = CONSENSUS_TIK_TIME * 3; +global.BLOCK_DELTA_ACTIVATE = 0; +global.TIME_END_EXCHANGE = - 3; +global.TIME_START_POW = - 4; +global.TIME_START_SAVE = - 4; +global.TIME_START_LOAD = global.TIME_START_SAVE - 4; +var FORMAT_DATA_TRANSFER = "{\ + Version:uint16,\ + BlockNum:uint,\ + Reserv1:uint32,\ + MaxPOW:[{BlockNum:uint,AddrHash:hash,SeqHash:hash}],\ + Reserv2:uint32,\ + BaseBlockNum:uint,\ + MaxSumID:[{BlockNum:uint,SumHash:hash,SumListID:[uint16]}],\ + BlockList:[{ID:uint16, AddrHash:hash,SeqHash:hash}],\ + TicketArray:[{HashTicket:arr10}],\ + TxArray:[{body:tr}],\ + NoSendTx:uint,\ + }"; +const WorkStructSend = {}; +module.exports = class CConsensus extends require("./block-loader") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.CurrentBlockNum = 0 + this.SendBlockID = 0 + this.RelayMode = false + this.TreeSendPacket = new RBTree(CompareItemHash) + if (!global.ADDRLIST_MODE && !this.VirtualMode) { + this.idBlockChainTimer = setInterval(this.StartBlockChain.bind(this), CONSENSUS_PERIOD_TIME - 5) + setInterval(this.DoTransfer.bind(this), CONSENSUS_CHECK_TIME) + } + } + StartBlockChain() { + this.OnStartSecond() + var CurTimeNum = global.GetCurrentTime() - CONSENSUS_PERIOD_TIME / 2; + var StartTimeNum = Math.floor((CurTimeNum + CONSENSUS_PERIOD_TIME) / CONSENSUS_PERIOD_TIME) * CONSENSUS_PERIOD_TIME; + var DeltaForStart = StartTimeNum - CurTimeNum; + if (DeltaForStart < (CONSENSUS_PERIOD_TIME - 5)) { + var self = this; + if (self.idBlockChainTimer) + clearInterval(self.idBlockChainTimer) + self.idBlockChainTimer = 0 + setTimeout(function() { + self.idBlockChainTimer = setInterval(self.StartBlockChain.bind(self), CONSENSUS_PERIOD_TIME) + self.OnStartSecond() + }, DeltaForStart) + } + } + OnStartSecond() { + PrepareStatEverySecond() + this.AddStatOnTimer() + this.DoBlockChain() + } + CreateBlockContext() { + var Context = {}; + Context.AddInfo = AddInfoBlock.bind(Context) + Context.Active = false + Context.TransferFromAddr = {} + Context.LevelsTransfer = [] + Context.ErrRun = "" + Context.PowTxTree = new RBTree(CompareItemTimePow) + Context.PowTicketTree = new RBTree(CompareItemTimePow) + Context.bSave = false + Context.PrevHash = undefined + Context.TreeHash = undefined + Context.MaxPOW = {} + Context.MaxSum = {} + Context.SumPow = 0 + Context.Power = 0 + Context.TrCount = 0 + Context.TrDataPos = 0 + Context.TrDataLen = 0 + Context.Info = "Create at:" + GetStrOnlyTimeUTC() + var Transfer; + var TransferM2; + var LocalLevel = 0; + var Levels = this.LevelNodes; + for (let L = 0; L < Levels.length; L++) { + var arr = Levels[L]; + if (arr && arr.length > 0) { + Transfer = { + LocalLevel: LocalLevel, TreeLevel: L, SendCount: 0, GetCount: 0, TransferNodes: {}, WasGet: false, WasSend: false, MustDeltaTime: CONSENSUS_TIK_TIME * (2 + MAX_LEVEL_SPECIALIZATION - L), + } + LocalLevel++ + Context.LevelsTransfer.push(Transfer) + Context.StartLevel = Context.LevelsTransfer.length - 1 + for (let j = 0; j < arr.length; j++) { + var Node = arr[j]; + var Addr = Node.addrStr; + if (!Transfer.TransferNodes[Addr]) { + let Item = { Node: Node, SendCount: 0, GetCount: 0, addrStr: Addr, TreeLevel: L, GetTiming: 3 * CONSENSUS_PERIOD_TIME, }; + Transfer.TransferNodes[Addr] = Item + } + Context.TransferFromAddr[Addr] = Transfer + } + } + } + Context.MLevelSend = Context.StartLevel + return Context; + } + StartConsensus() { + if (!CAN_START) + return; + var StartBlockNum = GetCurrentBlockNumByTime(); + if (StartBlockNum < global.BLOCK_PROCESSING_LENGTH2) + return; + this.CurrentBlockNum = StartBlockNum + var Block0 = this.GetBlockContext(StartBlockNum - BLOCK_DELTA_ACTIVATE); + if (!Block0.Active) { + AddInfoBlock(Block0, "Activate") + this.StartBlock(Block0) + } + else { + AddInfoBlock(Block0, "Was Active") + } + } + TrToInfo(Block, Array, StrInfo) { + var Str = ""; + for (var i = 0; i < Array.length; i++) { + var Item = Array[i]; + this.CheckCreateTransactionObject(Item) + Str += this.GetStrFromHashShort(shaarr(Item.body)) + "(" + Item.body.length + ")," + } + AddInfoBlock(Block, "" + StrInfo + ": Arr=[" + Str + "]") + } + TRANSFER(Info, CurTime) { + var startTime = process.hrtime(); + var Data = this.DataFromF(Info); + var Node = Info.Node; + Node.TransferBlockNum = Data.BlockNum + Node.CurBlockNum = Data.BaseBlockNum + Data.BlockNum + if (Data.Version !== 5) + return; + var Block = this.GetBlockContext(Data.BlockNum); + if (!Block || Block.StartLevel === undefined) { + global.ADD_TO_STAT("TRANSFER_ERR_STARTLEVEL") + this.AddCheckErrCount(Node, 1, "Err GetBlockContext") + return; + } + if (!Block.Active) + this.StartBlock(Block) + var Key = Node.addrStr; + var Transfer = Block.TransferFromAddr[Key]; + if (!Transfer) { + global.ADD_TO_STAT("NO_TRANSFER") + this.AddCheckErrCount(Node, 1, "Err Transfer") + return; + } + Transfer.WasGet = true + if (global.DoTxLog && Data.TicketArray.length) + global.ToLog("TRANSFER BlockNum:" + Block.BlockNum + " TicketArray=" + Data.TicketArray.length + " from " + NodeName(Node)) + if (global.DoTxLog && Data.TxArray.length) + global.ToLog("TRANSFER BlockNum:" + Block.BlockNum + " TxArray=" + Data.TxArray.length + " from " + NodeName(Node)) + this.ToMaxPOWList(Data.MaxPOW) + this.ToMaxSumList(this.GetMaxSumListFromID(Node, Data.MaxSumID, Data.BlockList)) + var WasNewAdd = 0; + if (Data.TxArray.length) { + for (var i = 0; i < Data.TxArray.length; i++) { + var Tr = Data.TxArray[i]; + var Res = this.AddTrToBlockQuote(Block, Tr); + if (Res === 1) + WasNewAdd = 1 + if (global.USE_CHECK_SENDING && Res > 0) { + var Tt = Block.PowTxTree.find(Tr); + if (Tt) { + if (!Tt.NodesList) + Tt.NodesList = [] + Tt.NodesList.push(Node) + Tt.TreeLevel = Transfer.TreeLevel + } + } + } + } + else { + for (var i = 0; i < Data.TicketArray.length; i++) { + var Tr = this.AddTicketToBlockQuote(Block, Data.TicketArray[i]); + if (Tr) { + if (!Tr.NodesList) + Tr.NodesList = [] + Tr.NodesList.push(Node) + } + } + } + ADD_TO_STAT_TIME("TRANSFER_MS", startTime) + var Delta = Date.now() - this.StartLoadBlockTime; + if (Delta > 10 * 1000 && Node.TransferCount > 10) { + Node.BlockProcessCount++ + Node.NextHotDelta = 10 * 1000 + } + Node.TransferCount++ + Node.LastTimeTransfer = global.GetCurrentTime() - 0 + var Item = Transfer.TransferNodes[Key]; + Item.GetTiming = GetCurrentTime(Block.DELTA_CURRENT_TIME) - Block.StartTimeNum + if (!Block.TransferNodesCount) + Block.TransferNodesCount = 0 + Block.TransferNodesCount++ + } + DoTransfer() { + if (glStopNode) + return; + if (!CAN_START) + return; + var MaxPOWList; + var MaxSumList; + var start = this.CurrentBlockNum - BLOCK_PROCESSING_LENGTH; + var finish = this.GetLastCorrectBlockNum(); + for (var b = start; b <= finish; b++) { + var Block = this.GetBlock(b); + if (!Block) + continue; + if (Block.StartLevel === undefined || Block.MLevelSend === undefined) + continue; + if (!Block.Active) + continue; + if (global.USE_TICKET) + this.DoJobListTX(Block) + if (Block.MLevelSend < 0) { + this.CheckEndExchange(Block) + continue; + } + if (Block.EndExchange) + continue; + var Transfer = Block.LevelsTransfer[Block.MLevelSend]; + if (!Transfer.WasSend) { + if (!MaxPOWList) { + MaxPOWList = this.GetMaxPOWList() + MaxSumList = this.GetMaxSumList() + } + var ArrT; + if (global.USE_TICKET) + ArrT = this.GetArrayFromTicketTree(Block) + else + ArrT = this.GetArrayFromTxTree(Block) + this.SendDataTransfer(Transfer, ArrT, MaxPOWList, MaxSumList, Block) + } + Transfer.WasSend = true + var bNext = Transfer.WasGet; + if (!bNext) { + var CurTimeNum = GetCurrentTime(Block.DELTA_CURRENT_TIME) - 0; + var DeltaTime = CurTimeNum - Block.StartTimeNum; + if (DeltaTime > Transfer.MustDeltaTime) { + bNext = true + Block.ErrRun = "" + Transfer.LocalLevel + " " + Block.ErrRun + for (var Addr in Transfer.TransferNodes) { + var Item = Transfer.TransferNodes[Addr]; + global.ADD_TO_STAT("TRANSFER_TIME_OUT") + this.AddCheckErrCount(Item.Node, 1, "TRANSFER_TIME_OUT") + } + global.ADD_TO_STAT("TimeOutLevel") + } + } + if (bNext) { + if (Block.MLevelSend === 0) { + Block.EndExchangeTime = Date.now() + if (!global.USE_TICKET) + this.CheckEndExchange(Block) + } + Block.MLevelSend-- + } + } + } + CheckEndExchange(Block) { + if (Block.EndExchange) + return; + if (!global.USE_TICKET) { + this.CreateTreeHash(Block) + return; + } + if (!Block.JobListTX || !Block.EndExchangeTime) + return; + var CurTime = Date.now(); + var Delta = CurTime - Block.EndExchangeTime; + if (Delta >= TX_DELTA_PROCESS_TIME * 2) { + if (global.DoTxLog) + global.ToLog("END:" + Block.BlockNum + " -> CreateTreeHash") + this.CreateTreeHash(Block) + } + } + SendDataTransfer(Transfer, ArrT, MaxPOWList, MaxSumList, Block) { + for (var Addr in Transfer.TransferNodes) { + var Item = Transfer.TransferNodes[Addr]; + Transfer.SendCount++ + var arrPow = []; + for (var i = 0; i < MaxPOWList.length; i++) { + var elem = MaxPOWList[i]; + var Str = "POW:" + Item.Node.id + elem.BlockNum + "-" + global.GetHexFromArr(elem.AddrHash); + var bWasSend = global.TreeBlockBuf.LoadValue(Str, 1); + if (!bWasSend) { + global.TreeBlockBuf.SaveValue(Str, true) + arrPow.push(elem) + } + } + var arrSum = []; + for (var i = 0; i < MaxSumList.length; i++) { + var elem = MaxSumList[i]; + var Str = "MAX:" + Item.Node.id + elem.BlockNum + "-" + global.GetHexFromArr(elem.SumHash); + var bWasSend = global.TreeBlockBuf.LoadValue(Str, 1); + if (!bWasSend) { + global.TreeBlockBuf.SaveValue(Str, true) + arrSum.push(elem) + } + } + var Arr; + if (global.USE_CHECK_SENDING) + Arr = this.FilterArrForSendNode(Block, Item.Node, ArrT, global.USE_TICKET) + else + Arr = ArrT + if (global.USE_LEVEL_WAY) { + var Arr2 = []; + for (var t = 0; t < Arr.length; t++) { + var Tr = Arr[t]; + if (Tr.TreeLevel !== Transfer.TreeLevel) + Arr2.push(Tr) + } + Arr = Arr2 + } + if (global.DoTxLog) + global.ToLog("SEND TRANSFER BlockNum:" + Block.BlockNum + " Arr=" + Arr.length + " to " + NodeName(Item.Node)) + var BufData = this.CreateTransferBuffer(Arr, arrPow, arrSum, Block, Item.Node); + this.Send(Item.Node, { "Method": "TRANSFER", "Context": {}, "Data": BufData }, 1) + if (!Block.JobListTX) + Block.JobListTX = [] + Block.JobListTX.push({ Node: Item.Node, TreeLevel: Item.TreeLevel, Time: Date.now() }) + } + } + TRANSFERTX(Info, CurTime) { + var Data = this.DataFromF(Info); + var Node = Info.Node; + var Block = this.GetBlockContext(Data.BlockNum); + if (!Block) { + return; + } + if (global.DoTxLog) + global.ToLog("TRANSFERTX BlockNum:" + Block.BlockNum + " Array=" + Data.Array.length + " from " + NodeName(Node)) + for (var i = 0; i < Data.Array.length; i++) { + this.AddTrToBlockQuote(Block, Data.Array[i], 1) + } + } + static + TRANSFERTX_F() { + return "{BlockNum:uint, Array:[{body:tr}]}"; + } + static + GETTRANSFERTX_F() { + return "{BlockNum:uint, TicketArray:[{HashTicket:arr10}]}"; + } + GETTRANSFERTX(Info, CurTime) { + return; + var Data = this.DataFromF(Info); + var Node = Info.Node; + var Block = this.GetBlockContext(Data.BlockNum); + if (!Block) { + return; + } + this.SendTrByTickets(Info, Node, Block, Data.TicketArray, 10) + } + CanSendTest() { + return 1; + } + SendTrByTickets(Info, Node, Block, ArrTT, CountTrySend) { + if (!Block.PowTxTree) + return; + var Arr = []; + var bFindTT = 0; + var BufLength = 0; + for (var i = 0; i < ArrTT.length; i++) { + var Tr = ArrTT[i]; + this.CheckCreateTicketObject(Tr, Block.BlockNum) + var Tr0 = Block.PowTxTree.find(Tr); + if (Tr0) { + if (Tr0.IsTx) { + if (this.CanSendTest()) + Arr.push(Tr0) + BufLength += Tr0.body.length + if (BufLength > MAX_BLOCK_SIZE) + break; + } + else { + bFindTT = 1 + } + } + } + if (bFindTT && CountTrySend) { + let SELF = this; + setTimeout(function() { + SELF.SendTrByTickets(Info, Node, Block, ArrTT, CountTrySend - 1) + }, 100) + return; + } + if (!Arr.length) + return; + var SendData = { "Method": "RETTRANSFERTX", "Context": Info.Context, "Data": { BlockNum: Block.BlockNum, Array: Arr, } }; + this.SendF(Node, SendData, global.MAX_BLOCK_SIZE + 1000) + } + static + RETTRANSFERTX_F() { + return "{BlockNum:uint,Array:[{body:tr}]}"; + } + RETTRANSFERTX(Info, CurTime) { + return; + var Data = this.DataFromF(Info); + var Node = Info.Node; + Node.TransferBlockNum = Data.BlockNum + var Block = this.GetBlockContext(Data.BlockNum); + if (!Block || !Block.PowTxTree) { + return; + } + if (global.DoTxLog) + global.ToLog("RETTRANSFERTX BlockNum:" + Block.BlockNum + " Array=" + Data.Array.length + " from " + NodeName(Node)) + for (var i = 0; i < Data.Array.length; i++) { + var Tr = Data.Array[i]; + this.CheckCreateTransactionObject(Tr) + var Tr0 = Block.PowTxTree.find(Tr); + if (Tr0) { + if (!Tr0.IsTx) { + Tr0.IsTx = 1 + Tr0.body = Tr.body + Tr0.HASH = Tr.HASH + } + } + } + } + DoJobListTX(Block) { + if (Block.EndExchange || !Block.JobListTX || !Block.PowTicketTree) + return; + var ArrTx; + var CurTime = Date.now(); + for (var i = 0; i < Block.JobListTX.length; i++) { + var JobItem = Block.JobListTX[i]; + var Delta = CurTime - JobItem.Time; + if (!JobItem.WasSend && Delta >= TX_DELTA_PROCESS_TIME) { + JobItem.WasSend = 1 + if (!ArrTx) + ArrTx = this.GetArrayFromTxTree(Block) + var Arr = this.FilterArrForSendNode(Block, JobItem.Node, ArrTx); + if (!Arr.length) + return; + if (global.DoTxLog) + global.ToLog("DoJobListTX BlockNum:" + Block.BlockNum + " Arr=" + Arr.length + " to " + NodeName(JobItem.Node)) + var SendData = { "Method": "TRANSFERTX", "Context": {}, "Data": { BlockNum: Block.BlockNum, Array: Arr, } }; + this.SendF(JobItem.Node, SendData, global.MAX_BLOCK_SIZE + 1000) + } + } + } + FindNodeTicket(Block, Tr, Node, bTt) { + var Ticket; + if (bTt) + Ticket = Tr + else + Ticket = Block.PowTicketTree.find(Tr) + if (Ticket && Ticket.NodesList) { + for (var n = 0; n < Ticket.NodesList.length; n++) { + var NodeItem = Ticket.NodesList[n]; + if (NodeItem === Node) { + return 1; + } + } + } + return 0; + } + FilterArrForSendNode(Block, Node, ArrTx, bTt) { + var Arr = []; + for (var t = 0; t < ArrTx.length; t++) { + var Tr = ArrTx[t]; + if (this.FindNodeTicket(Block, Tr, Node, bTt)) + continue; + Arr.push(Tr) + } + return Arr; + } + CheckEndExchange00(Block) { + if (Block.EndExchange) + return; + var CurTime = Date.now(); + var CanEnd = 1; + var bSend = 0; + var it = Block.PowTxTree.iterator(), Tr; + while ((Tr = it.next()) !== null) { + if (!Tr.IsTx) { + if (!Tr.LastProcessTime) + throw "!Tr.LastProcessTime"; + var Delta = CurTime - Tr.LastProcessTime; + if (Delta < TX_PROCESS_TIME * 10) { + bSend = 1 + CanEnd = 0 + break; + } + else { + var Stop = 1; + } + } + } + if (CanEnd) { + if (global.DoTxLog) + global.ToLog("END:" + Block.BlockNum + " -> CreateTreeHash") + this.CreateTreeHash(Block) + } + else + if (bSend) { + this.CheckTxExchange(Block, bSend) + } + } + CheckTxExchange(Block) { + return; + if (Block.EndExchange) + return; + if (!Block.PowTxTree) + return; + var CurTime = Date.now(); + var ArrNodesArr = []; + var it = Block.PowTxTree.iterator(), Tr; + while ((Tr = it.next()) !== null) { + if (!Tr.IsTx) { + if (!Tr.LastProcessTime) + throw "!Tr.LastProcessTime"; + var Delta = CurTime - Tr.LastProcessTime; + if (Delta >= TX_PROCESS_TIME) { + for (var i = 0; i < Tr.Nodes.length; i++) { + var TrNode = Tr.Nodes[i]; + var LocDelta = CurTime - TrNode.Time; + if (!TrNode.WasSend && LocDelta >= TX_PROCESS_TIME) { + var FindArr = undefined; + for (var n = 0; n < ArrNodesArr.length; n++) { + var ElArr = ArrNodesArr[n]; + if (ElArr.Node === TrNode.Node) { + FindArr = ElArr + break; + } + } + if (!FindArr) { + FindArr = { Node: TrNode.Node, Arr: [] } + ArrNodesArr.push(FindArr) + } + Tr.LastProcessTime = CurTime + TrNode.WasSend = 1 + FindArr.Arr.push(Tr) + break; + } + } + } + } + } + for (var n = 0; n < ArrNodesArr.length; n++) { + var ElArr = ArrNodesArr[n]; + if (global.DoTxLog) + global.ToLog("CheckTxExchange BlockNum:" + Block.BlockNum + " Array=" + ElArr.Arr.length + " to " + NodeName(ElArr.Node)) + var SendData = { "Method": "GETTRANSFERTX", "Context": {}, "Data": { BlockNum: Block.BlockNum, TicketArray: ElArr.Arr, } }; + this.SendF(ElArr.Node, SendData, ElArr.Arr.length * global.TR_TICKET_HASH_LENGTH + 1000) + } + } + GetMaxSumListFromID(Node, MaxSumID, BlockList) { + var Str0 = "GETBL:" + Node.id; + for (var i = 0; i < BlockList.length; i++) { + var elemBlockList = BlockList[i]; + global.TreeBlockBuf.SaveValue(Str0 + elemBlockList.ID, elemBlockList) + } + var MaxSum = []; + MaxSum: + for (var i = 0; i < MaxSumID.length; i++) { + var elem = MaxSumID[i]; + var Arr = []; + for (var n = 0; n < elem.SumListID.length; n++) { + var elemBlockList = global.TreeBlockBuf.LoadValue(Str0 + elem.SumListID[n], 1); + if (elemBlockList === undefined) { + continue MaxSum; + } + Arr.push(elemBlockList) + } + elem.SumList = Arr + MaxSum.push(elem) + } + return MaxSum; + } + CreateTransferBuffer(ArrT, MaxPOWList, MaxSumList, Block, Node) { + var Data; + var MaxSumID = []; + var BlockList = []; + for (var i = 0; i < MaxSumList.length; i++) { + var elem0 = MaxSumList[i]; + var ArrID = []; + for (var n = 0; n < elem0.SumList.length; n++) { + var elemBlockList = elem0.SumList[n]; + var Str = "BL:" + Node.id + global.GetHexFromArr(elemBlockList.Hash3); + var ID = global.TreeBlockBuf.LoadValue(Str, 1); + if (ID === undefined) { + this.SendBlockID++ + ID = this.SendBlockID % 65535 + global.TreeBlockBuf.SaveValue(Str, ID) + elemBlockList.ID = ID + BlockList.push(elemBlockList) + } + ArrID.push(ID) + } + MaxSumID.push({ BlockNum: elem0.BlockNum, SumHash: elem0.SumHash, SumListID: ArrID }) + } + var ArrTt, ArrTx; + if (global.USE_TICKET) { + ArrTt = ArrT + ArrTx = [] + } + else { + ArrTt = [] + ArrTx = ArrT + } + Data = { + "Version": 5, "BlockNum": Block.BlockNum, "Reserv1": 0, "MaxPOW": MaxPOWList, "Reserv2": 0, "BaseBlockNum": this.CurrentBlockNum - Block.BlockNum, + "MaxSumID": MaxSumID, "BlockList": BlockList, "TicketArray": ArrTt, "TxArray": ArrTx, "NoSendTx": Node.NoSendTx, + } + var BufWrite = global.BufLib.GetBufferFromObject(Data, FORMAT_DATA_TRANSFER, MAX_BLOCK_SIZE + 30000, WorkStructSend); + return BufWrite; + } + static + TRANSFER_F() { + return FORMAT_DATA_TRANSFER; + } + CheckingMaxPowOther(Block) { + var POW = Block.MaxPOW; + if (POW && POW.Hash && global.CompareArr(POW.PowHash, Block.PowHash) < 0) { + var LoadBlockNum = Block.BlockNum; + var LoadHash = POW.Hash; + var StrKey = this.GetStrFromHashShort(LoadHash); + var StrHashWas = this.GetStrFromHashShort(Block.Hash); + this.StartLoadBlockHeader(LoadHash, LoadBlockNum, "START OTHER:" + StrKey + " WAS:" + StrHashWas, false) + AddInfoBlock(Block, "REQ H: " + StrKey) + } + Block.CheckMaxPow = true + } + AddToMaxPOW(Block, item, Node) { + if (Block && item) { + if (!Block.MaxPOW) + Block.MaxPOW = {} + var POW = Block.MaxPOW; + if (!Block.PrevHash) + return; + item.BlockNum = Block.BlockNum + item.PrevHash = Block.PrevHash + CalcHashBlockFromSeqAddr(item, Block.PrevHash, global.MINING_VERSION_NUM) + if (POW.SeqHash === undefined || global.CompareArr(item.PowHash, POW.PowHash) < 0) { + POW.AddrHash = item.AddrHash + POW.Hash = item.Hash + POW.PowHash = item.PowHash + POW.PrevHash = item.PrevHash + POW.TreeHash = item.TreeHash + POW.SeqHash = item.SeqHash + } + if (Block.SeqHash && global.CompareArr(item.SeqHash, Block.SeqHash) === 0) { + if (POW.LocalSeqHash === undefined || global.CompareArr(POW.LocalSeqHash, Block.SeqHash) !== 0 || global.CompareArr(item.PowHash, POW.PowLocalHash) < 0) { + POW.LocalAddrHash = item.AddrHash + POW.PowLocalHash = item.PowHash + POW.LocalSeqHash = Block.SeqHash + } + } + var wasLider; + if (POW.MaxTree) + wasLider = POW.MaxTree.min() + this.AddPOWToMaxTree(POW, item) + if (wasLider) { + var newLider = POW.MaxTree.min(); + if (newLider !== wasLider) { + var Power = GetPowPower(newLider.PowHash); + AddInfoBlock(Block, "MaxPOW: " + Power) + } + } + } + } + AddPOWToMaxTree(POW, item) { + if (!POW.MaxTree) { + POW.MaxTree = new RBTree(function(a, b) { + return global.CompareArr(a.PowHash, b.PowHash); + }) + } + if (!POW.MaxTree.find(item)) { + POW.MaxTree.insert(item) + if (POW.MaxTree.size > 12) { + var maxitem = POW.MaxTree.max(); + POW.MaxTree.remove(maxitem) + } + } + } + GetMaxPOWList() { + var arr = []; + var start, finish; + start = this.CurrentBlockNum + TIME_START_SAVE - 2 + finish = this.CurrentBlockNum + for (var b = start; b < finish; b++) { + var Block = this.GetBlock(b); + if (Block && Block.Prepared && Block.MaxPOW) { + if (Block.MaxPOW && Block.MaxPOW.MaxTree) { + this.RecreateMaxPOW(Block) + var it = Block.MaxPOW.MaxTree.iterator(), Item; + while ((Item = it.next()) !== null) { + arr.push(Item) + } + } + } + } + return arr; + } + ToMaxPOWList(Arr) { + for (var i = 0; i < Arr.length; i++) { + var item = Arr[i]; + if (item && item.BlockNum >= this.CurrentBlockNum - BLOCK_PROCESSING_LENGTH && item.BlockNum < this.CurrentBlockNum) { + var Block = this.GetBlock(item.BlockNum); + this.AddToMaxPOW(Block, item) + } + } + } + RecreateMaxPOW(Block) { + if (Block.MaxPOW && Block.MaxPOW.MaxTree) { + var Tree = Block.MaxPOW.MaxTree; + var it = Tree.iterator(), Item; + while ((Item = it.next()) !== null) { + if (!Item.PrevHash) + global.ToLog("NO Item.PrevHash in " + Block.BlockNum) + if (Item.PrevHash && global.CompareArr(Item.PrevHash, Block.PrevHash) !== 0) { + Tree.remove(Item) + it = Tree.iterator() + } + } + } + Block.CheckMaxSum = false + } + CheckMaxSum(Block) { + var POW = Block.MaxSum; + var List = this.GetBlockList(Block.BlockNum); + var SumPow = this.GetSumFromList(List, Block.BlockNum); + if (POW && POW.SumHash && POW.SumPow > SumPow) { + var LoadBlockNum = Block.BlockNum; + var LoadHash = POW.SumHash; + var StrKey = this.GetStrFromHashShort(LoadHash); + if (this.StartLoadBlockHeader(LoadHash, LoadBlockNum, "START POW:" + POW.SumPow + ">" + SumPow + " SH:" + StrKey, true)) + AddInfoBlock(Block, "REQ SH: " + StrKey) + } + Block.CheckMaxSum = true + } + AddToMaxSum(Block, item) { + if (Block && item) { + if (!Block.MaxSum) + Block.MaxSum = {} + var POW = Block.MaxSum; + var SumPow = this.GetSumFromList(item.SumList, Block.BlockNum); + if (POW.SumHash === undefined || SumPow > POW.SumPow) { + POW.SumPow = SumPow + POW.SumHash = item.SumHash + POW.SumList = item.SumList + AddInfoBlock(Block, "SumPow:" + POW.SumPow) + Block.CheckMaxSum = false + } + return SumPow; + } + return 0; + } + GetMaxSumList() { + var Arr = []; + var start, finish; + start = this.CurrentBlockNum + TIME_START_LOAD - 2 + finish = this.CurrentBlockNum + for (var b = start; b <= finish; b++) { + var Block = this.GetBlock(b); + if (Block && Block.bSave && Block.MaxSum && Block.MaxSum.SumHash) { + var POW = Block.MaxSum; + var item = { BlockNum: Block.BlockNum, SumHash: POW.SumHash, SumList: POW.SumList, }; + Arr.push(item) + } + } + return Arr; + } + ToMaxSumList(Arr) { + var start, finish; + start = this.CurrentBlockNum + TIME_START_LOAD - 2 + finish = this.CurrentBlockNum + for (var i = 0; i < Arr.length; i++) { + var item = Arr[i]; + if (item && item.BlockNum >= start && item.BlockNum <= finish) { + var Block = this.GetBlock(item.BlockNum); + if (Block) { + this.AddToMaxSum(Block, item) + this.CheckMaxSum(Block) + } + } + } + } + GetBlockList(CurBlockNum) { + var arr = []; + for (var b = CurBlockNum - SUM_LIST_LENGTH + 1; b <= CurBlockNum; b++) { + var Block = this.GetBlock(b); + if (Block && Block.bSave) { + var item = { AddrHash: Block.AddrHash, SeqHash: Block.SeqHash, }; + arr.push(item) + } + else { + return []; + } + } + return arr; + } + GetSumFromList(arr, CurBlockNum) { + var SumPow = 0; + if (arr.length !== SUM_LIST_LENGTH) + return SumPow; + var CountLoad = 0; + var BlockNumStart = CurBlockNum - arr.length + 1; + for (var i = 0; i < arr.length; i++) { + var Item = arr[i]; + if (Item) { + Item.BlockNum = BlockNumStart + i + var Value = GetHashFromSeqAddr(Item.SeqHash, Item.AddrHash, Item.BlockNum, undefined, global.MINING_VERSION_NUM); + SumPow += GetPowPower(Value.PowHash) + Item.Hash3 = Value.Hash + } + else { + break; + } + } + return SumPow; + } + GetArrayFromTxTree(Block) { + if (!Block.PowTxTree) + return []; + var BufLength = 0; + var arr = []; + var it = Block.PowTxTree.iterator(), Item; + while ((Item = it.next()) !== null) { + arr.push(Item) + BufLength += Item.body.length + if (BufLength > MAX_BLOCK_SIZE) + break; + } + return arr; + } + GetArrayFromTicketTree(Block) { + if (!Block.PowTicketTree) + return []; + var arr = []; + var it = Block.PowTicketTree.iterator(), Item; + while ((Item = it.next()) !== null) { + arr.push(Item) + } + return arr; + } + AddToQuote(Tree, Tr) { + var Tr0 = Tree.find(Tr); + if (Tr0) { + return 3; + } + else { + Tree.insert(Tr) + if (Tree.size > MAX_TRANSACTION_LIMIT) { + var maxitem = Tree.max(); + Tree.remove(maxitem) + if (global.CompareArr(maxitem.HashPow, Tr.HashPow) === 0) + return 0; + } + return 1; + } + } + AddTicketToBlockQuote(Block, Tr) { + if (Block.PowTicketTree) { + var Res = this.IsValidTicket(Tr, Block.BlockNum); + if (Res >= 1) { + Res = this.AddToQuote(Block.PowTicketTree, Tr) + if (Res) + return Block.PowTicketTree.find(Tr); + } + return null; + } + } + AddTrToBlockQuote(Block, Tr, bTTAdd) { + if (Block.PowTxTree) { + var Res = this.IsValidTransaction(Tr, Block.BlockNum); + if (Res >= 1) { + if (bTTAdd) { + Res = this.AddToQuote(Block.PowTicketTree, Tr) + if (Res <= 0) + return Res; + } + Res = this.AddToQuote(Block.PowTxTree, Tr) + } + return Res; + } + } + GetBlockContext(BlockNum) { + if (BlockNum === undefined || !this.IsCorrectBlockNum(BlockNum)) + return undefined; + var Context = this.GetBlock(BlockNum); + if (!Context || !Context.StartTimeNum) { + Context = this.CreateBlockContext() + Context.BlockNum = BlockNum + Context.DELTA_CURRENT_TIME = GetDeltaCurrentTime() + Context.StartTimeNum = (BlockNum - 1 + BLOCK_DELTA_ACTIVATE) * CONSENSUS_PERIOD_TIME + START_NETWORK_DATE + this.BlockChain[BlockNum] = Context + } + if (!Context.TransferFromAddr) { + Context.TransferFromAddr = {} + Context.LevelsTransfer = [] + } + return Context; + } + StartBlock(Block) { + Block.Active = true + } + IsCorrectBlockNum(BlockNum) { + var start = this.CurrentBlockNum - BLOCK_PROCESSING_LENGTH; + var finish = this.GetLastCorrectBlockNum(); + if (BlockNum < start || BlockNum > finish) { + return false; + } + return true; + } + GetLastCorrectBlockNum() { + return this.CurrentBlockNum + 4; + } + GetStrSendCount(Block) { + if (!Block) + return ""; + var Str = ""; + var Count = 0; + for (var L = 0; L < Block.LevelsTransfer.length; L++) { + var Transfer = Block.LevelsTransfer[L]; + Str = Str + "," + Transfer.SendCount + if (typeof Transfer.SendCount === "number") + Count = Count + Transfer.SendCount + } + return "" + Count + ":[" + Str.substr(1) + "]"; + } + GetStrGetCount(Block) { + if (!Block) + return ""; + var Str = ""; + var Count = 0; + for (var L = 0; L < Block.LevelsTransfer.length; L++) { + var Transfer = Block.LevelsTransfer[L]; + Str = Str + "," + Transfer.GetCount + Count = Count + Transfer.GetCount + } + return "" + Count + ":[" + Str.substr(1) + "]"; + } + ToStrBlocks(DopStr) { + var num = Math.floor(this.CurrentBlockNum / 3) * 3; + var start = num - global.BLOCK_PROCESSING_LENGTH2 + 2; + var finish = this.CurrentBlockNum; + if (!DopStr) + DopStr = "" + var Str = ""; + for (var b = start; b <= finish; b++) { + var hashStr = ""; + var Block = this.GetBlock(b); + if (Block && Block.ErrRun) { + if (Block.ErrRun) + hashStr = Block.ErrRun.substr(0, 5) + else + if (Block && Block.TreeHash) + hashStr = "-" + GetHexFromAddres(Block.TreeHash).substr(0, 3) + "-" + } + else + if (Block && Block.TreeHash) { + hashStr = GetHexFromAddres(Block.TreeHash).substr(0, 5) + } + Str = Str + "|" + (hashStr + " ").substr(0, 5) + } + Str = Str.substr(1) + ToInfo("" + finish + " -> " + Str + " " + DopStr) + } + PreparePOWHash(Block) { + if (!Block.TreeHash) + Block.TreeHash = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] + var PrevHash = this.GetPrevHash(Block); + if (!PrevHash) { + AddInfoBlock(Block, "-err prev hash-") + return false; + } + Block.PrevHash = PrevHash + Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash) + this.CreatePOWNew(Block) + Block.Prepared = true + if (global.USE_MINING && !Block.StartMining) { + Block.StartMining = true + AddInfoBlock(Block, "-send mining-") + global.SetCalcPOW(Block, "FastCalcBlock") + } + return true; + } + CalcTreeHashFromArrTr(BlockNum, arrTr) { + var arrHASH = []; + for (var i = 0; i < arrTr.length; i++) { + var Tr = arrTr[i]; + arrHASH.push(Tr.HASH) + } + var Tree = CalcMerklFromArray(BlockNum, arrHASH); + return Tree.Root; + } + CreateTreeHash(Block) { + if (Block.EndExchange) + return; + Block.EndExchange = true + if (Block.bSave) + return; + var PrevBlock = this.GetBlock(Block.BlockNum - 1); + if (PrevBlock && !PrevBlock.EndExchange && !PrevBlock.bSave) { + AddInfoBlock(Block, "Prev Not End Exchange") + return; + } + AddInfoBlock(Block, "End Exchange,N=" + Block.TransferNodesCount) + var arrContent = []; + var arrHASH = []; + var arrTr = this.GetArrayFromTxTree(Block); + this.AddDAppTransactions(Block.BlockNum, arrTr) + for (var i = 0; i < arrTr.length; i++) { + var Tr = arrTr[i]; + arrContent.push(Tr.body) + arrHASH.push(Tr.HASH) + } + var Tree = CalcMerklFromArray(Block.BlockNum, arrHASH); + Block.TreeHash = Tree.Root + Block.arrContent = arrContent + Block.TrCount = Block.arrContent.length + } + WatchdogSaved(BlockNum) { + var Block = this.GetBlock(BlockNum); + if (!Block) { + global.ToLog("#1 WatchdogSaved: no BlockNum=" + BlockNum) + return; + } + if (Block.bSave) { + var BlockDB = this.ReadBlockDB(BlockNum); + if (!BlockDB) { + Block.bSave = false + return; + } + if (global.CompareArr(BlockDB.Hash, Block.Hash) !== 0) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#3 WatchdogSaved: Error Hash on Num=" + BlockNum) + return; + } + if (global.CompareArr(BlockDB.SumHash, Block.SumHash) !== 0) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#4 WatchdogSaved: Error SumHash on Num=" + BlockNum) + return; + } + if (global.CompareArr(BlockDB.SeqHash, Block.SeqHash) !== 0) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#5 WatchdogSaved: Error SeqHash on Num=" + BlockNum) + return; + } + var PrevHash = this.GetPrevHash(Block); + if (!PrevHash) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#6 WatchdogSaved: Error PrevHash on Num=" + BlockNum) + return; + } + var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); + if (global.CompareArr(SeqHash, Block.SeqHash) !== 0) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#7 WatchdogSaved: Error SeqHash on Num=" + BlockNum) + return; + } + PrevHash = this.GetPrevHashDB(BlockDB) + SeqHash = this.GetSeqHash(BlockDB.BlockNum, PrevHash, BlockDB.TreeHash) + if (global.CompareArr(SeqHash, BlockDB.SeqHash) !== 0) { + AddInfoBlock(Block, "=ERR:WATCHDOG=") + global.ToLog("#8 WatchdogSaved: Error SeqHash on Num=" + BlockNum) + return; + } + } + } + DoBlockChain() { + if (glStopNode) + return; + if (!CAN_START) + return; + this.StartConsensus() + var CURRENTBLOCKNUM = this.CurrentBlockNum; + if (GrayConnect()) { + if (!this.LoadHistoryMode) + this.StartSyncBlockchain(undefined, 1) + return; + } + if (this.LoadHistoryMode) + return; + var bWasSave = false; + var LoadBlockNum; + var LoadHash; + var start_save = CURRENTBLOCKNUM + TIME_START_SAVE; + for (var BlockNum = CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH2; BlockNum > global.BLOCK_PROCESSING_LENGTH2 && BlockNum < CURRENTBLOCKNUM; BlockNum++) { + var Block = this.GetBlock(BlockNum); + if (!Block) { + Block = this.GetBlockContext(BlockNum) + if (!Block) { + continue; + } + } + if (Block.bSave) { + var BlockDB = this.ReadBlockDB(BlockNum); + if (!BlockDB) { + Block.bSave = false + } + } + if (global.WATCHDOG_DEV) + this.WatchdogSaved(Block.BlockNum) + if (Block.bSave) { + bWasSave = true + if (Block.MaxSum && !Block.CheckMaxSum) { + AddInfoBlock(Block, "CheckMaxSum") + this.CheckMaxSum(Block) + } + if (BlockNum <= CURRENTBLOCKNUM - BLOCK_PROCESSING_LENGTH * 4) { + Block.TransferFromAddr = undefined + Block.LevelsTransfer = undefined + Block.mapData = undefined + Block.MaxPOW = undefined + Block.MaxSum = undefined + Block.arrContent = undefined + if (Block.PowTxTree) { + Block.PowTxTree.clear() + Block.PowTxTree = undefined + } + } + continue; + } + var PrevBlock = this.GetBlock(BlockNum - 1); + if (!PrevBlock) { + Block.HasErr = 1 + AddInfoBlock(Block, "!PrevBlock") + continue; + } + if (BlockNum >= CURRENTBLOCKNUM + TIME_END_EXCHANGE) { + if (!Block.Active) { + AddInfoBlock(Block, "WAIT ACTIVATE") + continue; + } + else + if (!Block.EndExchange) { + AddInfoBlock(Block, "WAIT EXCHANGE") + continue; + } + } + if (BlockNum === CURRENTBLOCKNUM + TIME_START_POW || Block.EndExchange) + if (!Block.Prepared) { + if (!Block.EndExchange) + this.CreateTreeHash(Block) + AddInfoBlock(Block, "Start POW") + this.PreparePOWHash(Block) + if (!Block.Prepared) + AddInfoBlock(Block, "!!Prepared") + continue; + } + if (!Block.EndExchange) { + AddInfoBlock(Block, "Not EndExchange") + Block.HasErr = 1 + Block.Prepared = 0 + this.CreateTreeHash(Block) + } + if (!Block.Prepared) { + Block.HasErr = 1 + AddInfoBlock(Block, "Not was Prepared") + this.PreparePOWHash(Block) + if (!Block.Prepared) + continue; + } + { + var PrevHash = this.GetPrevHash(Block); + if (!PrevHash) { + Block.HasErr = 1 + continue; + } + var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); + if (global.CompareArr(SeqHash, Block.SeqHash) !== 0) { + Block.HasErr = 1 + AddInfoBlock(Block, "New fast pow") + this.PreparePOWHash(Block) + } + if (Block.MaxPOW && Block.MaxPOW.SeqHash && Block.MaxPOW.AddrHash && Block.MaxPOW.LocalSeqHash && global.CompareArr(Block.SeqHash, + Block.MaxPOW.LocalSeqHash) === 0) { + if (global.CompareArr(Block.SeqHash, Block.MaxPOW.LocalSeqHash) === 0 && global.CompareArr(Block.MaxPOW.PowLocalHash, Block.PowHash) < 0) { + Block.AddrHash = Block.MaxPOW.LocalAddrHash + CalcHashBlockFromSeqAddr(Block, Block.PrevHash, global.MINING_VERSION_NUM) + AddInfoBlock(Block, "->Local lider:" + GetPowPower(Block.PowHash)) + } + if (global.CompareArr(Block.SeqHash, Block.MaxPOW.SeqHash) === 0 && global.CompareArr(Block.MaxPOW.AddrHash, Block.AddrHash) !== 0 && global.CompareArr(Block.MaxPOW.PowHash, + Block.PowHash) < 0) { + Block.AddrHash = Block.MaxPOW.AddrHash + CalcHashBlockFromSeqAddr(Block, Block.PrevHash, global.MINING_VERSION_NUM) + AddInfoBlock(Block, "->Max lider") + } + } + else { + Block.HasErr = 1 + AddInfoBlock(Block, "ERROR MaxPOW") + } + if (Block.MaxPOW && Block.MaxPOW.SeqHash && !Block.CheckMaxPow && !Block.CheckMaxSum && global.CompareArr(Block.SeqHash, Block.MaxPOW.SeqHash) !== 0) { + AddInfoBlock(Block, "CheckMaxPow") + this.CheckingMaxPowOther(Block) + } + if (BlockNum > start_save) + continue; + if (PrevBlock.bSave && this.BlockNumDB + 1 >= Block.BlockNum) { + this.AddToStatBlockConfirmation(Block) + var Power = GetPowPower(Block.PowHash); + if (this.WriteBlockDB(Block)) { + if (Block.arrContent && Block.arrContent.length) + global.ADD_TO_STAT("MAX:TRANSACTION_COUNT", Block.arrContent.length) + AddInfoBlock(Block, "SAVE:" + Power + " TH:" + this.GetStrFromHashShort(Block.TreeHash).substr(0, 4)) + } + else { + Block.HasErr = 1 + AddInfoBlock(Block, "ERROR WRITE DB") + } + this.AddToMaxSum(Block, { SumHash: Block.SumHash, SumList: this.GetBlockList(Block.BlockNum), }) + if (typeof global.RESYNC_CONDITION === "object") { + if (!this.OwnBlockCount) + this.OwnBlockCount = 0 + var Miner = ReadUintFromArr(Block.AddrHash, 0); + var MultK = RESYNC_CONDITION.K_POW; + var MaxBlocks = RESYNC_CONDITION.OWN_BLOCKS; + if (Miner === GENERATE_BLOCK_ACCOUNT) { + this.OwnBlockCount++ + if (this.OwnBlockCount >= MaxBlocks) { + var PrevSumPow = this.GetAvgPowBlock(Block.BlockNum - 2 * MaxBlocks, MaxBlocks); + var CurrentPow = this.GetAvgPowBlock(Block.BlockNum - MaxBlocks, MaxBlocks); + if (CurrentPow === 0 || PrevSumPow - CurrentPow >= MultK) { + global.ToLog("START RESYNC CONDITION") + this.OwnBlockCount = 0 + this.StartSyncBlockchain() + return; + } + } + } + else { + this.OwnBlockCount = 0 + } + } + } + else { + Block.HasErr = 1 + if (!PrevBlock.bSave) + AddInfoBlock(Block, "Prev block not saved") + else + AddInfoBlock(Block, "Low BlockNumDB") + } + } + } + var MaxNumBlockDB = this.GetMaxNumBlockDB(); + if (CURRENTBLOCKNUM + global.BLOCK_PROCESSING_LENGTH2 > MaxNumBlockDB) + for (var BlockNum = CURRENTBLOCKNUM - global.BLOCK_PROCESSING_LENGTH2; BlockNum > global.BLOCK_PROCESSING_LENGTH2 && BlockNum < start_save; BlockNum++) { + var Block = this.GetBlock(BlockNum); + if (Block && !Block.bSave && Block.TrCount && Block.TreeHash && !IsZeroArr(Block.TreeHash) && !Block.WasSaveDataTree) { + this.PreSaveDataTreeToDB(Block) + Block.WasSaveDataTree = 1 + AddInfoBlock(Block, "*PRESAVE DATA TREE*") + global.ToLog("PRESAVE DATA: " + Block.BlockNum) + } + } + this.RelayMode = !bWasSave + this.FREE_MEM_BLOCKS(CURRENTBLOCKNUM - BLOCK_COUNT_IN_MEMORY) + } + GetAvgPowBlock(StartNum, CountNum) { + var Count = 0; + var SumPow = 0; + for (var Num = StartNum; Num < StartNum + CountNum; Num++) { + var Block = this.GetBlock(Num); + if (Block && Block.bSave) { + var Power = GetPowPower(Block.PowHash); + SumPow += Power + Count++ + } + } + if (!Count) + return 0; + else + return SumPow / Count; + } + CreatePOWNew(Block) { + CreateHashMinimal(Block, GENERATE_BLOCK_ACCOUNT) + this.AddToMaxPOW(Block, { + SeqHash: Block.SeqHash, AddrHash: Block.AddrHash, PrevHash: Block.PrevHash, TreeHash: Block.TreeHash, + }) + } + SetNoPOW(BlockNumFrom, bReload, RefBlockNum) { + var CurNum = BlockNumFrom; + var finish = this.GetLastCorrectBlockNum(); + while (true) { + var BlockMem = this.BlockChain[CurNum]; + if (BlockMem) { + if (BlockMem.Prepared) { + AddInfoBlock(BlockMem, "-reset POW:" + RefBlockNum + "/" + bReload) + BlockMem.bSave = false + BlockMem.Prepared = false + BlockMem.StartMining = false + this.PreparePOWHash(BlockMem) + } + this.RecreateMaxPOW(BlockMem) + } + if (!BlockMem && CurNum > finish) + break; + CurNum++ + } + } + MiningProcess(msg) { + var BlockMining = this.GetBlock(msg.BlockNum); + if (!BlockMining) { + return; + } + if (!BlockMining.StartMining || BlockMining.bSave) + return; + if (BlockMining && BlockMining.Hash && BlockMining.SeqHash && global.CompareArr(BlockMining.SeqHash, msg.SeqHash) === 0) { + var ValueOld = GetHashFromSeqAddr(BlockMining.SeqHash, BlockMining.AddrHash, BlockMining.BlockNum); + var ValueMsg = GetHashFromSeqAddr(msg.SeqHash, msg.AddrHash, BlockMining.BlockNum); + var bWas = 0; + if (global.CompareArr(ValueOld.Hash1, ValueMsg.Hash1) > 0) { + var Nonce1 = ReadUintFromArr(msg.AddrHash, 12); + var DeltaNum1 = ReadUint16FromArr(msg.AddrHash, 24); + WriteUintToArrOnPos(BlockMining.AddrHash, Nonce1, 12) + WriteUint16ToArrOnPos(BlockMining.AddrHash, DeltaNum1, 24) + bWas += 1 + } + if (global.CompareArr(ValueOld.Hash2, ValueMsg.Hash2) > 0) { + var Nonce0 = ReadUintFromArr(msg.AddrHash, 6); + var Nonce2 = ReadUintFromArr(msg.AddrHash, 18); + var DeltaNum2 = ReadUint16FromArr(msg.AddrHash, 26); + WriteUintToArrOnPos(BlockMining.AddrHash, Nonce0, 6) + WriteUintToArrOnPos(BlockMining.AddrHash, Nonce2, 18) + WriteUint16ToArrOnPos(BlockMining.AddrHash, DeltaNum2, 26) + bWas += 2 + } + if (!bWas) + return; + var ValueNew = GetHashFromSeqAddr(BlockMining.SeqHash, BlockMining.AddrHash, BlockMining.BlockNum); + BlockMining.Hash = ValueNew.Hash + BlockMining.PowHash = ValueNew.PowHash + BlockMining.Power = GetPowPower(BlockMining.PowHash) + global.ADD_TO_STAT("MAX:POWER", BlockMining.Power) + var Power = GetPowPower(BlockMining.PowHash); + var HashCount = Math.pow(2, Power); + ADD_HASH_RATE(HashCount) + AddInfoBlock(BlockMining, "Set POW: " + Power) + this.SetNoPOW(BlockMining.BlockNum + 8, 0, BlockMining.BlockNum) + this.AddToMaxPOW(BlockMining, { + SeqHash: BlockMining.SeqHash, AddrHash: BlockMining.AddrHash, PrevHash: BlockMining.PrevHash, TreeHash: BlockMining.TreeHash, + }) + } + } +}; +global.TreeBlockBuf = new STreeBuffer(50 * 1000, CompareItemHashSimple, "string"); +var PrevTimeIdle = 0; +OnTimeIdle(); + +function OnTimeIdle() { + var CurTime = Date.now(); + var Delta = CurTime - PrevTimeIdle; + if (Delta <= 51) { + global.ADD_TO_STAT("TIME_IDLE", 5); + } + setTimeout(OnTimeIdle, 49); + PrevTimeIdle = CurTime; +}; diff --git a/src/core/block-loader-const.ts b/src/core/block-loader-const.ts new file mode 100644 index 0000000..61ef3ad --- /dev/null +++ b/src/core/block-loader-const.ts @@ -0,0 +1,16 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.PERIOD_GET_BLOCK = 300, global.COUNT_HISTORY_BLOCKS_FOR_LOAD = 600, global.COUNT_BLOCKS_FOR_CHECK_POW = 50, global.MAX_DELTA_COUNT_SUM_FOR_LOAD = 10, +global.MAX_COUNT_CHAIN_LOAD = 120, global.PACKET_ALIVE_PERIOD = 4 * CONSENSUS_PERIOD_TIME, global.PACKET_ALIVE_PERIOD_NEXT_NODE = PACKET_ALIVE_PERIOD / 2, +global.MAX_BLOCK_SEND = 8, global.COUNT_TASK_FOR_NODE = 10, global.FORMAT_BLOCK_TRANSFER = "{ BlockNum:uint, TreeHash:hash, arrContent:[tr], }", +global.WRK_BLOCK_TRANSFER = {}, global.MAX_ACCOUNTS_TRANSFER = 1024, global.MAX_SMARTS_TRANSFER = 10, global.TEST_NETWORK && (global.MAX_ACCOUNTS_TRANSFER = 128, +global.MAX_SMARTS_TRANSFER = 10), global.FORMAT_REST_TRANSFER = "{ Result:uint, Version:uint, Arr:[arr200], ProofHash:hash, ProofArrL:, ProofArrR:, }", +global.FORMAT_SMART_TRANSFER = "{ Result:uint, Arr:[tr], }"; diff --git a/src/core/block-loader.ts b/src/core/block-loader.ts new file mode 100644 index 0000000..5578c4e --- /dev/null +++ b/src/core/block-loader.ts @@ -0,0 +1,1284 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const fs = require("fs"); +import * as crypto from 'crypto'; +require('./block-loader-const'); +const STAT_BLOCK_LOAD_PERIOD = CONSENSUS_PERIOD_TIME / 5; +module.exports = class CBlock extends require("./rest-loader.js") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.MapMapLoaded = {} + this.BlockChain = {} + this.ChainID = 0 + this.BlockID = 0 + this.TaskNodeIndex = 0 + this.LoadedChainList = [] + this.LastChainLoad = undefined + this.StartLoadBlockTime = 0 + this.LoadHistoryMode = false + this.MapBlockBodyLoad = {} + if (!global.ADDRLIST_MODE && !this.VirtualMode) { + let Self = this; + setTimeout(function() { + Self.CheckStartedBlocks() + setInterval(Self.LoopChainLoad.bind(Self), 100) + setInterval(Self.LoopBlockLoad.bind(Self), 10) + setInterval(Self.LoopBlockBodyLoad.bind(Self), 1 * 1000) + }, 1000) + } + } + StopNode() { + global.glStopNode = true + } + GenesisBlockHeaderDB(Num) { + if (Num < 0) + return undefined; + var Block = { + BlockNum: Num, TreeHash: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0], AddrHash: DEVELOP_PUB_KEY0, Hash: this.GetHashGenesis(Num), PowHash: this.GetHashGenesis(Num), PrevHash: [0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], SeqHash: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], SumHash: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Comment1: "GENESIS", Comment2: "", TrCount: 0, TrDataPos: 0, TrDataLen: 0, + }; + Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash) + Block.SumPow = 0 + Block.bSave = true + return Block; + } + CheckStartedBlocks() { + this.FindStartBlockNum() + if (this.UseTruncateBlockDB) + this.TruncateBlockDB(this.UseTruncateBlockDB) + var CurNum = GetCurrentBlockNumByTime(); + if (CurNum <= this.BlockNumDB) { + this.TruncateBlockDB(CurNum) + } + CurNum = this.GetMaxNumBlockDB() + if (CurNum <= this.BlockNumDB) { + this.TruncateBlockDB(CurNum) + this.BlockNumDB = CurNum + } + if (this.BlockNumDB < global.BLOCK_PROCESSING_LENGTH2) + this.CreateGenesisBlocks() + if (fs.existsSync(GetCodePath("EXPERIMENTAL/_run.js"))) { + require(GetCodePath("EXPERIMENTAL/_run.js")).Run() + } + this.LoadMemBlocksOnStart() + } + CreateGenesisBlocks() { + global.ToLog("====CreateGenesisBlock====") + var PrevArr = []; + for (var n = 0; n < global.BLOCK_PROCESSING_LENGTH2; n++) { + var Block = this.GenesisBlockHeaderDB(n); + PrevArr[n] = Block + this.WriteBlockDB(Block) + } + return PrevArr; + } + GetPrevHash(Block) { + var startPrev = Block.BlockNum - global.BLOCK_PROCESSING_LENGTH2; + var Sum = 0; + var arr = []; + for (var i = 0; i < BLOCK_PROCESSING_LENGTH; i++) { + var PrevBlock = this.GetBlock(startPrev + i); + if (PrevBlock && PrevBlock.bSave) { + Sum = Sum + PrevBlock.SumPow + arr.push(PrevBlock.Hash) + } + else { + return undefined; + } + } + var PrevHash = CalcHashFromArray(arr, true); + return PrevHash; + } + GetPrevHashDB(Block) { + var startPrev = Block.BlockNum - global.BLOCK_PROCESSING_LENGTH2; + var arr = []; + for (var i = 0; i < BLOCK_PROCESSING_LENGTH; i++) { + var num = startPrev + i; + var PrevBlock = this.ReadBlockHeaderDB(num); + if (!PrevBlock || !PrevBlock.bSave) { + global.ToError(" ERROR CALC BLOCK: " + Block.BlockNum + " - prev block not found: " + num) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + arr.push(PrevBlock.Hash) + } + var PrevHash = CalcHashFromArray(arr, true); + return PrevHash; + } + StartSyncBlockchain(Node, bSilent, bCheckPoint) { + this.FREE_ALL_MEM_CHAINS() + if (global.NO_HISTORY_MODE) { + this.LoadHistoryMode = 0 + return; + } + if (global.CREATE_ON_START && !LOCAL_RUN) + return; + if (!GrayConnect()) + this.RelayMode = true + else + this.RelayMode = false + if (!bSilent) + this.RelayMode = true + this.LoadHistoryMode = true + this.LoadHistoryMessage = !bSilent + this.LoadHistoryContext = { + PrevBlockNum: - 1, Node: Node, BlockNum: this.BlockNumDB, MapSend: {}, Foward: 1, Pause: 0, DeltaBlockNum: 10, + StartTimeHistory: Date.now(), MaxTimeOut: 30 * 1000 + } + if (!bSilent && !bCheckPoint && REST_START_COUNT) { + this.CheckSyncRest() + } + if (!this.ActualNodes.size) { + global.ToLog("There is no connections to other nodes") + } + else { + if (this.LoadHistoryMessage) { + global.ToLog("Start synchronization") + } + } + } + LoopSyncBlockchain() { + if (!this.ActualNodes.size) + return; + var Context; + if (this.LoadRestContext && this.LoadRestContext.Mode < 200) + Context = this.LoadRestContext + else + Context = this.LoadHistoryContext + if (Context.PrevBlockNum === Context.BlockNum) { + var DeltaTime = Date.now() - Context.StartTimeHistory; + if (DeltaTime > Context.MaxTimeOut) { + global.ToLog("DETECT TIMEOUT LOAD") + this.StartSyncBlockchain() + return; + } + } + else { + Context.PrevBlockNum = Context.BlockNum + Context.StartTimeHistory = Date.now() + } + if (Context.LoopSyncRest) { + this.LoopSyncRest() + return; + } + if (Context.Pause) { + if (this.LoadedChainList.length) { + return; + } + Context.Pause = 0 + Context.BlockNum = this.BlockNumDB + } + var BlockDB = this.ReadBlockHeaderDB(Context.BlockNum); + if (!BlockDB || this.BlockNumDB >= GetCurrentBlockNumByTime() - BLOCK_PROCESSING_LENGTH - 2) { + this.LoadHistoryMode = false + if (this.LoadHistoryMessage) + global.ToLog("Finish synchronization") + if (!BlockDB) + return; + } + var Ret = this.GetNextNode(Context, Context.BlockNum, 1); + if (Ret.Result) { + var Node = Ret.Node; + this.SendF(Node, { "Method": "GETBLOCKHEADER", "Context": Context, "Data": { Foward: 1, BlockNum: Context.BlockNum, Hash: BlockDB.SumHash } }) + } + } + StartLoadBlockHeader(LoadHash, Num, StrInfo, bIsSum) { + if (this.LoadHistoryMode) + return; + if (global.NO_HISTORY_MODE) + return; + this.StartLoadBlockTime = Date.now() + if (Num > this.CurrentBlockNum + TIME_START_SAVE) { + return; + } + bIsSum = bIsSum || false + var Tree = this.GetHistoryTree("StartLoadBlockHeader"); + if (Tree.find({ hash: LoadHash })) + return false; + Tree.insert({ hash: LoadHash }) + var chain = { + id: 0, Count: 16, BlockNum: Num, IsSum: bIsSum, Hash: LoadHash, time: undefined, FindBlockDB: false, LoadDB: false, LoadCountDB: 0, + LoadSumDB: 0, LoadSum: 0, ParentChain: undefined, RootChain: undefined, BlockNumStart: Num, HashStart: LoadHash, IsSumStart: bIsSum, + BlockHead: undefined, MapSend: {}, Comment2: "", StopSend: false, Info: "", Error: false, + }; + this.ChainBindMethods(chain) + chain.AddInfo(StrInfo) + this.SetChainNum(chain) + var max = 3; + while (max > 0) { + max-- + if (!this.SendChainNext(chain, false)) + break; + } + return true; + } + SetChainNum(chain) { + if (!chain.id) { + this.ChainID++ + chain.id = this.ChainID + } + this.LoadedChainList.push(chain) + } + LoopChainLoad() { + if (glStopNode) + return; + if (this.UseTruncateBlockDB) + this.TruncateBlockDB(this.UseTruncateBlockDB) + if (this.LoadHistoryMode) { + this.LoopSyncBlockchain() + return; + } + if (this.BlockNumDB < this.CurrentBlockNum - global.BLOCK_PROCESSING_LENGTH2) { + this.StartSyncBlockchain() + return; + } + if (global.LOAD_TO_BEGIN && this.BlockNumDBMin) { + this.SendLoadToBegin() + } + var CountStopSend = 0; + var min_num = this.CurrentBlockNum - MAX_COUNT_CHAIN_LOAD; + var min_num_load = this.CurrentBlockNum; + for (var i = 0; i < this.LoadedChainList.length; i++) { + var chain = this.LoadedChainList[i]; + if (!chain) { + this.LoadedChainList.splice(i, 1) + continue; + } + var RootChain = chain.GetRootChain(); + if (chain.RootChain) + chain.RootChain = RootChain + if (RootChain.BlockNum < min_num_load) + min_num_load = RootChain.BlockNum + if (!chain.StopSend) { + if (chain.BlockHead) { + if (chain.BlockNum < this.CurrentBlockNum - COUNT_HISTORY_BLOCKS_FOR_LOAD) { + if (global.WATCHDOG_DEV) + global.ToLog("Very long length of blocks to load history, stop chain with id=" + chain.id + " (" + chain.BlockNum + "-" + chain.BlockNumMax + ")") + chain.StopSend = true + chain.AddInfo("Stop load #1") + this.FREE_ALL_MEM_CHAINS() + return; + } + else + if (chain.BlockNumMax < min_num) { + if (global.WATCHDOG_DEV) + global.ToLog("Timeout - stop load chain with id=" + chain.id + " (" + chain.BlockNum + "-" + chain.BlockNumMax + ")") + chain.StopSend = true + chain.AddInfo("Stop load #2") + this.ClearChains(chain, 0) + } + } + } + if (chain && !chain.IsSum && !chain.StopSend) { + var StrKey = "H:" + global.GetHexFromArr(chain.Hash); + var Map = this.GetMapLoadedFromChain(chain); + var WasBlock = Map[StrKey]; + if (WasBlock && WasBlock.chain !== chain && global.CompareArr(WasBlock.Hash, chain.Hash) === 0 && !WasBlock.chain.Deleted) { + if (global.WATCHDOG_DEV) + global.ToLog("Was hash in chain " + WasBlock.chain.id + " - stop load chain with id=" + chain.id + " (" + chain.BlockNum + ")") + chain.Comment2 = "was hash" + chain.StopSend = true + } + } + if (chain && chain.StopSend) + CountStopSend++ + chain = this.LoadedChainList[i] + if (chain && !chain.GetFindDB() && !chain.StopSend) { + this.SendChainNext(chain, true) + } + } + global.ADD_TO_STAT("MAX:LOADEDCHAINLIST", this.LoadedChainList.length) + this.FREE_MEM_CHAINS(min_num_load) + this.LastLoadedBlockNum = 0 + if (this.LoadedChainList.length > COUNT_HISTORY_BLOCKS_FOR_LOAD) { + if (global.WATCHDOG_DEV) + global.ToLog("LoadedChainList>COUNT_HISTORY_BLOCKS_FOR_LOAD -> FREE_ALL_MEM_CHAINS") + this.FREE_ALL_MEM_CHAINS() + } + } + GetNextNode(task, keyid, checktime, BlockNum) { + var CurTime = GetCurrentTime(0) - 0; + if (checktime && task.time) { + var Delta = CurTime - task.time; + if (Delta < PACKET_ALIVE_PERIOD_NEXT_NODE) + return { Result: false, timewait: true }; + } + task.time = undefined + var StartI = 0; + if (task.Node) + StartI = - 1 + var timewait = false; + var arr = this.GetActualNodes(); + arr.sort(function(a, b) { + return b.BlockProcessCount - a.BlockProcessCount; + }) + if (arr.length > 40) + arr.length = 40 + for (var i = StartI; i < arr.length; i++) { + var Node; + if (i === - 1) { + Node = task.Node + task.Node = undefined + } + else { + this.TaskNodeIndex++ + Node = arr[this.TaskNodeIndex % arr.length] + } + if (Node.Active) { + if (!Node.INFO || !Node.INFO.WasPing || Node.StopGetBlock || (Node.INFO.CheckPointHashDB && CHECK_POINT.BlockNum && global.CompareArr(CHECK_POINT.Hash, + Node.INFO.CheckPointHashDB) !== 0)) { + timewait = true + continue; + } + if (BlockNum !== undefined && Node.INFO && BlockNum > Node.INFO.BlockNumDB) { + timewait = true + continue; + } + if (Node.TaskLastSend) { + var Delta = CurTime - Node.TaskLastSend; + if (Delta < global.PERIOD_GET_BLOCK) { + timewait = true + continue; + } + } + var keysend = "" + Node.addrStr + ":" + keyid; + if (task.MapSend[keysend]) + continue; + Node.TaskLastSend = CurTime + task.time = CurTime + return { Result: true, Node: Node, timewait: timewait }; + } + } + if (!task.RestartGetNextNode) + task.RestartGetNextNode = 0 + if (!timewait && task.RestartGetNextNode < 3) { + if (!task.LastTimeRestartGetNextNode) + task.LastTimeRestartGetNextNode = 0 + var Delta = Date.now() - task.LastTimeRestartGetNextNode; + if (Delta > 3000) { + task.RestartGetNextNode++ + task.LastTimeRestartGetNextNode = Date.now() + task.MapSend = {} + return { Result: false, timewait: true }; + } + } + return { Result: false, timewait: timewait }; + } + SendChainNext(chain, checktime) { + var Ret = this.GetNextNode(chain, chain.BlockNum, checktime); + if (Ret.Result) { + if (!chain.Context) + chain.Context = { Chain: chain } + var Node = Ret.Node; + this.SendF(Node, { + "Method": "GETBLOCKHEADER", "Context": chain.Context, "Data": { + Foward: 0, BlockNum: chain.BlockNum, Hash: chain.Hash, + IsSum: chain.IsSum, Count: chain.Count + } + }) + var DopStr = ""; + if (chain.IsSum) + DopStr = "SUM:" + chain.AddInfo(chain.BlockNum + "/" + DopStr + this.GetStrFromHashShort(chain.Hash) + "->" + GetNodeStrPort(Node)) + return true; + } + return false; + } + static + GETBLOCKHEADER_F() { + return "{\ + Foward:byte,\ + BlockNum:uint,\ + Hash:hash,\ + Count:uint,\ + IsSum:byte\ + }"; + } + static + GETBLOCKHEADER100_F() { + return "{\ + BlockNum:uint,\ + Hash:hash,\ + Count:uint\ + }"; + } + GetBlockArrFromBuffer_Load(BufRead, Info) { + var BlockArr = GetBlockArrFromBuffer(BufRead, Info); + if (BlockArr.length > 0 && BlockArr[0].BlockNum === global.BLOCK_PROCESSING_LENGTH2) + BlockArr.unshift(this.ReadBlockHeaderDB(BLOCK_PROCESSING_LENGTH2 - 1)) + return BlockArr; + } + RETBLOCKHEADER_FOWARD(Info, CurTime) { + if (!Info.Context.Foward) + return; + var Context = this.LoadHistoryContext; + Context.time = undefined + var BufRead = global.BufLib.GetReadBuffer(Info.Data); + var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info); + var arr2 = []; + var bFindDB = 0; + if (arr.length > 1) + for (var i = 0; i < arr.length; i++) { + var Block = arr[i]; + if (!Block) + return; + if (Block.BlockNum === CHECK_POINT.BlockNum && !IsZeroArr(CHECK_POINT.Hash)) { + if (global.CompareArr(CHECK_POINT.Hash, Block.Hash) !== 0) { + break; + } + Context.FindCheckPoint = true + } + if (Block.BlockNum < this.BlockNumDB) { + break; + } + if (!bFindDB) { + var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum); + if (BlockDB && global.CompareArr(BlockDB.SumHash, Block.SumHash) === 0) { + bFindDB = 1 + arr2.push(Block) + } + else + if (BlockDB && IsZeroArr(BlockDB.SumHash)) { + bFindDB = 1 + arr2.push(Block) + } + } + else + if (bFindDB) { + arr2.push(Block) + } + } + if (arr2.length > 1) { + Context.WasLoadNum = 1 + var chain = { id: 0, StopSend: 1, WriteToDBAfterLoad: 1 }; + this.ChainBindMethods(chain) + this.SetChainNum(chain) + this.PrepareTransactionsForLoad(chain, arr2) + Context.BlockNum = Block.BlockNum + Context.Pause = 1 + } + else { + if (!Context.WasLoadNum) { + Context.BlockNum = Math.floor(Context.BlockNum - Context.DeltaBlockNum) + Context.DeltaBlockNum = Context.DeltaBlockNum * 1.2 + if (Context.BlockNum < global.BLOCK_PROCESSING_LENGTH2) + Context.BlockNum = global.BLOCK_PROCESSING_LENGTH2 - 1 + this.BlockNumDB = Context.BlockNum + this.SetTruncateBlockDB(Context.BlockNum) + } + else { + var keysend = "" + Info.Node.addrStr + ":" + Context.BlockNum; + Context.MapSend[keysend] = 1 + } + } + } + RETBLOCKHEADER(Info, CurTime) { + Info.Node.NextPing = MIN_PERIOD_PING + if (Info.Context.Foward) + return this.RETBLOCKHEADER_FOWARD(Info, CurTime); + var chain = Info.Context.Chain; + if (chain && !chain.StopSend && !chain.Deleted) { + var BufRead = global.BufLib.GetReadBuffer(Info.Data); + chain.time = undefined + var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info); + if (arr.length <= 1) { + var keysend = "" + Info.Node.addrStr + ":" + chain.BlockNum; + chain.MapSend[keysend] = 1 + chain.AddInfo("NO:" + GetNodeStrPort(Info.Node)) + return; + } + chain.AddInfo("L=" + arr.length + " from:" + GetNodeStrPort(Info.Node)) + var NextLoadBlock; + var PrevBlock; + for (var i = arr.length - 1; i >= 0; i--) { + var Block = arr[i]; + var StrKey = global.GetHexFromArr(Block.SumHash); + var MapBlockLoaded = this.GetMapLoaded(Block.BlockNum); + var BlockFind = MapBlockLoaded[StrKey]; + if (BlockFind && BlockFind.chain !== chain && BlockFind.chain.Deleted) { + delete MapBlockLoaded[StrKey] + BlockFind = undefined + } + if (!chain.BlockHead) + chain.BlockHead = Block + if (!chain.BlockNumMax) + chain.BlockNumMax = Block.BlockNum + var PrevBlock0 = PrevBlock; + if (BlockFind) { + if (PrevBlock) { + PrevBlock.BlockDown = BlockFind + PrevBlock.Send = undefined + } + PrevBlock = BlockFind + } + else { + if (PrevBlock) { + PrevBlock.BlockDown = Block + PrevBlock.Send = undefined + } + PrevBlock = Block + } + if (BlockFind && BlockFind.chain !== chain) { + chain.ParentChain = BlockFind.chain + chain.RootChain = BlockFind.chain.GetRootChain() + if (chain.RootChain) + chain.RootChain.BlockNumMax = chain.BlockHead.BlockNum + chain.StopSend = true + chain.AddInfo("StopSend - Find load Block") + break; + } + else + if (!BlockFind) { + Block.chain = chain + Block.Node = Info.Node + var StrSumHash = global.GetHexFromArr(Block.SumHash); + MapBlockLoaded[StrSumHash] = Block + var StrHash = global.GetHexFromArr(Block.Hash); + MapBlockLoaded["H:" + StrHash] = Block + var StrTreeHash = global.GetHexFromArr(Block.TreeHash); + MapBlockLoaded["TH:" + StrTreeHash] = Block + var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum); + if (BlockDB) { + Block.Power = GetPowPower(Block.PowHash) + chain.LoadCountDB++ + chain.LoadSumDB += BlockDB.Power + chain.LoadSum += Block.Power + if (global.CompareArr(BlockDB.SumHash, Block.SumHash) === 0) { + Block.FindBlockDB = true + Block.SumPow = BlockDB.SumPow + chain.FindBlockDB = true + chain.StopSend = true + chain.AddInfo("BlockFind - Find Block in DB") + NextLoadBlock = undefined + break; + } + } + NextLoadBlock = Block + } + } + if (NextLoadBlock && !NextLoadBlock.chain.StopSend) { + if (arr.length >= chain.Count) { + chain.Count = chain.Count * 2 + if (chain.Count > COUNT_BLOCKS_FOR_LOAD) + chain.Count = COUNT_BLOCKS_FOR_LOAD + } + if (chain.LoadCountDB >= COUNT_BLOCKS_FOR_CHECK_POW) { + if (chain.LoadSumDB - chain.LoadSum > MAX_DELTA_COUNT_SUM_FOR_LOAD) { + var Str = "ERR LOADED SUM POW chains: SumDB > Sum loaded from: " + NodeInfo(Info.Node); + chain.StopSend = true + chain.AddInfo(Str) + } + } + if (!chain.StopSend) + this.BlockChainLoad(NextLoadBlock) + } + if (chain.GetFindDB()) + this.CheckToStartLoadBlockData(chain) + } + } + BlockChainLoad(Block) { + var chain = Block.chain; + Block.Send = undefined + chain.BlockNum = Block.BlockNum + chain.Hash = Block.SumHash + chain.IsSum = true + chain.StopSend = false + chain.FindBlockDB = false + chain.RootChain = undefined + chain.ParentChain = undefined + chain.AddInfo("SetChainSend:" + chain.BlockNum) + } + CheckToStartLoadBlockData(chain) { + if (chain.Deleted) + return; + var arr = this.GetArrFromChain(chain); + if (arr.length < 2) + return; + var BlockMax = arr[arr.length - 1]; + var BlockMin = arr[0]; + var PrevBlock = BlockMin; + for (var i = 1; i < arr.length; i++) { + var Block = arr[i]; + Block.Power = GetPowPower(Block.PowHash) + Block.SumPow = PrevBlock.SumPow + Block.Power + PrevBlock = Block + } + var BlockNow = this.ReadBlockHeaderDB(BlockMax.BlockNum); + if (BlockNow && (BlockMax.SumPow < BlockNow.SumPow || BlockMax.SumPow === BlockNow.SumPow && global.CompareArr(BlockMax.PowHash, BlockNow.PowHash) < 0)) { + var Str = "Low SumPow"; + chain.AddInfo(Str) + return; + } + var Str = "Start Load blocks: " + (BlockMin.BlockNum + 1) + " - " + BlockMax.BlockNum; + chain.AddInfo(Str) + this.PrepareTransactionsForLoad(chain, arr) + } + GetArrFromChain(chain) { + var arr = []; + var Block = chain.BlockHead; + while (Block) { + arr.unshift(Block) + if (Block.AddToLoad || Block.FindBlockDB || Block.LoadDBFinaly) { + break; + } + Block = Block.BlockDown + } + return arr; + } + PrepareTransactionsForLoad(chain, arr, bNoSlice) { + if (!bNoSlice) + arr = arr.slice(1) + chain.arr = arr + if (arr.length > 0) { + for (var i = 0; i < arr.length; i++) + arr[i].AddToLoad = 1 + chain.CurNumArrLoad = 0 + } + } + LoopBlockLoad() { + if (glStopNode) + return; + var CountSend = 0; + for (var num = 0; num < this.LoadedChainList.length; num++) { + var chain = this.LoadedChainList[num]; + if (chain && chain.arr && chain.arr.length && chain.StopSend) { + var Count = 0; + for (var i = chain.CurNumArrLoad; i < chain.arr.length; i++) { + Count++ + var Block = chain.arr[i]; + if (!IsZeroArr(Block.TreeHash) && !Block.TreeEq && !Block.LoadDBFinaly) { + if (!Block.MapSend) { + if (!Block.BodyLoad) { + var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum); + if (BlockDB) { + if (global.CompareArr(BlockDB.TreeHash, Block.TreeHash) == 0) { + Block.TreeEq = true + Block.Reserv500 = BlockDB.Reserv500 + Block.TrDataPos = BlockDB.TrDataPos + Block.TrDataLen = BlockDB.TrDataLen + continue; + } + } + } + Block.MapSend = {} + } + if (this.SendBlockNext(Block)) { + CountSend++ + if (CountSend >= MAX_BLOCK_SEND) + return; + } + } + else + if (i === chain.CurNumArrLoad) { + chain.CurNumArrLoad++ + Block.LoadDBFinaly = true + Count = 0 + } + } + this.CheckAndWriteLoadedChain(chain) + } + } + } + CheckAndWriteLoadedChain(chain) { + if (chain.CurNumArrLoad >= chain.arr.length) { + var Block = chain.arr[chain.arr.length - 1]; + if (chain.WriteToDBAfterLoad || Block.BlockNum >= this.CurrentBlockNum + TIME_START_SAVE - 2) { + var bAllLoaded = true; + if (!chain.WriteToDBAfterLoad) { + var cur_parent = chain.ParentChain; + while (cur_parent) { + if (cur_parent.arr && cur_parent.CurNumArrLoad < cur_parent.arr.length) { + bAllLoaded = false + break; + } + cur_parent = cur_parent.ParentChain + } + } + if (bAllLoaded) { + var arr = []; + var cur_chain = chain; + while (cur_chain) { + if (cur_chain.arr) + for (var i = cur_chain.arr.length - 1; i >= 0; i--) { + var Block = cur_chain.arr[i]; + arr.unshift(Block) + } + cur_chain = cur_chain.ParentChain + } + this.WriteLoadedBlockArr(arr) + } + } + } + } + WriteLoadedBlockArr(arr) { + if (!arr.length) + return; + var startTime = process.hrtime(); + if (this.LoadHistoryMessage) + global.ToLog("WRITE DATA Count:" + arr.length + " " + arr[0].BlockNum + "-" + arr[arr.length - 1].BlockNum, 2) + var CurrentBlockNum = GetCurrentBlockNumByTime(); + var Block, FirstBlock; + for (var i = 0; i < arr.length; i++) { + Block = arr[i] + if (Block.BlockNum > this.BlockNumDB + 1) + break; + if (!FirstBlock) + FirstBlock = Block + Block.BlockDown = undefined + if (Block.BlockNum > this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) { + var PrevHash = this.GetPrevHashDB(Block); + if (global.CompareArr(PrevHash, Block.PrevHash) !== 0) { + if (global.WATCHDOG_DEV) + global.ToError("******** ERROR LOADED DATA Count:" + arr.length + " AT BLOCK NUM:" + Block.BlockNum + " (" + arr[0].BlockNum + "-" + arr[arr.length - 1].BlockNum + ")") + this.FREE_ALL_MEM_CHAINS() + return; + } + } + var Res = 0; + if (Block.TreeEq) { + this.ReadBlockBodyDB(Block) + Res = this.WriteBlockDBFinaly(Block) + } + else { + if (IsZeroArr(Block.TreeHash)) { + Res = this.WriteBlockDB(Block) + } + else { + ToLogTrace("IsZeroArr(Block.TreeHash)") + throw "IsZeroArr(Block.TreeHash)"; + } + } + if (!Res) { + global.ToLog("ERROR WRITE DB, NUM=" + Block.BlockNum) + this.FREE_ALL_MEM_CHAINS() + return; + } + Block.LoadDB = true + if (Block.BlockNum >= CurrentBlockNum - BLOCK_COUNT_IN_MEMORY) { + this.CopyBlockToMem(Block) + } + else { + if (Block.arrContent) + Block.arrContent.length = 0 + Block.arrContent = undefined + } + var BlockMem = this.BlockChain[Block.BlockNum]; + if (BlockMem) { + AddInfoBlock(BlockMem, "LOAD:" + GetPowPower(Block.PowHash) + " TH:" + this.GetStrFromHashShort(Block.TreeHash).substr(0, 4)) + } + } + if (Block && FirstBlock) { + var CurNumStart = Math.max(FirstBlock.BlockNum + 8, Block.BlockNum + 1); + this.SetNoPOW(CurNumStart, 1, FirstBlock.BlockNum) + } + this.FREE_ALL_MEM_CHAINS() + ADD_TO_STAT_TIME("WRITECHAIN_TO_DB_TIME", startTime) + } + CopyBlock(Block, BlockDst) { + BlockDst.BlockNum = Block.BlockNum + BlockDst.TreeHash = Block.TreeHash + BlockDst.AddrHash = Block.AddrHash + BlockDst.PrevHash = Block.PrevHash + BlockDst.SumHash = Block.SumHash + BlockDst.SumPow = Block.SumPow + BlockDst.TrDataPos = Block.TrDataPos + BlockDst.TrDataLen = Block.TrDataLen + BlockDst.SeqHash = Block.SeqHash + BlockDst.Hash = Block.Hash + BlockDst.PowHash = Block.PowHash + BlockDst.TrCount = Block.TrCount + BlockDst.arrContent = Block.arrContent + BlockDst.bSave = Block.bSave + } + CopyBlockToMem(Block) { + var BlockMem = this.BlockChain[Block.BlockNum]; + if (BlockMem) { + this.CopyBlock(Block, BlockMem) + BlockMem.Prepared = true + BlockMem.MinTrPow = undefined + this.RecreateMaxPOW(BlockMem) + } + this.AddToStatBlockConfirmation(Block) + } + ClearMaxInBlock(Block) { + Block.MaxPOW = {} + var POW = Block.MaxPOW; + POW.SeqHash = Block.SeqHash + POW.AddrHash = Block.AddrHash + POW.PrevHash = Block.PrevHash + POW.TreeHash = Block.TreeHash + POW.Hash = Block.Hash + POW.PowHash = Block.PowHash + POW.SumPow = Block.SumPow + Block.MaxSum = {} + POW = Block.MaxSum + POW.SeqHash = Block.SeqHash + POW.AddrHash = Block.AddrHash + POW.PrevHash = Block.PrevHash + POW.TreeHash = Block.TreeHash + POW.Hash = Block.Hash + POW.PowHash = Block.PowHash + POW.SumHash = Block.SumHash + POW.SumPow = Block.SumPow + } + AddToStatBlockConfirmation(Block) { + if (Block.BlockNum > START_BLOCK_RUN + global.BLOCK_PROCESSING_LENGTH2) { + var TimeDelta = this.CurrentBlockNum - Block.BlockNum; + global.ADD_TO_STAT("MAX:BlockConfirmation", TimeDelta) + } + else { + global.ADD_TO_STAT("MAX:BlockConfirmation", BLOCK_PROCESSING_LENGTH) + } + } + SendBlockNext(Block) { + var SendResult = 0; + var Key = global.GetHexFromArr(Block.TreeHash); + while (true) { + var Ret = this.GetNextNode(Block, Key, true, Block.BlockNum); + if (Ret.Result) { + var Node = Ret.Node; + if (!Block.Context) + Block.Context = { Block: Block } + this.SendF(Node, { "Method": "GETBLOCK", "Context": Block.Context, "Data": { BlockNum: Block.BlockNum, TreeHash: Block.TreeHash } }) + Node.SendBlockCount++ + SendResult = 1 + AddInfoBlock(Block, "SendNext") + if (Block.chain) + Block.chain.AddInfo("QUERY BL:" + Block.BlockNum + "/" + this.GetStrFromHashShort(Block.TreeHash) + " TO:" + GetNodeStrPort(Node)) + } + else { + if (!Ret.timewait) { + this.ClearChains(Block.chain, true) + } + } + break; + } + return SendResult; + } + ClearChains(DeleteChain, bShow) { + if (!DeleteChain) { + this.FREE_ALL_MEM_CHAINS() + return this.LoadedChainList.length; + } + var allsum = this.LoadedChainList.length; + var Sum = 0; + for (var i = 0; i < this.LoadedChainList.length; i++) { + var chain = this.LoadedChainList[i]; + if (chain) { + if (chain === DeleteChain) { + chain.Deleted = true + this.LoadedChainList[i] = undefined + Sum++ + } + if (chain.ParentChain === DeleteChain) { + Sum += this.ClearChains(chain) + } + } + } + if (bShow) { + global.ToLog("===========ClearChains================= " + DeleteChain.id + " count=" + Sum + "/" + allsum) + } + return Sum; + } + RecalcLoadBlockStatictic() { + return; + var TimeNum = Math.floor(Date.now() / STAT_BLOCK_LOAD_PERIOD); + if (this.LoadBlockStatNum === TimeNum) + return; + this.LoadBlockStatNum = TimeNum + const PeriodSec = 5; + const Period = CONSENSUS_PERIOD_TIME / STAT_BLOCK_LOAD_PERIOD; + const PeriodCount = PeriodSec * Period; + var FreeGet = 64; + var it = this.ActualNodes.iterator(), Node; + while ((Node = it.next()) !== null) { + var arr = Node.SendBlockArr; + arr.push(Node.SendBlockCount) + if (arr.length > PeriodCount) { + arr.shift() + } + arr = Node.LoadBlockArr + arr.push(Node.LoadBlockCount) + if (arr.length > PeriodCount) { + arr.shift() + } + var SendPackets = 0; + var LoadPackets = 0; + for (var i = 0; i < Node.SendBlockArr.length; i++) + SendPackets += Node.SendBlockArr[i] + for (var i = 0; i < Node.LoadBlockArr.length; i++) + LoadPackets += Node.LoadBlockArr[i] + Node.SendBlockCountAll = SendPackets + Node.LoadBlockCountAll = LoadPackets + var Nuts = Math.floor(LoadPackets / PeriodSec); + var RestPackets = SendPackets - LoadPackets; + var CountGet = 1 + Math.floor(Math.max(0, (Nuts - RestPackets / Period))); + Node.CanGetBlocks = Math.min(FreeGet, CountGet) + FreeGet -= Node.CanGetBlocks + Node.SendBlockCount = 0 + Node.LoadBlockCount = 0 + global.ADD_TO_STAT("NODE_CAN_GET:" + NodeName(Node), Node.CanGetBlocks, 1) + } + } + static + GETBLOCK_F() { + return "{\ + BlockNum:uint,\ + TreeHash:hash,\ + }"; + } + RETGETBLOCK(Info, CurTime) { + Info.Node.NextPing = MIN_PERIOD_PING + var Block = Info.Context.Block; + if (Block && !Block.TreeEq) { + var Data = global.BufLib.GetObjectFromBuffer(Info.Data, FORMAT_BLOCK_TRANSFER, WRK_BLOCK_TRANSFER); + Info.Data = undefined + if (Data.BlockNum !== Block.BlockNum || global.CompareArr(Data.TreeHash, Block.TreeHash) !== 0) { + this.SetBlockNOSendToNode(Block, Info.Node, "NO") + return; + } + if (Block.chain) { + Block.chain.AddInfo("Load TR:" + Data.BlockNum + "/" + this.GetStrFromHashShort(Data.TreeHash) + " from:" + GetNodeStrPort(Info.Node)) + AddInfoBlock(Block, "LOAD TR OK") + } + var arrContent = Data.arrContent; + var TreeHash = CalcTreeHashFromArrBody(Block.BlockNum, arrContent); + if (global.CompareArr(Block.TreeHash, TreeHash) !== 0) { + global.ToLog("2. BAD CMP TreeHash block=" + Block.BlockNum + " from:" + NodeName(Info.Node) + " TreeHash=" + global.GetHexFromArr(TreeHash) + " BlockTreeHash=" + global.GetHexFromArr(Block.TreeHash)) + this.SetBlockNOSendToNode(Block, Info.Node, "BAD CMP TreeHash") + return; + } + if (arrContent.length > 0 && Data.BlockNum % PERIOD_ACCOUNT_HASH === 0) { + var TR = arrContent[0]; + if (TR[0] === TYPE_TRANSACTION_ACC_HASH) { + if (!DApps.Accounts.TRCheckAccountHash(TR, Data.BlockNum)) { + if (!this.BADHashCount) + this.BADHashCount = 0 + this.BADHashCount++ + global.ToLog("**** BAD ACCOUNT Hash in block=" + Block.BlockNum + " from:" + NodeName(Info.Node) + " ****") + global.ToLog("May be need to Rewrite transactions from: " + (Block.BlockNum - 2 * DELTA_BLOCK_ACCOUNT_HASH)) + this.SetBlockNOSendToNode(Block, Info.Node, "BAD CMP ACC HASH") + if (global.WATCHDOG_BADACCOUNT && this.BADHashCount > 60) { + global.ToLog("Run WATCHDOG!") + this.BADHashCount = 0 + this.FREE_ALL_MEM_CHAINS() + this.SetTruncateBlockDB(Block.BlockNum - 5 * DELTA_BLOCK_ACCOUNT_HASH) + } + else { + } + return; + } + } + } + Block.arrContent = arrContent + var Ret = this.WriteBodyDB(Block); + Block.TrCount = 0 + Block.arrContent.length = 0 + Block.arrContent = undefined + if (!Ret) { + this.SetBlockNOSendToNode(Block, Info.Node, "Error write") + return; + } + Block.TreeEq = true + Block.Send = undefined + global.ADD_TO_STAT("BLOCK_LOADED", 1) + Info.Node.LoadBlockCount++ + if (GrayConnect()) + Info.Node.BlockProcessCount++ + if (this.LoadHistoryMode) { + var Context = this.LoadHistoryContext; + Context.PrevBlockNum = Context.BlockNum + Context.StartTimeHistory = Date.now() + } + } + } + SendCanBlock(Node, Block) { + Node.SendBlockCount++ + if (!Node.INFO.BlockNumDB) + return; + if (Node.INFO.BlockNumDB >= Block.BlockNum) { + this.SendF(Node, { "Method": "CANBLOCK", "Data": { BlockNum: Block.BlockNum } }) + } + } + static + CANBLOCK_F() { + return "{BlockNum:uint}"; + } + CANBLOCK(Info, CurTime) { + var Data = this.DataFromF(Info); + this.SendF(Info.Node, { "Method": "RETCANBLOCK", "Data": { Result: 1 } }) + } + static + RETCANBLOCK_F() { + return "{Result:byte}"; + } + RETCANBLOCK(Info, CurTime) { + var Data = this.DataFromF(Info); + if (Data.Result === 1) { + Info.Node.LoadBlockCount++ + } + } + SetBlockNOSendToNode(Block, Node, Str) { + var Str = global.GetHexFromArr(Block.TreeHash); + var Str2 = this.GetStrFromHashShort(Block.TreeHash); + var keysend = "" + Node.addrStr + ":" + Str; + Block.MapSend[keysend] = 1 + if (Block.chain) + Block.chain.AddInfo("" + Block.BlockNum + " " + Str2 + "<-" + GetNodeStrPort(Node)) + } + FindBlockInLoadedChain(BlockNum, TreeHash) { + var StrTreeHash = global.GetHexFromArr(TreeHash); + var MapBlockLoaded = this.GetMapLoaded(BlockNum); + var BlockFind = MapBlockLoaded["TH:" + StrTreeHash]; + if (BlockFind && BlockFind.TreeEq) + return BlockFind; + else + return undefined; + } + CheckSeqHashDB(Block, StrError) { + if (Block.BlockNum < global.BLOCK_PROCESSING_LENGTH2) + return true; + var TreeHashTest = CalcTreeHashFromArrBody(Block.BlockNum, Block.arrContent); + if (global.CompareArr(TreeHashTest, Block.TreeHash) !== 0) { + var StrHex = global.GetHexFromArr(TreeHashTest); + var StrHex0 = global.GetHexFromArr(Block.TreeHash); + var Str = StrError + " #3 ERROR TREEHASH: " + Block.BlockNum + " Hex:" + StrHex0.substr(0, 12) + " != " + StrHex.substr(0, + 12); + if (global.WATCHDOG_DEV) + ToErrorTrace(Str) + else + global.ToError(Str) + return false; + } + var PrevHash = this.GetPrevHashDB(Block); + var testSeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); + var TestValue = GetHashFromSeqAddr(testSeqHash, Block.AddrHash, Block.BlockNum, PrevHash); + if (global.CompareArr(TestValue.Hash, Block.Hash) !== 0) { + var Str = StrError + " #2 ERROR HASH - block num: " + Block.BlockNum; + if (global.WATCHDOG_DEV) + ToErrorTrace(Str) + else + global.ToError(Str) + return false; + } + return true; + } + ToLogBlock(Block, StrInfo, arr) { + global.ToLog("-------------" + StrInfo) + global.ToLog("BlockNum=" + (Block.BlockNum)) + global.ToLog("Hash=" + global.GetHexFromArr(Block.Hash)) + global.ToLog("SeqHash=" + global.GetHexFromArr(Block.SeqHash)) + global.ToLog("PrevHash=" + global.GetHexFromArr(Block.PrevHash)) + global.ToLog("TreeHash=" + global.GetHexFromArr(Block.TreeHash)) + global.ToLog("AddrHash=" + global.GetHexFromArr(Block.AddrHash)) + global.ToLog("SumHash=" + global.GetHexFromArr(Block.SumHash)) + global.ToLog("SumPow=" + Block.SumPow) + for (var i = 0; i < arr.length; i++) { + global.ToLog("arr[" + i + "]=" + global.GetHexFromArr(arr[i])) + } + } + GetBlock(num, bToMem, bReadBody) { + if (bToMem === undefined) + bToMem = true + if (num < this.CurrentBlockNum - BLOCK_COUNT_IN_MEMORY) + bToMem = false + var Block = this.BlockChain[num]; + if (!Block) { + if (bReadBody) + Block = this.ReadBlockDB(num) + else + Block = this.ReadBlockHeaderDB(num) + if (bToMem) { + this.BlockChain[num] = Block + } + } + return Block; + } + GetMapLoaded(num) { + if (num < 0) + num = 0 + var index = Math.floor(num / BLOCK_COUNT_IN_MEMORY); + var map = this.MapMapLoaded[index]; + if (!map) { + map = {} + this.MapMapLoaded[index] = map + } + return map; + } + GetMapLoadedFromChain(chain) { + return this.GetMapLoaded(chain.BlockNumStart); + } + FREE_MEM_BLOCKS(NumMax) { + for (var key in this.BlockChain) { + var Block = this.BlockChain[key]; + if (!Block || Block.BlockNum < NumMax) { + delete this.BlockChain[key] + } + } + } + FREE_MEM_CHAINS(NumMax) { + this.FREE_MEM_BLOCKS(NumMax - BLOCK_COUNT_IN_MEMORY) + var maxArrMap = Math.floor(NumMax / BLOCK_COUNT_IN_MEMORY) - 1; + if (maxArrMap >= 0) { + var nWasCount = 0; + for (var key in this.MapMapLoaded) + if (key < maxArrMap) { + nWasCount++ + delete this.MapMapLoaded[key] + } + } + } + FREE_ALL_MEM_CHAINS() { + this.FREE_MEM_BLOCKS(this.BlockNumDB - BLOCK_COUNT_IN_MEMORY) + for (var i = 0; i < this.LoadedChainList.length; i++) { + var chain = this.LoadedChainList[i]; + if (chain) { + chain.Deleted = true + chain.ChainMax = undefined + } + } + if (!this.LoadHistoryMode) { + this.AddValueToHistory("LoadedChainList", this.LoadedChainList) + this.AddValueToHistory("MapMapLoaded", this.MapMapLoaded) + } + this.LoadedChainList = [] + this.MapMapLoaded = {} + if (typeof gc === "function") + gc() + } + AddValueToHistory(typedata, val) { + var Arr = global.HistoryBlockBuf.LoadValue(typedata, 1); + if (!Arr) { + Arr = [] + global.HistoryBlockBuf.SaveValue(typedata, Arr) + } + Arr.push(val) + } + GetHistoryTree(typedata) { + var Tree = global.HistoryBlockBuf.LoadValue(typedata, 1); + if (!Tree) { + Tree = new RBTree(CompareItemHash) + global.HistoryBlockBuf.SaveValue(typedata, Tree) + } + return Tree; + } + ChainBindMethods(chain) { + + function GetRootChain() { + var Count = 0; + var root_chain = this; + while (root_chain.RootChain) { + Count++ + root_chain = root_chain.RootChain + if (Count > MAX_COUNT_CHAIN_LOAD) { + TO_ERROR_LOG("BLOCK", 10, "Error COUNT GetRootChain") + global.SERVER.FREE_ALL_MEM_CHAINS() + return undefined; + } + } + return root_chain; + }; + + function GetFindDB() { + var Root = this.GetRootChain(); + if (Root) + return Root.FindBlockDB; + else + return false; + }; + chain.GetRootChain = GetRootChain.bind(chain) + chain.GetFindDB = GetFindDB.bind(chain) + chain.AddInfo = AddInfoChain.bind(chain) + } + GetMemoryStamp(Str) { + return Str + ":##:" + Math.floor(this.CurrentBlockNum / BLOCK_COUNT_IN_MEMORY); + } + GetStrFromHashShort(Hash) { + var Str = global.GetHexFromArr(Hash); + if (typeof Str === "string") + return Str.substr(0, 6); + else + return ""; + } + ToLogTime(startTime, Str) { + const Time = process.hrtime(startTime); + var deltaTime = (Time[0] * 1000 + Time[1] / 1e6); + global.ToLog(Str + " : " + deltaTime + "ms") + } + AddBlockToLoadBody(Block) { + if (!this.MapBlockBodyLoad[Block.BlockNum]) { + this.MapBlockBodyLoad[Block.BlockNum] = Block + } + } + LoopBlockBodyLoad() { + var arr = []; + for (var key in this.MapBlockBodyLoad) { + var Block = this.MapBlockBodyLoad[key]; + if (!Block.BodyLoad) { + Block.BodyLoad = 1 + arr.push(Block) + } + } + this.MapBlockBodyLoad = {} + if (!arr.length) + return; + var chain = { StopSend: 1, WriteToDBAfterLoad: 1, BodyLoad: 1 }; + this.ChainBindMethods(chain) + this.SetChainNum(chain) + this.PrepareTransactionsForLoad(chain, arr, 1) + } +}; +global.LoadBlockFromNetwork = function(Params, F) { + var BlockNum = Params.BlockNum; + if (BlockNum >= global.SERVER.BlockNumDBMin) { + global.ToLog("Cant LoadBlockFromNetwork:" + BlockNum, 2); + F(1); + return; + } + global.ToLog("Start DownloadBlockFromNetwork:" + BlockNum, 2); + var TaskLoadBlockFromNetwork = { MapSend: {} }; + var Ret = global.SERVER.GetNextNode(TaskLoadBlockFromNetwork, BlockNum, 1); + if (Ret.Result) { + let Node = Ret.Node; + global.SERVER.SendF(Node, { + "Method": "GETBLOCK", "Data": { BlockNum: BlockNum, TreeHash: [] }, "Context": { + F: function(Info) { + var Block = global.BufLib.GetObjectFromBuffer(Info.Data, FORMAT_BLOCK_TRANSFER, WRK_BLOCK_TRANSFER); + Info.Data = undefined; + if (!Block.BlockNum || Block.BlockNum !== Params.BlockNum) { + global.ToLog("Error get BlockNum:" + Params.BlockNum + " from " + NodeName(Info.Node), 2); + F(1); + return; + } + global.ToLog("Got BlockFromNetwork:" + Params.BlockNum + " from " + NodeName(Info.Node), 2); + var ResError; + if (!Block.arrContent || Block.arrContent.length === 0) { + ResError = 1; + } + else { + ResError = 0; + global.SERVER.WriteBlockDB(Block); + } + F(ResError, Block); + } + }, + }); + } + else { + global.ToLog("Not find node for download block", 2); + F(1); + } +}; +global.HistoryBlockBuf = new STreeBuffer(HISTORY_BLOCK_COUNT * 1000, CompareItemHashSimple, "string"); diff --git a/src/core/buffer.ts b/src/core/buffer.ts new file mode 100644 index 0000000..52a1bb0 --- /dev/null +++ b/src/core/buffer.ts @@ -0,0 +1,364 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + + +function Write(e,r,t,n,l) +{ + if(!(e.len >= e.length)) + { + if("number" == typeof t) + throw ToLogTrace("ERRR StringFormat "), "ERR!!"; + var a = t; + if("buffer" === a.substr(0, 6) && 6 < a.length) + n = parseInt(a.substr(6)), a = "buffer"; + else + if("arr" === a.substr(0, 3) && 3 < a.length) + n = parseInt(a.substr(3)), a = "arr"; + else + if("str" === a.substr(0, 3) && 3 < a.length) + { + var i = parseInt(a.substr(3)); + return r && e.write(r, e.len, i), void (e.len += i); + } + switch(a) + { + case "str": + var f = toUTF8Array(r); + 65535 < (i = f.length) && (i = 0), e[e.len] = 255 & i, e[e.len + 1] = i >>> 8 & 255, e.len += 2; + for(var s = 0; s < i; s++) + e[e.len + s] = f[s]; + e.len += i; + break; + case "byte": + r < 0 && (r = 0), e[e.len] = r, e.len += 1; + break; + case "double": + e.writeDoubleLE(r, e.len, 8), e.len += 8; + break; + case "uint": + r < 0 && (r = 0), 0xffffffffffff <= r && (r = 0), e.writeUIntLE(r, e.len, 6), e.len += 6; + break; + case "uint16": + r < 0 && (r = 0), e[e.len] = 255 & r, e[e.len + 1] = r >>> 8 & 255, e.len += 2; + break; + case "uint32": + r < 0 && (r = 0), e.writeUInt32LE(r, e.len, 4), e.len += 4; + break; + case "time": + var u = r.valueOf(); + e.writeUIntLE(u, e.len, 6), e.len += 6; + break; + case "addres": + case "hash": + i = r ? Math.min(32, r.length) : 0; + for(s = 0; s < i; s++) + e[e.len + s] = r[s]; + e.len += 32; + break; + case "buffer": + i = void 0 === n ? r.length : Math.min(n, r.length); + for(s = 0; s < i; s++) + e[e.len + s] = r[s]; + e.len += n; + break; + case "arr": + i = r ? Math.min(n, r.length) : 0; + for(s = 0; s < i; s++) + e[e.len + s] = r[s]; + e.len += n; + break; + case "tr": + i = r.length; + MAX_TRANSACTION_SIZE > MAX_TRANSACTION_SIZE && (i = MAX_TRANSACTION_SIZE), e[e.len] = 255 & i, e[e.len + 1] = i >>> 8 & 255, + e.len += 2; + for(s = 0; s < i; s++) + e[e.len + s] = r[s]; + e.len += i; + break; + case "data": + i = r.length; + e.writeUInt32LE(i, e.len, 4), e.len += 4; + for(s = 0; s < i; s++) + e[e.len + s] = r[s]; + e.len += i; + break; + case "hashSTR": + var o = GetHexFromAddres(r); + e.write(o, e.len, 64), e.len += 64; + break; + case "uintSTR": + o = r.toString(); + e.write(o, e.len, 10), e.len += 10; + break; + default: + l = l || {}; + var d = t.substr(0, 1); + if("[" === d) + { + r && (i = r.length); + var b = GetMiddleString(a); + Write(e, i, "uint32"); + for(s = 0; s < i; s++) + Write(e, r[s], b, void 0, l); + } + else + if("<" === d) + { + r && (i = r.length); + b = GetMiddleString(a); + var h = 0, c = e.len; + e.len += 4; + for(s = 0; s < i; s++) + r[s] && (h++, Write(e, s, "uint32"), Write(e, r[s], b, void 0, l)); + e.writeUInt32LE(h, c, 4); + } + else + { + if("{" !== d) + throw "Bad write type params: " + a; + var g = l[a]; + g || (g = GetAttributes(GetMiddleString(a)), l[a] = g); + for(s = 0; s < g.length; s++) + { + var v = g[s]; + Write(e, r[v.Key], v.Value, void 0, l); + } + } + } + } +}; + +function Read(e,r,t,n,l) +{ + var a; + if("number" == typeof r) + throw ToLogTrace("ERR StringFormat"), "ERRR!"; + var i = r; + if("buffer" === i.substr(0, 6)) + 6 < i.length ? (t = parseInt(i.substr(6)), i = "buffer") : t = 0; + else + if("arr" === i.substr(0, 3)) + 3 < i.length ? (t = parseInt(i.substr(3)), i = "arr") : t = 0; + else + if("str" === i.substr(0, 3)) + { + if(3 < i.length) + { + var f = parseInt(i.substr(3)); + a = e.toString("utf8", e.len, e.len + f), e.len += f; + for(var s = - 1, u = a.length - 1; 0 <= u; u--) + if(0 !== a.charCodeAt(u)) + { + s = u; + break; + } + return a = 0 <= s ? a.substr(0, u + 1) : ""; + } + t = 0; + } + switch(i) + { + case "str": + f = e.len + 2 <= e.length ? e[e.len] + 256 * e[e.len + 1] : 0, e.len += 2; + var o = e.slice(e.len, e.len + f); + a = Utf8ArrayToStr(o), e.len += f; + break; + case "byte": + a = e.len + 1 <= e.length ? e[e.len] : 0, e.len += 1; + break; + case "double": + a = e.len + 8 <= e.length ? e.readDoubleLE(e.len, 8) : 0, e.len += 8; + break; + case "uint": + a = e.len + 6 <= e.length ? e.readUIntLE(e.len, 6) : 0, e.len += 6; + break; + case "uint16": + a = e.len + 2 <= e.length ? e[e.len] + 256 * e[e.len + 1] : 0, e.len += 2; + break; + case "uint32": + a = e.len + 4 <= e.length ? e.readUInt32LE(e.len, 4) : 0, e.len += 4; + break; + case "time": + if(l) + throw "Bad read type params: time - DisableTime ON"; + a = e.len + 6 <= e.length ? e.readUIntLE(e.len, 6) : 0, a = new Date(a), e.len += 6; + break; + case "addres": + case "hash": + a = []; + for(u = 0; u < 32; u++) + e.len + u <= e.length ? a[u] = e[e.len + u] : a[u] = 0; + e.len += 32; + break; + case "buffer": + case "arr": + a = e.len + t <= e.length ? e.slice(e.len, e.len + t) : Buffer.alloc(t), e.len += t; + break; + case "tr": + if(e.len + 1 >= e.length) + { + a = void 0; + break; + } + f = e[e.len] + 256 * e[e.len + 1]; + e.len += 2, a = e.slice(e.len, e.len + f), e.len += f; + break; + case "data": + (f = e.len + 4 <= e.length ? e.readUInt32LE(e.len, 4) : 0) > e.length - e.len - 4 && (f = 0), e.len += 4, a = e.slice(e.len, + e.len + f), e.len += f; + break; + case "hashSTR": + var d = e.toString("utf8", e.len, e.len + 64); + a = GetAddresFromHex(d), e.len += 64; + break; + case "uintSTR": + d = e.toString("utf8", e.len, e.len + 10); + a = parseInt(d), e.len += 10; + break; + default: + n = n || {}; + var b = i.substr(0, 1); + if("[" === b || "<" === b) + { + var h = "<" === b; + a = []; + var c = GetMiddleString(i); + for(f = Read(e, "uint32"), u = 0; u < f && e.len <= e.length; u++) + { + h ? a[Read(e, "uint32")] = Read(e, c, void 0, n, l) : a[u] = Read(e, c, void 0, n, l); + } + } + else + { + if("{" !== b) + throw "Bad read type params: " + i; + var g = n[i]; + g || (g = GetAttributes(GetMiddleString(i)), n[i] = g), a = {}; + for(u = 0; u < g.length; u++) + { + var v = g[u]; + a[v.Key] = Read(e, v.Value, void 0, n, l); + } + } + } + return a; +}; + +function BufWriteByte(e) +{ + this[this.len] = e, this.len += 1; +}; + +function BufWrite(e,r,t) +{ + Write(this, e, r, t); +}; + +function BufRead(e,r) +{ + return Read(this, e, r); +}; + +function GetNewBuffer(e) +{ + var r = Buffer.alloc(e); + return r.Read = BufRead.bind(r), r.Write = BufWrite.bind(r), r.len = 0, r; +}; + +function GetReadBuffer(e) +{ + var r = Buffer.from(e); + return r.Read = BufRead.bind(r), r.Write = BufWrite.bind(r), r.len = 0, r; +}; + +function GetObjectFromBuffer(e,r,t,n) +{ + var l = Buffer.from(e); + return l.len = 0, Read(l, r, void 0, t, n); +}; + +function GetBufferFromObject(e,r,t,n,l) +{ + var a = Buffer.alloc(t); + return a.len = 0, Write(a, e, r, void 0, n), l || (a = a.slice(0, a.len)), a; +}; + +function GetMiddleString(e) +{ + return e.substr(1, e.length - 2); +}; + +function GetMiddleString2(e,r,t) +{ + for(var n = 0, l = "", a = 0; a < e.length; a++) + { + var i = e.substr(a, 1); + if(" " !== i && "\n" !== i && (i !== r || 1 != ++n)) + { + if(i === t && 0 === --n) + break; + n && (l += i); + } + } + return l; +}; + +function GetAttributeStrings(e) +{ + for(var r = 0, t = [], n = "", l = 0; l < e.length; l++) + { + var a = e.substr(l, 1); + if("{" === a) + r++; + else + if("}" === a) + r--; + else + { + if("," === a && 0 === r) + { + 0 < n.length && t.push(n), n = ""; + continue; + } + if(" " === a || "\n" === a) + continue; + } + n += a; + } + return 0 < n.length && t.push(n), t; +}; + +function GetKeyValueStrings(e) +{ + for(var r = "", t = 0; t < e.length; t++) + { + var n = e.substr(t, 1); + if(" " !== n && "\n" !== n) + { + if(":" === n) + return {Key:r, Value:e.substr(t + 1)}; + r += n; + } + } + throw "Error format Key:Value = " + e; +}; + +function GetAttributes(e) +{ + for(var r = [], t = GetAttributeStrings(e), n = 0; n < t.length; n++) + { + var l = GetKeyValueStrings(t[n]); + r.push(l); + } + return r; +}; +module.exports.GetNewBuffer = GetNewBuffer, module.exports.GetReadBuffer = GetReadBuffer, module.exports.alloc = GetNewBuffer, +module.exports.from = GetReadBuffer, module.exports.Write = Write, module.exports.Read = Read, module.exports.GetObjectFromBuffer = GetObjectFromBuffer, +module.exports.GetBufferFromObject = GetBufferFromObject; diff --git a/src/core/code.ts b/src/core/code.ts new file mode 100644 index 0000000..f55b103 --- /dev/null +++ b/src/core/code.ts @@ -0,0 +1,204 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as fs from 'fs' +const FORMAT_EVAL_SEND = "{MaxBlockNum:uint,Code:str,Sign:arr64}"; +module.exports = class CCode extends require("./base") +{ + LastEvalCodeNum + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + if (!global.ADDRLIST_MODE && !this.VirtualMode) { + setInterval(this.CheckLoadCodeTime.bind(this), 10 * 1000) + } + this.LastEvalCodeNum = 0 + global.CheckCreateDir(global.GetDataPath("Update")) + } + CheckLoadCodeTime() { + if (global.START_LOAD_CODE.StartLoadNode && global.START_LOAD_CODE.StartLoadVersionNum) { + var Delta = (new Date() as any) - global.START_LOAD_CODE.StartLoadVersionNumTime; + if (Delta > 20 * 1000) { + global.ToError("Cannot load code version:" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + global.START_LOAD_CODE.StartLoadNode.ip + ":" + global.START_LOAD_CODE.StartLoadNode.port) + this.ClearLoadCode() + } + } + } + ClearLoadCode() { + global.START_LOAD_CODE.StartLoad = undefined + global.START_LOAD_CODE.StartLoadVersionNum = 0 + global.START_LOAD_CODE.StartLoadVersionNumTime = 0 + } + StartLoadCode(Node, CodeVersion) { + var VersionNum = CodeVersion.VersionNum; + global.START_LOAD_CODE.StartLoad = CodeVersion + global.START_LOAD_CODE.StartLoadNode = Node + global.START_LOAD_CODE.StartLoadVersionNum = VersionNum + global.START_LOAD_CODE.StartLoadVersionNumTime = new Date() + var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip"); + if (fs.existsSync(fname)) { + this.UseCode(VersionNum, false) + return; + } + var Context = { "VersionNum": VersionNum }; + this.SendF(Node, { "Method": "GETCODE", "Context": Context, "Data": VersionNum }) + } + static + GETCODE_F() { + return "uint"; + } + RETCODE(Info) { + var VersionNum = Info.Context.VersionNum; + if (!VersionNum || !global.START_LOAD_CODE.StartLoad) + return; + var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip"); + if (!fs.existsSync(fname)) { + var Hash = global.shaarr(Info.Data); + if (global.CompareArr(Hash, global.START_LOAD_CODE.StartLoad.Hash) === 0) { + var file_handle = fs.openSync(fname, "w"); + fs.writeSync(file_handle, Info.Data, 0, Info.Data.length) + fs.closeSync(file_handle) + this.UseCode(VersionNum, global.USE_AUTO_UPDATE) + } + else { + global.ToError("Error check hash of version code :" + global.START_LOAD_CODE.StartLoadVersionNum + " from node: " + Info.Node.ip + ":" + Info.Node.port) + this.ClearLoadCode() + this.AddCheckErrCount(Info.Node, 1, "Error check hash of version code") + } + } + } + UseCode(VersionNum, bUpdate) { + if (bUpdate) { + UpdateCodeFiles(VersionNum) + } + if (global.global.START_LOAD_CODE.StartLoad) { + global.CODE_VERSION = global.START_LOAD_CODE.StartLoad + this.ClearLoadCode() + } + } + SetNewCodeVersion(Data, PrivateKey) { + var fname = global.GetDataPath("ToUpdate/wallet.zip"); + if (fs.existsSync(fname)) { + var fname2 = global.GetDataPath("Update/wallet-" + Data.VersionNum + ".zip"); + if (fs.existsSync(fname2)) { + fs.unlinkSync(fname2) + } + var data = fs.readFileSync(fname); + var Hash = global.shaarr(data); + var file_handle = fs.openSync(fname2, "w"); + fs.writeSync(file_handle, data, 0, data.length) + fs.closeSync(file_handle) + var SignArr = arr2(Hash, GetArrFromValue(Data.VersionNum)); + var Sign = secp256k1.sign(SHA3BUF(SignArr), PrivateKey).signature; + global.CODE_VERSION = Data + global.CODE_VERSION.Hash = Hash + global.CODE_VERSION.Sign = Sign + return "OK Set new code version=" + Data.VersionNum; + } + else { + return "File not exist: " + fname; + } + } +}; + +function UpdateCodeFiles(StartNum) { + var fname = global.GetDataPath("Update"); + if (!fs.existsSync(fname)) + return 0; + var arr = fs.readdirSync(fname); + var arr2 = []; + for (var i = 0; i < arr.length; i++) { + if (arr[i].substr(0, 7) === "wallet-") { + arr2.push(parseInt(arr[i].substr(7))); + } + } + arr2.sort(function(a, b) { + return a - b; + }); + for (var i = 0; i < arr2.length; i++) { + var Num = arr2[i]; + var Name = "wallet-" + Num + ".zip"; + var Path = fname + "/" + Name; + global.ToLog("Check file:" + Name); + if (fs.existsSync(Path)) { + if (StartNum === Num) { + global.ToLog("UnpackCodeFile:" + Name); + UnpackCodeFile(Path); + if (StartNum % 2 === 0) { + global.RestartNode(1); + } + else { + } + return 1; + } + else { + global.ToLog("Delete old file update:" + Name); + fs.unlinkSync(Path); + } + } + } + return 0; +}; +global.UnpackCodeFile = UnpackCodeFile; + +function UnpackCodeFile(fname) { + var data = fs.readFileSync(fname); + var reader = ZIP.Reader(data); + reader.forEach(function(entry) { + var Name = entry.getName(); + var Path = GetCodePath(Name); + if (entry.isFile()) { + var buf = entry.getData(); + global.CheckCreateDir(Path, true, true); + var file_handle = fs.openSync(Path, "w"); + fs.writeSync(file_handle, buf, 0, buf.length); + fs.closeSync(file_handle); + } + else { + } + }); + reader.close(); +}; +global.RestartNode = function RestartNode(bForce) { + global.NeedRestart = 1; + setTimeout(DoExit, 5000); + if (global.nw || global.NWMODE) { + } else { + StopChildProcess(); + global.ToLog("********************************** FORCE RESTART!!!"); + return; + } + if (this.ActualNodes) { + var it = this.ActualNodes.iterator(), Node; + while ((Node = it.next()) !== null) { + if (Node.Socket) + CloseSocket(Node.Socket, "Restart"); + } + } + this.StopServer(); + this.StopNode(); + StopChildProcess(); + global.ToLog("****************************************** RESTART!!!"); + global.ToLog("EXIT 1"); +}; + +function DoExit() { + global.ToLog("EXIT 2"); + if (global.nw || global.NWMODE) { + global.ToLog("RESTART NW"); + var StrRun = '"' + process.argv[0] + '" .\n'; + StrRun += '"' + process.argv[0] + '" .\n'; + SaveToFile("run-next.bat", StrRun); + const child_process = require('child_process'); + child_process.exec("run-next.bat", { shell: true }); + } + global.ToLog("EXIT 3"); + process.exit(0); +}; diff --git a/src/core/connect.ts b/src/core/connect.ts new file mode 100644 index 0000000..da2ce31 --- /dev/null +++ b/src/core/connect.ts @@ -0,0 +1,1372 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as crypto from 'crypto'; +const CNode = require("./node"); +global.PERIOD_FOR_RECONNECT = 3600 * 1000; +global.CHECK_DELTA_TIME = { Num: 0, bUse: 0, StartBlockNum: 0, EndBlockNum: 0, bAddTime: 0, DeltaTime: 0, Sign: [] }; +global.CHECK_POINT = { BlockNum: 0, Hash: [], Sign: [] }; +global.CODE_VERSION = { + BlockNum: 0, addrArr: [], LevelUpdate: 0, BlockPeriod: 0, VersionNum: UPDATE_CODE_VERSION_NUM, Hash: [], Sign: [], + StartLoadVersionNum: 0 +}; +global.NET_CONSTANT = { + Num: 0, BlockNum: 0, MaxTrasactionLimit: MAX_TRANSACTION_LIMIT, Reserv1: 0, Reserv2: 0, Reserv3: 0, Reserv4: 0, + Reserv5: 0, Hash: [], Sign: [] +}; +global.START_LOAD_CODE = {}; +const MAX_PERIOD_GETNODES = 120 * 1000; +global.MIN_PERIOD_PING = 4 * 1000; +const MAX_PERIOD_PING = 120 * 1000; +global.MAX_PING_FOR_CONNECT = 400; +var MAX_TIME_CORRECT = 3 * 3600 * 1000; +global.MAX_WAIT_PERIOD_FOR_HOT = 4 * CONSENSUS_PERIOD_TIME; +const PERIOD_FOR_START_CHECK_TIME = 300; +module.exports = class CConnect extends require("./transfer-msg") +{ + StartTime + WasNodesSort + LevelNodes + NodesArr + NodesArrUnSort + NodesMap + NodesIPMap + PerioadAfterCanStart + КодДлÑÐ Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¥ÐµÐºÑ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.StartTime = Date.now() + this.WasNodesSort = false + this.LevelNodes = [] + this.NodesArr = [] + this.NodesArrUnSort = [] + this.NodesMap = {} + this.NodesIPMap = {} + this.WasNodesSort = true + this.PerioadAfterCanStart = 0 + this.КодДлÑÐ Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¥ÐµÐºÑ = global.GetHexFromArr(this.KeyPair.computeSecret(global.DEVELOP_PUB_KEY, null)) + this.DO_CONSTANT() + if (!global.ADDRLIST_MODE && !this.VirtualMode) { + setInterval(this.StartPingPong.bind(this), 1000) + setInterval(this.DeleteBadConnectingByTimer.bind(this), global.MAX_WAIT_PERIOD_FOR_STATUS / 2) + setInterval(this.StartCheckTransferTree.bind(this), 1000) + } + setInterval(this.NodesArrSort.bind(this), 30000) + } + DO_CONSTANT() { + this.CommonKey = global.GetHexFromArr(global.WALLET.HashProtect(global.COMMON_KEY)) + this.KeyToNode = global.shaarr(global.COMMON_KEY) + this.NameToNode = this.ValueToXOR("Name", global.NODES_NAME) + } + СтатДанныеОтладкиИзБлока() { + var МаÑÑив = []; + if (this.СтатБлок && this.СтатБлок.SeqHash) { + WriteArrToArr(МаÑÑив, this.ValueToXORDevelop("Stat:BlockNum", this.СтатБлок.BlockNum, "uint"), 6) + WriteArrToArr(МаÑÑив, this.ValueToXORDevelop("Stat:SeqHash", this.СтатБлок.SeqHash, "hash"), 32) + WriteArrToArr(МаÑÑив, this.ValueToXORDevelop("Stat:AddrHash", this.СтатБлок.AddrHash, "hash"), 32) + } + return МаÑÑив; + } + ДоÑтупенКлючРазработчика(Node) { + if (Node.PubKey && global.WALLET.WalletOpen !== false && IsDeveloperAccount(WALLET.PubKeyArr)) { + return 1; + } + return 0; + } + БлокИзДанных(Node, Arr) { + var Block = {}; + if (this.ДоÑтупенКлючРазработчика(Node) && !IsZeroArr(Arr)) { + var Data = global.BufLib.GetObjectFromBuffer(Arr, "{BlockNum:arr6,SeqHash:arr32,AddrHash:arr32}", {}); + Block.BlockNum = this.ValueFromXORDevelop(Node, "Stat:BlockNum", Data.BlockNum, "uint") + Block.SeqHash = this.ValueFromXORDevelop(Node, "Stat:SeqHash", Data.SeqHash, "hash") + Block.AddrHash = this.ValueFromXORDevelop(Node, "Stat:AddrHash", Data.AddrHash, "hash") + } + return Block; + } + StartConnectTry(Node) { + var Delta = Date.now() - Node.StartTimeConnect; + if (Delta >= Node.NextConnectDelta && this.IsCanConnect(Node)) { + if (!GetSocketStatus(Node.Socket)) { + Node.StartTimeConnect = Date.now() + if (Delta < 60 * 1000) + Node.NextConnectDelta = Node.NextConnectDelta * 2 + else + Node.NextConnectDelta = Math.trunc(Node.NextConnectDelta * 1.2) + Node.CreateConnect() + } + } + } + FindRunNodeContext(addrArr, ip, port, bUpdate) { + var Node, addrStr; + addrStr = GetHexFromAddres(addrArr) + Node = this.NodesMap[addrStr] + if (!Node) { + var key = "" + ip + ":" + port; + Node = this.NodesIPMap[key] + if (!Node) { + Node = this.GetNewNode(addrStr, ip, port) + } + } + if (Node.addrStr !== addrStr) { + delete this.NodesMap[Node.addrStr] + this.NodesMap[addrStr] = Node + Node.addrStrTemp = undefined + } + Node.addrArr = addrArr + Node.addrStr = addrStr + Node.ip = ip.trim() + Node.port = port + return Node; + } + CheckNodeMap(Node) { + if (Node.addrStrTemp && Node.addrStrTemp !== Node.addrStr) { + delete this.NodesMap[Node.addrStrTemp] + var Node2 = this.NodesMap[Node.addrStr]; + if (Node2 && Node2 !== Node) { + Node2.Delete = 1 + AddNodeInfo(Node2, "FIND DOUBLE!!") + delete this.NodesMap[Node.addrStr] + } + this.NodesMap[Node.addrStr] = Node + Node.addrStrTemp = undefined + } + } + StartHandshake(Node) { + return this.StartConnectTry(Node); + } + StartPingPong() { + if (glStopNode) + return; + if (global.CAN_START) + this.PerioadAfterCanStart++ + this.TimeDevCorrect() + var arr = global.SERVER.GetActualNodes(); + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + if (this.IsCanConnect(Node) && !Node.IsAddrList) { + if (Node.Hot) + Node.NextPing = MIN_PERIOD_PING + if (Node.NextPing < MIN_PERIOD_PING) + Node.NextPing = MIN_PERIOD_PING + var Delta = Date.now() - Node.PingStart; + if (Delta >= Node.NextPing) { + Node.PingStart = Date.now() + Node.NextPing = Node.NextPing * 1.5 + if (Node.NextPing > MAX_PERIOD_PING) + Node.NextPing = MAX_PERIOD_PING + if (!Node.PingNumber) + Node.PingNumber = 0 + Node.PingNumber++ + var Context = { "StartTime": GetCurrentTime(0), PingNumber: Node.PingNumber }; + this.SendF(Node, { "Method": "PING", "Context": Context, "Data": this.GetPingData(Node) }) + } + } + } + } + GetPingData(Node) { + var GrayAddres = 0; + if (GrayConnect()) + GrayAddres = 1 + var BlockNumHash = Math.trunc((GetCurrentBlockNumByTime() - global.BLOCK_PROCESSING_LENGTH2) / PERIOD_ACCOUNT_HASH) * PERIOD_ACCOUNT_HASH; + var AccountsHash = global.DApps.Accounts.GetHashOrUndefined(BlockNumHash); + var CheckPointHashDB = []; + if (CHECK_POINT.BlockNum && CHECK_POINT.BlockNum <= this.BlockNumDB) { + var Block = this.ReadBlockHeaderFromMapDB(CHECK_POINT.BlockNum); + if (Block) { + CheckPointHashDB = Block.Hash + } + } + var HashDB = []; + if (this.BlockNumDB > 0) { + var Block = this.ReadBlockHeaderFromMapDB(this.BlockNumDB); + if (Block) + HashDB = Block.Hash + } + var LevelCount = this.GetLevelEnum(Node); + var StopGetBlock = global.STOPGETBLOCK; + if (!StopGetBlock && this.BusyLevel) { + if (Node.BlockProcessCount <= this.BusyLevel) + StopGetBlock = 1 + } + var СтатДанные = []; + var DirectMAccount = 0; + var Ret = { + VERSIONMAX: DEF_VERSION, + FIRST_TIME_BLOCK: 0, + PingVersion: 3, + GrayConnect: GrayAddres, Reserve2: 0, AutoCorrectTime: AUTO_CORRECT_TIME, + LevelCount: LevelCount, Time: (GetCurrentTime() - 0), BlockNumDB: this.BlockNumDB, LoadHistoryMode: this.LoadHistoryMode, CanStart: global.CAN_START, + CheckPoint: CHECK_POINT, Reserv3: [], Key: this.KeyToNode, Name: this.NameToNode, TrafficFree: this.SendTrafficFree, AccountBlockNum: BlockNumHash, + AccountsHash: AccountsHash, MemoryUsage: Math.trunc(process.memoryUsage().heapTotal / 1024 / 1024), CheckDeltaTime: CHECK_DELTA_TIME, + CodeVersion: CODE_VERSION, IsAddrList: global.ADDRLIST_MODE, CheckPointHashDB: CheckPointHashDB, PortWeb: HTTP_HOSTING_PORT, HashDB: HashDB, + StopGetBlock: StopGetBlock, NetConstant: NET_CONSTANT, + }; + return Ret; + } + static + PING_F(bSend) { + return "{\ + VERSIONMAX:str15,\ + PingVersion:byte,\ + GrayConnect:byte,\ + Reserve2:byte,\ + AutoCorrectTime:byte,\ + LevelCount:uint16,\ + Time:uint,\ + BlockNumDB:uint,\ + LoadHistoryMode:byte,\ + CanStart:byte,\ + CheckPoint:{BlockNum:uint,Hash:hash,Sign:arr64},\ + Reserv3:arr38,\ + Key:arr32,\ + Name:arr32,\ + TrafficFree:uint,\ + AccountBlockNum:uint,\ + AccountsHash:hash,\ + MemoryUsage:uint,\ + CheckDeltaTime:{Num:uint,bUse:byte,StartBlockNum:uint,EndBlockNum:uint,bAddTime:byte,DeltaTime:uint,Sign:arr64},\ + CodeVersion:{BlockNum:uint,addrArr:arr32,LevelUpdate:byte,BlockPeriod:uint,VersionNum:uint,Hash:hash,Sign:arr64},\ + IsAddrList:byte,\ + CheckPointHashDB:hash,\ + PortWeb:uint16,\ + HashDB:hash,\ + StopGetBlock:uint,\ + NetConstant:{Num:uint,BlockNum:uint,MaxTrasactionLimit:uint,Reserv1:uint,Reserv2:uint,Reserv3:uint,Reserv4:uint,Reserv5:uint,Sign:arr64},\ + }"; + } + static + PONG_F(bSend) { + return CConnect.PING_F(bSend); + } + PING(Info, CurTime) { + this.DoPingData(Info, 1) + this.SendF(Info.Node, { "Method": "PONG", "Context": Info.Context, "Data": this.GetPingData(Info.Node) }) + } + DoPingData(Info, bCheckPoint) { + var Node = Info.Node; + var Data = this.DataFromF(Info); + Info.Node.VERSIONMAX = Data.VERSIONMAX + if (Data.PingVersion >= 3 && global.COMMON_KEY && global.CompareArr(Data.Key, this.KeyToNode) === 0) { + Node.Name = this.ValueFromXOR(Node, "Name", Data.Name) + if (Node.BlockProcessCount < 5000000 + global.TRUST_PROCESS_COUNT) + Node.BlockProcessCount = 5000000 + global.TRUST_PROCESS_COUNT + } + else { + Node.Name = "" + } + Node.INFO = Data + Node.INFO.WasPing = 1 + Node.LevelCount = Data.LevelCount + Node.LoadHistoryMode = Data.LoadHistoryMode + Node.LastTime = global.GetCurrentTime() - 0 + Node.NextConnectDelta = 1000 + Node.StopGetBlock = Data.StopGetBlock + Node.portweb = Data.PortWeb + if (bCheckPoint) { + this.CheckCheckPoint(Data, Info.Node) + this.CheckCodeVersion(Data, Info.Node) + this.CheckDeltaTime(Data, Info.Node) + } + } + PONG(Info, CurTime) { + var Data = this.DataFromF(Info); + var Node = Info.Node; + if (!Info.Context) + return; + if (!Info.Context.StartTime) + return; + if (Info.Context.PingNumber !== Node.PingNumber) + return; + this.DoPingData(Info, 0) + var DeltaTime = GetCurrentTime(0) - Info.Context.StartTime; + Node.DeltaTimeM = DeltaTime + Node.SumDeltaTime += DeltaTime + Node.CountDeltaTime++ + Node.DeltaTime = Math.trunc(Node.SumDeltaTime / Node.CountDeltaTime) + if (!Node.DeltaTime) + Node.DeltaTime = 1000 + if (DeltaTime) { + Node.DeltaGlobTime = global.GetCurrentTime() - (Data.Time + DeltaTime / 2) + } + this.CheckCheckPoint(Data, Info.Node) + if (!global.START_LOAD_CODE.StartLoadVersionNum) + global.START_LOAD_CODE.StartLoadVersionNum = 0 + this.CheckNetConstant(Data, Info.Node) + this.CheckCodeVersion(Data, Info.Node) + if (!global.CAN_START) { + if (DeltaTime > MAX_PING_FOR_CONNECT) + global.ToLog("DeltaTime=" + DeltaTime + ">" + MAX_PING_FOR_CONNECT + " ms - " + NodeInfo(Node), 2) + } + var Times; + if (DeltaTime <= MAX_PING_FOR_CONNECT) { + Times = Node.Times + if (!Times || Times.Count >= 10) { + Times = { SumDelta: 0, Count: 0, AvgDelta: 0, Arr: [] } + Node.Times = Times + } + var Time1 = Data.Time; + var Time2 = global.GetCurrentTime(); + var Delta2 = - (Time2 - Time1 - DeltaTime / 2); + Times.Arr.push(Delta2) + Times.SumDelta += Delta2 + Times.Count++ + Times.AvgDelta = Times.SumDelta / Times.Count + if (Times.Count >= 2) { + Times.Arr.sort(function(a, b) { + return Math.abs(a) - Math.abs(b); + }) + Node.AvgDelta = Times.Arr[0] + } + if (global.AUTO_CORRECT_TIME) { + this.CorrectTime() + } + } + else { + } + global.ADD_TO_STAT("MAX:PING_TIME", DeltaTime) + if (!global.CAN_START) + if (Times && Times.Count >= 1 && Times.AvgDelta <= 200) { + global.ToLog("****************************************** CAN_START") + global.CAN_START = true + } + this.CheckDeltaTime(Data, Info.Node) + } + CheckCheckPoint(Data, Node) { + if (CREATE_ON_START) + return; + if (Data.CheckPoint.BlockNum && Data.CheckPoint.BlockNum > CHECK_POINT.BlockNum) { + var SignArr = arr2(Data.CheckPoint.Hash, GetArrFromValue(Data.CheckPoint.BlockNum)); + if (CheckDevelopSign(SignArr, Data.CheckPoint.Sign)) { + global.CHECK_POINT = Data.CheckPoint + this.ResetNextPingAllNode() + if (Data.CheckPoint.BlockNum < this.BlockNumDBMin) + return; + var Block = this.ReadBlockHeaderDB(CHECK_POINT.BlockNum); + if (Block && global.CompareArr(Block.Hash, CHECK_POINT.Hash) !== 0) { + this.BlockNumDB = CHECK_POINT.BlockNum - 1 + this.TruncateBlockDB(this.BlockNumDB) + this.StartSyncBlockchain(Node, 0, 1) + } + } + else { + Node.NextConnectDelta = 60 * 1000 + global.ToLog("Error Sign CheckPoint=" + Data.CheckPoint.BlockNum + " from " + NodeInfo(Node)) + this.AddCheckErrCount(Node, 10, "Error Sign CheckPoint") + } + } + } + CheckDeltaTime(Data, Node) { + if (global.AUTO_CORRECT_TIME) + if (global.CAN_START && !CREATE_ON_START) { + if (Data.CheckDeltaTime.Num > CHECK_DELTA_TIME.Num) { + var SignArr = this.GetSignCheckDeltaTime(Data.CheckDeltaTime); + if (CheckDevelopSign(SignArr, Data.CheckDeltaTime.Sign)) { + global.CHECK_DELTA_TIME = Data.CheckDeltaTime + } + else { + Node.NextConnectDelta = 60 * 1000 + global.ToLog("Error Sign CheckDeltaTime Num=" + Data.CheckDeltaTime.Num + " from " + NodeInfo(Node)) + this.AddCheckErrCount(Node, 10, "Error Sign CheckDeltaTime") + } + } + } + } + CheckNetConstant(Data, Node) { + if (Data.NetConstant.Num > NET_CONSTANT.Num) { + var SignArr = this.GetSignCheckNetConstant(Data.NetConstant); + if (CheckDevelopSign(SignArr, Data.NetConstant.Sign)) { + global.NET_CONSTANT = Data.NetConstant + var CurBlockNum = GetCurrentBlockNumByTime(); + var Delta = Data.NetConstant.BlockNum - CurBlockNum; + if (Delta < 1) + Delta = 1 + this.ResetNextPingAllNode() + global.ToLog("Get new NetConstant (wait " + Delta + " s) Num=" + Data.NetConstant.Num) + if (this.idTimerSetConst) + clearTimeout(this.idTimerSetConst) + let SELF = this; + this.idTimerSetConst = setTimeout(function() { + SELF.DoNetConst() + this.idTimerSetConst = 0 + }, Delta * 1000) + } + else { + Node.NextConnectDelta = 60 * 1000 + global.ToLog("Error Sign CheckNetConstant Num=" + Data.NetConstant.Num + " from " + NodeInfo(Node)) + this.AddCheckErrCount(Node, 10, "Error Sign CheckNetConstant") + } + } + } + DoNetConst() { + global.MAX_TRANSACTION_LIMIT = NET_CONSTANT.MaxTrasactionLimit + } + CheckCodeVersion(Data, Node) { + var CodeVersion = Data.CodeVersion; + Node.VersionNum = CodeVersion.VersionNum + if (CodeVersion.VersionNum >= MIN_CODE_VERSION_NUM) { + Node.VersionOK = true + } + else { + Node.VersionOK = false + } + if (Node.VersionOK) { + Node.CanHot = true + if (CHECK_POINT.BlockNum && Data.CheckPoint.BlockNum) + if (CHECK_POINT.BlockNum !== Data.CheckPoint.BlockNum || global.CompareArr(CHECK_POINT.Hash, Data.CheckPoint.Hash) !== 0) { + Node.CanHot = false + Node.NextConnectDelta = 60 * 1000 + } + } + else { + Node.CanHot = false + if (!Node.VersionOK) { + Node.NextConnectDelta = 60 * 1000 + } + } + var bLoadVer = 0; + if (CodeVersion.BlockNum && (CodeVersion.BlockNum <= GetCurrentBlockNumByTime() || CodeVersion.BlockPeriod === 0) && CodeVersion.BlockNum > CODE_VERSION.BlockNum && !IsZeroArr(CodeVersion.Hash) && (CodeVersion.VersionNum > CODE_VERSION.VersionNum && CodeVersion.VersionNum > global.START_LOAD_CODE.StartLoadVersionNum || CodeVersion.VersionNum === CODE_VERSION.VersionNum && IsZeroArr(CODE_VERSION.Hash))) { + bLoadVer = 1 + } + if (bLoadVer) { + var Level = AddrLevelArrFromBegin(this.addrArr, CodeVersion.addrArr); + if (CodeVersion.BlockPeriod) { + var Delta = GetCurrentBlockNumByTime() - CodeVersion.BlockNum; + Level += Delta / CodeVersion.BlockPeriod + } + if (Level >= CodeVersion.LevelUpdate) { + var SignArr = arr2(CodeVersion.Hash, GetArrFromValue(CodeVersion.VersionNum)); + if (CheckDevelopSign(SignArr, CodeVersion.Sign)) { + global.ToLog("Get new CodeVersion = " + CodeVersion.VersionNum + " HASH:" + global.GetHexFromArr(CodeVersion.Hash).substr(0, 20)) + if (CodeVersion.VersionNum > CODE_VERSION.VersionNum && CodeVersion.VersionNum > global.START_LOAD_CODE.StartLoadVersionNum) { + this.StartLoadCode(Node, CodeVersion) + } + else { + CODE_VERSION = CodeVersion + } + } + else { + global.ToLog("Error Sign CodeVersion=" + CodeVersion.VersionNum + " from " + NodeInfo(Node) + " HASH:" + global.GetHexFromArr(CodeVersion.Hash).substr(0, + 20)) + global.ToLog(JSON.stringify(CodeVersion)) + this.AddCheckErrCount(Node, 10, "Error Sign CodeVersion") + Node.NextConnectDelta = 60 * 1000 + } + } + } + } + GetSignCheckNetConstant(Data) { + var Buf = global.BufLib.GetBufferFromObject(Data, "{Num:uint,BlockNum:uint,MaxTrasactionLimit:uint,Reserv1:uint,Reserv2:uint,Reserv3:uint,Reserv4:uint,Reserv5:uint}", + 1000, {}); + return global.shaarr(Buf); + } + GetSignCheckDeltaTime(Data) { + var Buf = global.BufLib.GetBufferFromObject(Data, "{Num:uint,bUse:byte,StartBlockNum:uint,EndBlockNum:uint,bAddTime:byte,DeltaTime:uint}", + 1000, {}); + return global.shaarr(Buf); + } + ResetNextPingAllNode() { + var arr = global.SERVER.GetActualNodes(); + for (var i = 0; i < arr.length; i++) { + var Node2 = arr[i]; + if (Node2 && Node2.NextPing > 5 * 1000) + Node2.NextPing = 5 * 1000 + } + } + StartDisconnectHot(Node, StrError, bDeleteHot) { + AddNodeInfo(Node, "DisconnectHot:" + StrError) + if (Node.Active && Node.Hot) { + AddNodeInfo(Node, "SEND DISCONNECTHOT") + this.Send(Node, { "Method": "DISCONNECTHOT", "Context": {}, "Data": StrError }, STR_TYPE) + } + this.DeleteNodeFromHot(Node) + } + DISCONNECTHOT(Info, CurTime) { + this.DeleteNodeFromHot(Info.Node) + global.ADD_TO_STAT("DISCONNECTHOT") + AddNodeInfo(Info.Node, "GET DISCONNECTHOT:" + Info.Data) + } + StartGetNodes(Node) { + if (glStopNode) + return; + var Delta = Date.now() - Node.StartTimeGetNodes; + if (Delta >= Node.NextGetNodesDelta) { + Node.StartTimeGetNodes = Date.now() + Node.NextGetNodesDelta = Math.min(Node.NextGetNodesDelta * 2, MAX_PERIOD_GETNODES) + if (global.ADDRLIST_MODE) + Node.NextGetNodesDelta = MAX_PERIOD_GETNODES + this.Send(Node, { "Method": "GETNODES", "Context": {}, "Data": undefined }) + } + } + GETNODES(Info, CurTime) { + this.SendF(Info.Node, { + "Method": "RETGETNODES", "Context": Info.Context, "Data": { + arr: this.GetDirectNodesArray(false, 0, 1), IsAddrList: global.ADDRLIST_MODE, + } + }, MAX_NODES_RETURN * 250 + 300) + } + static + RETGETNODES_F() { + return "{arr:[\ + {\ + addrArr:arr32,\ + ip:str20,\ + port:uint16,\ + portweb:uint16,\ + LastTime:uint,\ + DeltaTime:uint,\ + Reserv:arr8\ + }\ + ],\ + IsAddrList:byte}"; + } + RETGETNODES(Info, CurTime) { + var Data = this.DataFromF(Info); + var arr = Data.arr; + if (arr && arr.length > 0) { + for (var i = 0; i < arr.length; i++) { + arr[i].addrStr = global.GetHexFromArr(arr[i].addrArr) + var Item = this.AddToArrNodes(arr[i], true); + if (Item) + Item.LastTimeGetNode = CurTime - 0 + } + } + Info.Node.IsAddrList = Data.IsAddrList + AddNodeInfo(Info.Node, "RETGETNODES length=" + arr.length) + } + static + RETGETNODES2_F() { + return "{arr:[\ + {\ + addrStr:str64,\ + ip:str30,\ + port:uint16,\ + portweb:uint16,\ + LastTime:uint,\ + DeltaTime:uint,\ + StatData:arr70\ + }\ + ],\ + IsAddrList:byte}"; + } + RETGETNODES2(Info, CurTime) { + var Data = this.DataFromF(Info); + var arr = Data.arr; + if (arr && arr.length > 0) { + for (var i = 0; i < arr.length; i++) { + var Item = this.AddToArrNodes(arr[i], true); + if (Item) + Item.LastTimeGetNode = CurTime - 0 + } + } + Info.Node.IsAddrList = Data.IsAddrList + AddNodeInfo(Info.Node, "RETGETNODES2 length=" + arr.length) + } + GetNewNode(addrStr, ip, port) { + var Node = new CNode(addrStr, ip, port); + this.AddToArrNodes(Node, false) + return Node; + } + IsCanConnect(Node) { + if (Node.addrStr === this.addrStr || this.NodeInBan(Node) || Node.Delete || Node.Self || Node.DoubleConnection) + return false; + if (Node.ip === this.ip && Node.port === this.port) + return false; + if (this.addrStr === Node.addrStr) + return false; + return true; + } + GetDirectNodesArray(bAll, bWebPort, bGetAddrArr) { + var ret = []; + var Value = { + addrStr: this.addrStr, ip: this.ip, port: this.port, LastTime: 0, DeltaTime: 0, Hot: true, BlockProcessCount: 0, portweb: HTTP_HOSTING_PORT, + }; + if (bGetAddrArr) + Value.addrArr = global.GetArrFromHex(Value.addrStr) + ret.push(Value) + var len = this.NodesArr.length; + var UseRandom = 0; + var MaxDeltaTime = 24 * 3600 * 1000; + if (len > MAX_NODES_RETURN && !bAll) { + UseRandom = 1 + MaxDeltaTime = NODES_DELTA_CALC_HOUR * 3600 * 1000 + len = MAX_NODES_RETURN + } + var mapWasAdd = {}; + var CurTime = global.GetCurrentTime(); + for (var i = 0; i < len; i++) { + var Item; + if (UseRandom) { + Item = this.NodesArr[random(this.NodesArr.length)] + if (mapWasAdd[Item.addrStr]) { + continue; + } + mapWasAdd[Item.addrStr] = 1 + } + else { + Item = this.NodesArr[i] + } + if (bWebPort && !Item.portweb) + continue; + if (!this.IsCanConnect(Item)) + continue; + if (Item.GrayConnect) + continue; + if (Item.BlockProcessCount < 0) + continue; + if (!GrayConnect() && Item.LastTime - 0 < CurTime - MaxDeltaTime) + continue; + var Value = { + addrStr: Item.addrStr, ip: Item.ip, port: Item.port, FirstTime: Item.FirstTime, FirstTimeStr: Item.FirstTimeStr, LastTime: Item.LastTime - 0, + DeltaTime: Item.DeltaTime, Hot: Item.Hot, BlockProcessCount: Item.BlockProcessCount, Name: Item.Name, portweb: Item.portweb, + }; + if (bGetAddrArr) + Value.addrArr = global.GetArrFromHex(Value.addrStr) + ret.push(Value) + } + return ret; + } + AddToArrNodes(Item) { + if (Item.addrStr === "" || Item.addrStr === this.addrStr) + return; + var Node; + var key = Item.ip + ":" + Item.port; + Node = this.NodesMap[Item.addrStr] + if (!Node) { + Node = this.NodesIPMap[key] + } + if (!Node) { + if (Item instanceof CNode) + Node = Item + else + Node = new CNode(Item.addrStr, Item.ip, Item.port) + Node.id = this.NodesArr.length + Node.addrArr = GetAddresFromHex(Node.addrStr) + this.NodesMap[Node.addrStr] = Node + this.NodesArr.push(Node) + this.NodesArrUnSort.push(Node) + global.ADD_TO_STAT("AddToNodes") + } + this.NodesMap[Node.addrStr] = Node + this.NodesIPMap[key] = Node + if (Node.addrArr && global.CompareArr(Node.addrArr, this.addrArr) === 0) { + Node.Self = true + } + if (Item.BlockProcessCount) + Node.BlockProcessCount = Item.BlockProcessCount + if (Item.FirstTime) { + Node.FirstTime = Item.FirstTime + Node.FirstTimeStr = Item.FirstTimeStr + } + if (Item.Name) + Node.Name = Item.Name + if (Item.portweb) + Node.portweb = Item.portweb + return Node; + } + NodesArrSort() { + this.NodesArr.sort(SortNodeBlockProcessCount) + if ((GrayConnect() || !this.LoadHistoryMode) && Date.now() - this.StartTime > 120 * 1000) { + var arr0 = this.GetDirectNodesArray(true); + var arr = arr0.slice(1, 2000); + SaveParams(global.GetDataPath("nodes.lst"), arr) + } + } + LoadNodesFromFile() { + var arr = LoadParams(global.GetDataPath("nodes.lst"), []); + arr.sort(SortNodeBlockProcessCount) + for (var i = 0; i < arr.length; i++) { + if (arr[i].LastTime) { + if (typeof arr[i].LastTime === "string") + arr[i].LastTime = 0 + } + this.AddToArrNodes(arr[i], true) + } + } + GetLevelEnum(Node) { + var Level = this.AddrLevelNode(Node); + var arr0 = this.LevelNodes[Level]; + if (!arr0) { + Node.LevelEnum = 1 + return 1; + } + var arr = [].concat(arr0); + var bWas = 0; + for (var n = 0; n < arr.length; n++) { + if (arr[n] === Node) { + bWas = 1 + break; + } + } + if (!bWas) + arr.push(Node) + arr.sort(SortNodeBlockProcessCount) + for (var n = 0; n < arr.length; n++) { + if (arr[n] === Node) { + Node.LevelEnum = 1 + n + break; + } + } + return Node.LevelEnum; + } + StartAddLevelConnect(Node) { + if (!global.CAN_START) + return; + global.ADD_TO_STAT("NETCONFIGURATION") + if (Node.Active && Node.CanHot) + this.SendF(Node, { "Method": "ADDLEVELCONNECT", "Context": {}, "Data": this.GetLevelEnum(Node) }) + } + static + ADDLEVELCONNECT_F() { + return "uint"; + } + ADDLEVELCONNECT(Info, CurTime) { + Info.Node.LevelCount = this.DataFromF(Info) + var ret; + var Count; + if (!global.CAN_START) + return; + if (Info.Node.GrayConnect || GrayConnect()) + return; + var Count = this.GetLevelEnum(Info.Node); + var bAdd = this.AddLevelConnect(Info.Node); + if (bAdd) { + ret = { result: 1, Count: Count } + } + else { + ret = { result: 0, Count: Count } + } + AddNodeInfo(Info.Node, "GET ADDLEVELCONNECT, DO bAdd=" + bAdd) + this.SendF(Info.Node, { "Method": "RETADDLEVELCONNECT", "Context": Info.Context, "Data": ret }) + } + AddLevelConnect(Node) { + if (!global.CAN_START) + return false; + var Level = this.AddrLevelNode(Node); + Node.Hot = true + var arr = this.LevelNodes[Level]; + if (!arr) { + arr = [] + this.LevelNodes[Level] = arr + } + var bWas = 0; + for (var i = 0; i < arr.length; i++) + if (arr[i] === Node) { + bWas = 1 + } + if (!bWas) + arr.push(Node) + Node.TransferCount = 0 + if (this.LoadHistoryMode) + Node.LastTimeTransfer = (GetCurrentTime() - 0) + 30 * 1000 + else + Node.LastTimeTransfer = (GetCurrentTime() - 0) + 10 * 1000 + Node.CanHot = true + this.CheckDisconnectHot(Level) + if (!Node.CanHot) + return false; + this.SendGetMessage(Node) + global.ADD_TO_STAT("NETCONFIGURATION") + global.ADD_TO_STAT("AddLevelConnect") + AddNodeInfo(Node, "Add Level connect") + return true; + } + static + RETADDLEVELCONNECT_F() { + return "{result:byte,Count:uint}"; + } + RETADDLEVELCONNECT(Info, CurTime) { + var Data = this.DataFromF(Info); + AddNodeInfo(Info.Node, "GET RETADDLEVELCONNECT: " + Data.result) + if (Data.result === 1) { + this.AddLevelConnect(Info.Node) + } + else { + this.AddCheckErrCount(Info.Node, 1) + } + Info.Node.LevelCount = Data.Count + } + DeleteBadConnectingByTimer() { + if (glStopNode) + return; + var CurTime = global.GetCurrentTime(); + var arr = global.SERVER.NodesArr; + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + var Status = GetSocketStatus(Node.Socket); + if (Node.Active && Status < 100) { + var Delta = CurTime - Node.LastTime; + if (Delta > MAX_WAIT_PERIOD_FOR_STATUS) { + AddNodeInfo(Node, "Close bad connecting by time") + this.DeleteNodeFromActive(Node) + } + } + } + } + CheckDisconnectHot(Level) { + var CurTime = global.GetCurrentTime() - 0; + var MaxCountChilds; + if (Level < 3) + MaxCountChilds = 4 + else + MaxCountChilds = MAX_CONNECT_CHILD + var arr = this.LevelNodes[Level]; + if (arr) { + for (var n = arr.length - 1; n >= 0; n--) { + var Node = arr[n]; + if (Node) { + var DeltaTime = CurTime - Node.LastTimeTransfer; + if (!Node.Hot || DeltaTime > MAX_WAIT_PERIOD_FOR_HOT) { + this.StartDisconnectHot(Node, "TimeDisconnectHot") + } + } + } + arr.sort(SortNodeBlockProcessCount) + var ChildCount = arr.length; + for (var n = arr.length - 1; n >= MIN_CONNECT_CHILD; n--) { + var Node = arr[n]; + if (Node) { + if (ChildCount > MaxCountChilds) { + ChildCount-- + Node.CanHot = false + this.StartDisconnectHot(Node, "MAX_CONNECT_CHILD") + global.ADD_TO_STAT("DisconnectChild") + continue; + } + if (ChildCount > (MIN_CONNECT_CHILD) && Node.LevelCount > MIN_CONNECT_CHILD) { + ChildCount-- + Node.CanHot = false + this.AddCheckErrCount(Node, 1) + this.StartDisconnectHot(Node, "MIN_CONNECT_CHILD:" + Node.LevelCount + " LevelEnum:" + (n + 1)) + global.ADD_TO_STAT("DisconnectChild") + continue; + } + } + } + } + } + SetTime(NewTime) { + global.ToLog("Set new time: " + NewTime) + if (NewTime) { + global.DELTA_CURRENT_TIME = NewTime - (GetCurrentTime(0) - 0) + SAVE_CONST(true) + } + } + static + TIME_F() { + return "{Time:uint, Sign:arr64}"; + } + SendTimeDev(Node) { + if (!WALLET.WalletOpen) { + global.ToLog("Error Wallet not open") + return 0; + } + if (!this.SignCurrentTimeDev) { + var SignArr = global.GetArrFromHex(SERVER.addrStr); + this.SignCurrentTimeDev = secp256k1.sign(SHA3BUF(SignArr), global.WALLET.KeyPair.getPrivateKey('')).signature + } + var Time = global.GetCurrentTime() - 0; + global.ToLog("Send time: " + Time + " to " + NodeInfo(Node)) + this.SendF(Node, { "Method": "TIME", "Data": { Time: Time, Sign: this.SignCurrentTimeDev } }) + return 1; + } + SendTimeToAll() { + var Count = 0; + for (var i = 0; i < this.NodesArr.length; i++) { + var Node = this.NodesArr[i]; + if (Node.Active) { + if (this.SendTimeDev(Node)) + Count++ + } + } + return Count; + } + TIME(Info, CurTime) { + if (global.AUTO_CORRECT_TIME) { + var Node = Info.Node; + var Data = this.DataFromF(Info); + var SignArr = global.GetArrFromHex(Node.addrStr); + if (CheckDevelopSign(SignArr, Data.Sign)) { + this.SetTime(Data.Time) + } + else { + Node.NextConnectDelta = 60 * 1000 + global.ToLog("Error Sign TIME from " + NodeInfo(Node)) + this.AddCheckErrCount(Node, 10, "Error Sign TIME") + } + } + } + ConnectToAll() { + var Count = 0; + for (var i = 0; i < this.NodesArr.length; i++) { + var Node = this.NodesArr[i]; + if (!Node.Active && this.IsCanConnect(Node) && !Node.WasAddToConnect) { + AddNodeInfo(Node, "To connect all") + Node.NextConnectDelta = 1000 + Node.WasAddToConnect = 1 + ArrConnect.push(Node) + Count++ + } + } + return Count; + } + DisconnectAll() { + var Count = 0; + for (var i = 0; i < this.NodesArr.length; i++) { + var Node = this.NodesArr[i]; + if (Node.Active) { + AddNodeInfo(Node, "Disconnect hot all") + Node.NextConnectDelta = 10000 + this.DeleteNodeFromActive(Node) + Count++ + } + } + return Count; + } + GetHotTimeNodes() { + if (this.LoadHistoryMode || !global.CAN_START) + return this.GetActualNodes(); + else + return this.GetHotNodes(); + } + CorrectTime() { + var MaxCorrect = MAX_TIME_CORRECT; + var PerioadAfterCanStart = this.PerioadAfterCanStart; + var ArrNodes = this.GetHotTimeNodes(); + var CountNodes = ArrNodes.length; + var DeltaArr = []; + var NodesSet = new Set(); + for (var i = 0; i < ArrNodes.length; i++) { + var Node = ArrNodes[i]; + if (!Node.Times) + continue; + if (Node.Times.Count < 2) + continue; + if (PerioadAfterCanStart >= PERIOD_FOR_START_CHECK_TIME) + if (Node.Times.Count < 5) + continue; + NodesSet.add(Node) + } + for (var Node of NodesSet) { + DeltaArr.push(Node.Times.AvgDelta) + } + if (DeltaArr.length < 1) + return; + if (this.LoadHistoryMode && CountNodes > 10) { + PerioadAfterCanStart = 0 + CountNodes = 10 + } + if (DeltaArr.length < CountNodes / 2) + return; + if (PerioadAfterCanStart >= PERIOD_FOR_START_CHECK_TIME) { + if (DeltaArr.length < 3 * CountNodes / 4) + return; + } + DeltaArr.sort(function(a, b) { + return a - b; + }) + var start, finish; + if (Math.floor(DeltaArr.length / 2) === DeltaArr.length / 2) { + start = DeltaArr.length / 2 - 1 + finish = start + 1 + } + else { + start = Math.floor(DeltaArr.length / 2) + finish = start + } + var Sum = 0; + var Count = 0; + for (var i = start; i <= finish; i++) { + Sum = Sum + DeltaArr[i] + Count++ + } + var AvgDelta = Sum / Count; + if (PerioadAfterCanStart < PERIOD_FOR_START_CHECK_TIME) { + var KT = (PERIOD_FOR_START_CHECK_TIME - PerioadAfterCanStart) / PERIOD_FOR_START_CHECK_TIME; + AvgDelta = AvgDelta * KT + } + else { + MaxCorrect = 25 + } + if (AvgDelta < (- MaxCorrect)) + AvgDelta = - MaxCorrect + else + if (AvgDelta > MaxCorrect) + AvgDelta = MaxCorrect + AvgDelta = Math.trunc(AvgDelta) + if (Math.abs(AvgDelta) < 15) { + return; + } + if (AvgDelta > 0) + global.ADD_TO_STAT("CORRECT_TIME_UP", AvgDelta) + else + global.ADD_TO_STAT("CORRECT_TIME_DOWN", - AvgDelta) + global.DELTA_CURRENT_TIME = Math.trunc(global.DELTA_CURRENT_TIME + AvgDelta) + this.ClearTimeStat() + SAVE_CONST() + } + ClearTimeStat() { + var ArrNodes = this.GetHotTimeNodes(); + for (var Node of ArrNodes) { + Node.Times = undefined + } + } + TimeDevCorrect() { + if (CHECK_DELTA_TIME.bUse) { + var BlockNum = GetCurrentBlockNumByTime(); + if (CHECK_DELTA_TIME.StartBlockNum <= BlockNum && CHECK_DELTA_TIME.EndBlockNum > BlockNum) { + if (!global.DELTA_CURRENT_TIME) + global.DELTA_CURRENT_TIME = 0 + var CorrectTime = 0; + if (CHECK_DELTA_TIME.bAddTime) + CorrectTime = CHECK_DELTA_TIME.DeltaTime + else + CorrectTime = - CHECK_DELTA_TIME.DeltaTime + global.DELTA_CURRENT_TIME += CorrectTime + this.ClearTimeStat() + SAVE_CONST(true) + } + } + } + SetNodePrioritet(Node, Prioritet) { + if (Node.Prioritet === Prioritet) + return; + if (Node.addrArr) { + var Item = this.ActualNodes.find(Node); + if (Item) { + this.ActualNodes.remove(Node) + Node.Prioritet = Prioritet + this.ActualNodes.insert(Node) + } + } + Node.Prioritet = Prioritet + } + AddNodeToActive(Node) { + if (Node.addrArr) { + if (global.CompareArr(Node.addrArr, this.addrArr) === 0) { + return; + } + this.CheckNodeMap(Node) + this.ActualNodes.insert(Node) + } + Node.ResetNode() + Node.Active = true + Node.NextConnectDelta = 1000 + if (!Node.FirstTime) { + Node.FirstTime = global.GetCurrentTime() - 0 + Node.FirstTimeStr = "" + GetStrTimeUTC() + } + global.ADD_TO_STAT("AddToActive") + } + DeleteNodeFromActive(Node) { + Node.Active = false + if (Node.Hot) + this.StartDisconnectHot(Node, "NotActive", 1) + Node.Hot = false + this.ActualNodes.remove(Node) + CloseSocket(Node.Socket, "DeleteNodeFromActive") + CloseSocket(Node.Socket2, "DeleteNodeFromActive") + Node.ResetNode() + Node.Socket = undefined + Node.Socket2 = undefined + } + StartReconnect() { + return; + var arr = this.GetActualNodes(); + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + if (Node.Socket && Node.Socket.ConnectToServer) { + if (!Node.SocketStart) + Node.SocketStart = Date.now() + var DeltaTime = Date.now() - Node.SocketStart; + if (DeltaTime >= PERIOD_FOR_RECONNECT) { + if (random(100) >= 90) + Node.CreateReconnection() + } + } + } + } + IsLocalIP(addr) { + if (addr.substr(0, 7) === "192.168" || addr.substr(0, 3) === "10.") + return 1; + else + return 0; + } + GetActualsServerIP(bFlag) { + var arr = this.GetActualNodes(); + var Str = ""; + arr.sort(function(a, b) { + if (a.ip > b.ip) + return - 1; + else + if (a.ip < b.ip) + return 1; + else + return 0; + }) + if (bFlag) + return arr; + for (var i = 0; i < arr.length; i++) { + Str += arr[i].ip + ", " + } + return Str.substr(0, Str.length - 2); + } + AddrLevelNode(Node) { + if (Node.GrayConnect) + return MAX_LEVEL_SPECIALIZATION - 1; + return AddrLevelArr(this.addrArr, Node.addrArr); + } + GetNodesLevelCount() { + var Count = 0; + for (var i = 0; i < this.LevelNodes.length; i++) { + var arr = this.LevelNodes[i]; + for (var n = 0; arr && n < arr.length; n++) + if (arr[n].Hot) { + Count++ + break; + } + } + return Count; + } + GetHotNodes() { + var ArrNodes = []; + for (var L = 0; L < this.LevelNodes.length; L++) { + var arr = this.LevelNodes[L]; + for (let j = 0; arr && j < arr.length; j++) { + ArrNodes.push(arr[j]) + } + } + return ArrNodes; + } + DeleteNodeFromHot(Node) { + if (Node.Hot) { + Node.Hot = false + } + Node.CanHot = false + for (var i = 0; i < this.LevelNodes.length; i++) { + var arr = this.LevelNodes[i]; + for (var n = 0; arr && n < arr.length; n++) + if (arr[n] === Node) { + arr.splice(n, 1) + global.ADD_TO_STAT("DeleteLevelConnect") + global.ADD_TO_STAT("NETCONFIGURATION") + break; + } + } + } + DeleteAllNodesFromHot(Str) { + for (var i = 0; i < this.LevelNodes.length; i++) { + var arr = this.LevelNodes[i]; + for (var n = 0; arr && n < arr.length; n++) { + var Node = arr[n]; + if (Node.Hot) { + global.ADD_TO_STAT("DeleteAllNodesFromHot") + this.StartDisconnectHot(Node, Str, 1) + } + } + } + } + GetTransferTree() { + var HotArr = []; + for (var Level = 0; Level < this.LevelNodes.length; Level++) { + var arr = this.LevelNodes[Level]; + HotArr[Level] = [] + for (var n = 0; arr && n < arr.length; n++) { + var Node = arr[n]; + if (Node) { + Node.Hot = 1 + Node.Level = Level + HotArr[Level].push(Node) + } + } + } + var arr = this.NodesArr; + for (var n = 0; arr && n < arr.length; n++) { + var Node = arr[n]; + if (!Node) + continue; + if (Node.Hot) + continue; + if (!this.IsCanConnect(Node)) + continue; + Node.Level = this.AddrLevelNode(Node) + if (!HotArr[Node.Level]) + HotArr[Node.Level] = [] + HotArr[Node.Level].push(Node) + } + return HotArr; + } + DetectGrayMode() { + if (global.NET_WORK_MODE) + return; + var CurTime = Date.now(); + var CountNodes = this.ActualNodes.size; + if (CountNodes || this.StopDetectGrayMode) { + this.SetDirectMode() + this.StopDetectGrayMode = 1 + return; + } + if (!this.LastNotZeroNodesTime) + this.LastNotZeroNodesTime = CurTime + var DeltaTime = CurTime - this.LastNotZeroNodesTime; + if (DeltaTime > 10 * 1000) { + global.ToLog("DETECT GRAY MODE") + if (!global.NET_WORK_MODE) { + global.NET_WORK_MODE = { ip: "", port: "" } + } + global.NET_WORK_MODE.UseDirectIP = 0 + SAVE_CONST() + } + } + SetDirectMode() { + var CountNodes = this.ActualNodes.size; + if (CountNodes && !global.NET_WORK_MODE) { + global.NET_WORK_MODE = { ip: "", port: "30000" } + global.NET_WORK_MODE.UseDirectIP = 1 + SAVE_CONST() + } + } + StartCheckTransferTree() { + var ArrTree = this.GetTransferTree(); + this.TransferTree = ArrTree + var CurTime = Date.now(); + if (GrayConnect()) { + var MustCount = GetGrayServerConnections(); + if (this.ActualNodes.size < MustCount) { + this.NodesArr.sort(SortNodeBlockProcessCountGray) + var WasDoConnect = 0; + var arr = this.NodesArr; + for (var n = 0; arr && n < arr.length; n++) { + var Node = arr[n]; + if (!Node) + continue; + if (!this.IsCanConnect(Node)) + continue; + var DeltaTime = CurTime - Node.StartTimeConnect; + if (!Node.Active && WasDoConnect < 5 && !Node.WasAddToConnect && DeltaTime >= Node.NextConnectDelta) { + AddNodeInfo(Node, "To connect") + Node.WasAddToConnect = 1 + ArrConnect.push(Node) + WasDoConnect++ + } + } + } + while (this.ActualNodes.size > MustCount) { + var Node = this.ActualNodes.max(); + AddNodeInfo(Node, "DeleteFromActive") + this.DeleteNodeFromActive(Node) + } + } + else { + this.DetectGrayMode() + for (var Level = 0; Level < ArrTree.length; Level++) { + var arr = ArrTree[Level]; + if (!arr) + continue; + arr.sort(SortNodeBlockProcessCount) + var WasDoConnect = 0; + var WasDoHot = 0; + var length = Math.min(arr.length, 10); + for (var n = 0; n < length; n++) { + var Node = arr[n]; + var DeltaTime = CurTime - Node.StartTimeConnect; + if (!Node.Active && WasDoConnect < 5 && !Node.WasAddToConnect && DeltaTime >= Node.NextConnectDelta) { + AddNodeInfo(Node, "To connect") + Node.WasAddToConnect = 1 + ArrConnect.push(Node) + WasDoConnect++ + } + DeltaTime = CurTime - Node.StartTimeHot + if (Node.Active && !Node.Hot && WasDoHot < MIN_CONNECT_CHILD && DeltaTime > Node.NextHotDelta && !Node.GrayConnect) { + AddNodeInfo(Node, "To hot level") + this.StartAddLevelConnect(Node) + Node.StartTimeHot = CurTime + Node.NextHotDelta = Node.NextHotDelta * 2 + WasDoHot++ + } + if (Node.Hot) + WasDoHot++ + } + this.CheckDisconnectHot(Level) + } + } + } + ValueToXOR(StrType, Str) { + var Arr1 = toUTF8Array(Str); + var Arr2 = global.shaarr(this.CommonKey + ":" + this.addrStr + ":" + StrType); + return global.WALLET.XORHash(Arr1, Arr2, 32); + } + ValueFromXOR(Node, StrType, Arr1) { + var Arr2 = global.shaarr(this.CommonKey + ":" + Node.addrStr + ":" + StrType); + var Arr = global.WALLET.XORHash(Arr1, Arr2, 32); + var Str = Utf8ArrayToStr(Arr); + return Str; + } + ValueToXORDevelop(StrName, Data, Type) { + var Arr1; + if (Type === "uint") { + Arr1 = [] + WriteUintToArr(Arr1, Data) + } + else + if (Type === "hash") { + Arr1 = Data + } + else + if (Type === "str") { + Arr1 = toUTF8Array(Data) + } + var Arr2 = global.shaarr(this.КодДлÑÐ Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¥ÐµÐºÑ + ":" + StrName); + return global.WALLET.XORHash(Arr1, Arr2, Arr1.length); + } + ValueFromXORDevelop(Node, StrName, Arr1, Type) { + if (!Node.КодДлÑРазработчикаХекÑ) { + Node.КодДлÑÐ Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¥ÐµÐºÑ = global.GetHexFromArr(WALLET.KeyPair.computeSecret(Node.PubKey, null)) + } + var Arr2 = global.shaarr(Node.КодДлÑÐ Ð°Ð·Ñ€Ð°Ð±Ð¾Ñ‚Ñ‡Ð¸ÐºÐ°Ð¥ÐµÐºÑ + ":" + StrName); + var Arr = global.WALLET.XORHash(Arr1, Arr2, Arr1.length); + if (Type === "uint") { + return ReadUintFromArr(Arr, 0); + } + else + if (Type === "hash") { + return Arr; + } + var Str = Utf8ArrayToStr(Arr); + return Str; + } +}; + +function SortNodeBlockProcessCount(a, b) { + if (b.BlockProcessCount !== a.BlockProcessCount) + return b.BlockProcessCount - a.BlockProcessCount; + if (a.DeltaTime !== b.DeltaTime) + return a.DeltaTime - b.DeltaTime; + return a.id - b.id; +}; + +function SortNodeBlockProcessCountGray(a, b) { + if (a.StartFindList !== b.StartFindList) + return a.StartFindList - b.StartFindList; + if (b.BlockProcessCount !== a.BlockProcessCount) + return b.BlockProcessCount - a.BlockProcessCount; + if (a.DeltaTime !== b.DeltaTime) + return a.DeltaTime - b.DeltaTime; + return a.id - b.id; +}; + +function GetGrayServerConnections() { + var Count = MAX_GRAY_CONNECTIONS_TO_SERVER; + if (SERVER.LoadHistoryMode && global.SERVER.LoadHistoryMessage) + Count = Count * 10; + return Count; +}; +global.GetGrayServerConnections = GetGrayServerConnections; +global.SortNodeBlockProcessCount = SortNodeBlockProcessCount; diff --git a/src/core/constant.ts b/src/core/constant.ts new file mode 100644 index 0000000..2b67aae --- /dev/null +++ b/src/core/constant.ts @@ -0,0 +1,352 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.UPDATE_CODE_VERSION_NUM = 1102; +global.MIN_CODE_VERSION_NUM = 1094; +global.MINING_VERSION_NUM = 0; +global.InitParamsArg = InitParamsArg; +global.CONST_NAME_ARR = [ + "AUTO_CORRECT_TIME", + "DELTA_CURRENT_TIME", + "COMMON_KEY", + "NODES_NAME", + "SERVER_PRIVATE_KEY_HEX", + "USE_NET_FOR_SERVER_ADDRES", + "NET_WORK_MODE", + "STAT_MODE", + "MAX_STAT_PERIOD", + "LISTEN_IP", + "HTTP_PORT_NUMBER", + "HTTP_PORT_PASSWORD", + "HTTP_IP_CONNECT", + "WALLET_NAME", + "WALLET_DESCRIPTION", + "USE_HARD_API_V2", + "COUNT_VIEW_ROWS", + "USE_HINT", + "ALL_VIEW_ROWS", + "ALL_LOG_TO_CLIENT", + "LOG_LEVEL", + "USE_MINING", + "MINING_START_TIME", + "MINING_PERIOD_TIME", + "POW_MAX_PERCENT", + "COUNT_MINING_CPU", + "SIZE_MINING_MEMORY", + "POW_RUN_COUNT", + "USE_AUTO_UPDATE", + "RESTART_PERIOD_SEC", + "MAX_GRAY_CONNECTIONS_TO_SERVER", + "TRANSACTION_PROOF_COUNT", + "UPDATE_NUM_COMPLETE", + "LIMIT_SEND_TRAFIC", + "WATCHDOG_DEV", + "ADDRLIST_MODE", + "CheckPointDelta", + "MIN_VER_STAT", + "DEBUG_WALLET", + "HTTP_HOSTING_PORT", + "HTTPS_HOSTING_DOMAIN", + "HTTP_MAX_COUNT_ROWS", + "HTTP_ADMIN_PASSORD", + "WATCHDOG_BADACCOUNT", + "RESYNC_CONDITION", + "MAX_CONNECTIONS_COUNT", + "TRUST_PROCESS_COUNT", + "REST_START_COUNT", + "LOAD_TO_BEGIN" +]; +global.NODES_DELTA_CALC_HOUR = 4; +global.USE_HARD_API_V2 = 0; +global.USE_TICKET = 0; +global.USE_CHECK_SENDING = 1; +global.USE_LEVEL_WAY = 0; +global.TR_TICKET_HASH_LENGTH = 10; +global.BLOCKNUM_TICKET_ALGO = 16070000; +global.WATCHDOG_BADACCOUNT = 1; +global.WATCHDOG_DEV = 0; +global.RESYNC_CONDITION = { "OWN_BLOCKS": 20, "K_POW": 5 }; +global.REST_BLOCK_SCALE = 1000; +global.REST_START_COUNT = 10000; +global.LOAD_TO_BEGIN = 2; +global.DEBUG_WALLET = 0; +global.CHECK_GLOBAL_TIME = 1; +global.AUTO_CORRECT_TIME = 1; +global.DELTA_CURRENT_TIME = 0; +global.NODES_NAME = ""; +global.COMMON_KEY = ""; +global.SERVER_PRIVATE_KEY_HEX = undefined; +global.USE_NET_FOR_SERVER_ADDRES = 1; +global.NET_WORK_MODE = undefined; +global.STAT_MODE = 0; +global.MAX_STAT_PERIOD = 1 * 3600; +global.UPDATE_NUM_COMPLETE = 0; +global.WALLET_NAME = "TERA"; +global.WALLET_DESCRIPTION = ""; +global.USE_MINING = 0; +global.POW_MAX_PERCENT = 50; +global.POW_RUN_COUNT = 5000; +global.POWRunPeriod = 1; +global.CheckPointDelta = 20; +global.ALL_LOG_TO_CLIENT = 1; +global.LOG_LEVEL = 1; +global.LIMIT_SEND_TRAFIC = 0; +global.COUNT_VIEW_ROWS = 20; +global.MIN_VER_STAT = 0; +global.STOPGETBLOCK = 0; +global.RESTART_PERIOD_SEC = 0; +global.HARD_PACKET_PERIOD120 = 160; +global.MINING_START_TIME = ""; +global.MINING_PERIOD_TIME = ""; +global.CHECK_RUN_MINING = 21 * 1000; +global.CHECK_STOP_CHILD_PROCESS = 10 * 1000; +global.COUNT_MINING_CPU = 0; +global.SIZE_MINING_MEMORY = 0; +global.HTTP_HOSTING_PORT = 0; +global.HTTPS_HOSTING_DOMAIN = ""; +global.HTTP_MAX_COUNT_ROWS = 20; +global.HTTP_ADMIN_PASSORD = ""; +require("./startlib.js"); +global.MIN_POWER_POW_HANDSHAKE = 12; +global.USE_HINT = 0; +global.ALL_VIEW_ROWS = 0; +global.COUNT_BLOCK_PROOF = 300; +global.COUNT_NODE_PROOF = 10; +global.MIN_POWER_POW_MSG = 2; +global.MEM_POOL_MSG_COUNT = 1000; +global.MAX_LEVEL_SPECIALIZATION = 24; +global.MIN_CONNECT_CHILD = 2; +global.MAX_CONNECT_CHILD = 7; +global.MAX_CONNECTIONS_COUNT = 1000; +global.TRUST_PROCESS_COUNT = 80000; +global.MAX_NODES_RETURN = 100; +global.MAX_WAIT_PERIOD_FOR_STATUS = 10 * 1000; +global.MAX_GRAY_CONNECTIONS_TO_SERVER = 10; +global.MAX_PACKET_LENGTH = 450 * 1024; +global.COUNT_BLOCKS_FOR_LOAD = 600; +global.TR_LEN = 100; +global.BLOCK_PROCESSING_LENGTH = 8; +global.BLOCK_PROCESSING_LENGTH2 = global.BLOCK_PROCESSING_LENGTH * 2; +global.CONSENSUS_PERIOD_TIME = 1000; +global.MAX_BLOCK_SIZE = 130 * 1024; +global.MAX_TRANSACTION_SIZE = 65535; +global.MIN_TRANSACTION_SIZE = 32; +global.MAX_TRANSACTION_COUNT = 2000; +global.MAX_TRANSACTION_LIMIT = 250; +global.MIN_POWER_POW_TR = 10; +if (global.MIN_POWER_POW_BL === undefined) + global.MIN_POWER_POW_BL = 5; +global.GENERATE_BLOCK_ACCOUNT = 0; +global.TOTAL_SUPPLY_TERA = 1e9; +global.TRANSACTION_PROOF_COUNT = 1000 * 1000; +global.MIN_POWER_POW_ACC_CREATE = 16; +global.START_MINING = 2 * 1000 * 1000; +global.REF_PERIOD_MINING = 1 * 1000 * 1000; +global.DELTA_BLOCK_ACCOUNT_HASH = 1000; +global.PERIOD_ACCOUNT_HASH = 50; +global.START_BLOCK_ACCOUNT_HASH = 14500000; +global.START_BLOCK_ACCOUNT_HASH3 = 24015000; +global.NEW_ACCOUNT_INCREMENT = 22305000; +global.NEW_BLOCK_REWARD1 = 22500000; +global.NEW_FORMULA_START = 32000000; +global.NEW_FORMULA_KTERA = 3; +global.NEW_FORMULA_TARGET1 = 43000000; +global.NEW_FORMULA_TARGET2 = 45000000; +global.BLOCK_COUNT_IN_MEMORY = 40; +global.HISTORY_BLOCK_COUNT = 40; +global.MAX_SIZE_LOG = 200 * 1024 * 1024; +global.READ_ONLY_DB = 0; +global.USE_CHECK_SAVE_DB = 1; +global.START_NETWORK_DATE = 1530446400000; +global.NETWORK = "TERA-MAIN"; +global.DEF_MAJOR_VERSION = "0001"; +global.SMART_BLOCKNUM_START = 10000000; +global.PRICE_DAO = function(BlockNum) { + return { NewAccount: 10, NewSmart: 100, NewTokenSmart: 10000 }; +}; +if (global.LOCAL_RUN) { + var Num = Date.now() - 300 * 1000; + global.START_NETWORK_DATE = Math.trunc(Num / 1000) * 1000; +} +global.NEW_SIGN_TIME = 25500000; +InitParamsArg(); +if (global.LOCAL_RUN) { + global.REST_BLOCK_SCALE = 100; + global.DELTA_BLOCK_ACCOUNT_HASH = 30; + global.PERIOD_ACCOUNT_HASH = 10; + global.START_BLOCK_ACCOUNT_HASH = 1; + global.START_BLOCK_ACCOUNT_HASH3 = 1; + global.BLOCKNUM_TICKET_ALGO = 1; + global.SMART_BLOCKNUM_START = 0; + global.START_MINING = 60; + global.REF_PERIOD_MINING = 10; + global.TEST_TRANSACTION_GENERATE = 0; + global.MIN_POWER_POW_TR = 8; + global.MIN_POWER_POW_ACC_CREATE = 8; + global.NEW_ACCOUNT_INCREMENT = 1; + global.NEW_BLOCK_REWARD1 = 1; + global.NEW_FORMULA_START = 1; + global.NEW_FORMULA_KTERA = 3; + global.NEW_FORMULA_TARGET1 = 0; + global.NEW_FORMULA_TARGET2 = 1; + NETWORK = "LOCAL"; + global.ALL_VIEW_ROWS = 1; + global.COUNT_NODE_PROOF = 1; + global.NEW_SIGN_TIME = 0; +} +else + if (global.TEST_NETWORK) { + global.REST_BLOCK_SCALE = 100; + var Num = Date.now() - 50 * 1000; + console.log("CURRENT NUM: " + (Math.trunc(Num / 1000) * 1000)); + global.SMART_BLOCKNUM_START = 0; + global.START_NETWORK_DATE = 1550843168000 + 1000 * 1000; + global.START_MINING = 1000; + global.REF_PERIOD_MINING = 1000; + global.MIN_POWER_POW_ACC_CREATE = 8; + global.TRANSACTION_PROOF_COUNT = 200 * 1000; + global.MAX_SIZE_LOG = 20 * 1024 * 1024; + global.START_BLOCK_ACCOUNT_HASH = 1000; + global.START_BLOCK_ACCOUNT_HASH3 = 2356000; + global.BLOCKNUM_TICKET_ALGO = 1; + global.WALLET_NAME = "TEST"; + NETWORK = "TERA-TEST2"; + if (global.START_PORT_NUMBER === undefined) + global.START_PORT_NUMBER = 40000; + global.ALL_VIEW_ROWS = 1; + global.NEW_ACCOUNT_INCREMENT = 1903000; + global.NEW_BLOCK_REWARD1 = 1905000; + global.NEW_FORMULA_START = 11402000; + global.NEW_FORMULA_KTERA = 3; + global.NEW_FORMULA_TARGET1 = 11403000; + global.NEW_FORMULA_TARGET2 = 11405000; + global.COUNT_NODE_PROOF = 8; + global.REST_START_COUNT = 10000; + global.NEW_SIGN_TIME = 4859000; + } +if (global.LOCAL_RUN) { + global.BLOCKNUM_TICKET_ALGO = 0; + global.MIN_POWER_POW_TR = 0; + global.AUTO_CORRECT_TIME = 0; + global.CHECK_GLOBAL_TIME = 0; +} +global.GetNetworkName = function() { + return NETWORK + "-" + global.DEF_MAJOR_VERSION; +}; +global.DEF_VERSION = global.DEF_MAJOR_VERSION + "." + global.UPDATE_CODE_VERSION_NUM; +global.DEF_CLIENT = "TERA-CORE"; +global.FIRST_TIME_BLOCK = global.START_NETWORK_DATE; +global.START_BLOCK_RUN = 0; +if (global.START_IP === undefined) + global.START_IP = ""; +if (global.LISTEN_IP === undefined) + global.LISTEN_IP = "0.0.0.0"; +if (global.START_PORT_NUMBER === undefined) + global.START_PORT_NUMBER = 30000; +if (global.HTTP_PORT_PASSWORD === undefined) + global.HTTP_PORT_PASSWORD = ""; +if (global.HTTP_IP_CONNECT === undefined) + global.HTTP_IP_CONNECT = ""; +if (global.USE_AUTO_UPDATE === undefined) + global.USE_AUTO_UPDATE = 1; +if (global.USE_PARAM_JS === undefined) + global.USE_PARAM_JS = 1; +if (global.DATA_PATH === undefined) + global.DATA_PATH = ""; +if (global.CREATE_ON_START === undefined) + global.CREATE_ON_START = false; +if (global.LOCAL_RUN === undefined) + global.LOCAL_RUN = 0; +if (global.CODE_PATH === undefined) + global.CODE_PATH = process.cwd(); +if (global.DEBUG_MODE === undefined) + global.DEBUG_MODE = 0; +global.DEBUG_MODE = 0; +if (typeof window === 'object') { + window.RUN_CLIENT = 0; + window.RUN_SERVER = 1; +} +global.RUN_CLIENT = 0; +global.RUN_SERVER = 1; + +function InitParamsArg() { + for (var i = 1; i < process.argv.length; i++) { + var str0 = process.argv[i]; + var str = str0.toUpperCase(); + if (str.substr(0, 9) == "HTTPPORT:") { + global.HTTP_PORT_NUMBER = parseInt(str.substr(9)); + } + else + if (str.substr(0, 9) == "PASSWORD:") { + global.HTTP_PORT_PASSWORD = str0.substr(9); + } + else + if (str.substr(0, 5) == "PATH:") + global.DATA_PATH = str0.substr(5); + else + if (str.substr(0, 5) == "PORT:") + global.START_PORT_NUMBER = parseInt(str.substr(5)); + else + if (str.substr(0, 3) == "IP:") + global.START_IP = str.substr(3); + else + if (str.substr(0, 7) == "LISTEN:") + global.LISTEN_IP = str.substr(7); + else + if (str.substr(0, 8) == "HOSTING:") { + global.HTTP_HOSTING_PORT = parseInt(str.substr(8)); + } + else + if (str.substr(0, 13) == "STARTNETWORK:") { + global.START_NETWORK_DATE = parseInt(str.substr(13)); + console.log("START_NETWORK_DATE: " + global.START_NETWORK_DATE); + } + else { + switch (str) { + case "CHILDPOW": + global.CHILD_POW = true; + break; + case "ADDRLIST": + global.ADDRLIST_MODE = true; + break; + case "CREATEONSTART": + global.CREATE_ON_START = true; + break; + case "LOCALRUN": + global.LOCAL_RUN = 1; + break; + case "TESTRUN": + global.TEST_NETWORK = 1; + break; + case "NOLOCALRUN": + global.LOCAL_RUN = 0; + break; + case "NOAUTOUPDATE": + global.USE_AUTO_UPDATE = 0; + break; + case "NOPARAMJS": + global.USE_PARAM_JS = 0; + break; + case "READONLYDB": + global.READ_ONLY_DB = 1; + break; + case "NWMODE": + global.NWMODE = 1; + break; + case "NOALIVE": + global.NOALIVE = 1; + break; + case "DEV_MODE": + global.DEV_MODE = 1; + break; + } + } + } +}; diff --git a/src/core/crypto-library.ts b/src/core/crypto-library.ts new file mode 100644 index 0000000..8c4f4ff --- /dev/null +++ b/src/core/crypto-library.ts @@ -0,0 +1,993 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +require("./library.js"); +import * as crypto from 'crypto' + +let { + sha3, + secp256k1, + SHA3BUF, + GetSignHash, + shaarr, + ToLog +} = global + +global.MAX_SUPER_VALUE_POW = (1 << 30) * 2; +var BuferForStr = Buffer.alloc(32); +global.GetHexFromAddres = function(arr) { + if (!arr) + return ""; + if (arr.data !== undefined) + arr = arr.data; + for (var i = 0; i < 32; i++) + BuferForStr[i] = arr[i]; + return BuferForStr.toString('hex').toUpperCase(); +}; +global.GetArr32FromHex = function(Str) { + var array = new Uint8Array(32); + for (var i = 0; i < array.length; i++) { + array[i] = parseInt(Str.substr(i * 2, 2), 16); + } + return array; +}; +global.GetAddresFromHex = global.GetArr32FromHex; +global.GetHexAddresFromPublicKey = function(arr) { + return Buffer.from(arr.slice(1)).toString('hex').toUpperCase(); +}; +global.GetHexFromArr = function(arr) { + if (!arr) + return ""; + else + return Buffer.from(arr).toString('hex').toUpperCase(); +}; + +function GetArrFromHex(Str) { + var array = []; + for (var i = 0; i < Str.length / 2; i++) { + array[i] = parseInt(Str.substr(i * 2, 2), 16); + } + return array; +}; +global.GetArrFromHex = GetArrFromHex; +global.GetHexFromArrBlock = function(Arr, LenBlock) { + var Str = ""; + var Arr2 = []; + for (var i = 0; i < Arr.length; i++) { + Arr2[i % LenBlock] = Arr[i]; + if (Arr2.length >= LenBlock) { + Str += global.GetHexFromArr(Arr2) + "\n"; + Arr2 = []; + } + } + if (Arr2.length) { + Str += global.GetHexFromArr(Arr2); + } + return Str; +}; +global.GetPublicKeyFromAddres = function(Arr) { + var RetArr = new Uint8Array(33); + RetArr[0] = 2; + for (var i = 1; i < 33; i++) + RetArr[i] = Arr[i - 1]; + return RetArr; +}; +global.CheckDevelopSign = function(SignArr, Sign) { + var hash = SHA3BUF(SignArr); + for (var i = 0; i < DEVELOP_PUB_KEY_ARR.length; i++) { + var Result = secp256k1.verify(hash, Buffer.from(Sign), DEVELOP_PUB_KEY_ARR[i]); + if (Result) + return 1; + } + return 0; +}; +let GetPublicKeyFromAddres = global.GetPublicKeyFromAddres; +global.CheckContextSecret = function(Context, ContextAddrTo) { + if (ContextAddrTo.Secret === undefined) { + if (ContextAddrTo.publickey === undefined) { + ContextAddrTo.publickey = GetPublicKeyFromAddres(ContextAddrTo.addrArr); + } + ContextAddrTo.Secret = Context.KeyPair.computeSecret(ContextAddrTo.publickey, null); + } +}; +let CheckContextSecret = global.CheckContextSecret; +global.GetSignHash = function(Context, ContextAddrTo, Msg) { + CheckContextSecret(Context, ContextAddrTo); + if (typeof Msg === "string") + Msg = Buffer.from(Msg); + var Buf = Buffer.concat([Msg, ContextAddrTo.Secret], Msg.length + ContextAddrTo.Secret.length); + var Arr = global.shaarr(Buf); + return Arr; +}; +global.GetVerifyHash = function(Context, ContextAddr, Msg, Sign1) { + try { + var Sign2 = GetSignHash(Context, ContextAddr, Msg); + for (var i = 0; i < Sign1.length; i++) + if (Sign1[i] !== Sign2[i]) + return false; + return true; + } + catch (e) { + return false; + } +}; +global.GetKeyPair = function(password, secret, startnonce1, startnonce2) { + secret = secret || "low"; + startnonce1 = startnonce1 || 0; + startnonce2 = startnonce2 || 0; + var KeyPair: any = crypto.createECDH('secp256k1'); + var private1 = global.shaarr(password); + var private2 = private1; + var nonce1 = 0; + if (secret === "high") + for (nonce1 = startnonce1; nonce1 < 2000000000; nonce1++) { + private1[31] = nonce1 & 0xFF; + private1[30] = (nonce1 >>> 8) & 0xFF; + private1[29] = (nonce1 >>> 16) & 0xFF; + private1[28] = (nonce1 >>> 24) & 0xFF; + private2 = global.shaarr(private1); + if (private2[0] === 0 && private2[1] === 0 && private2[2] === 0) { + break; + } + nonce1++; + } + var nonce2; + for (nonce2 = startnonce2; nonce2 < 2000000000; nonce2++) { + private2[31] = nonce2 & 0xFF; + private2[30] = (nonce2 >>> 8) & 0xFF; + private2[29] = (nonce2 >>> 16) & 0xFF; + private2[28] = (nonce2 >>> 24) & 0xFF; + KeyPair.setPrivateKey(Buffer.from(private2)); + var Data = KeyPair.getPublicKey('', 'compressed'); + if (Data[0] === 2 && Data[31] === 0 && Data[32] === 0) { + KeyPair.nonce1 = nonce1; + KeyPair.nonce2 = nonce2; + KeyPair.PubKeyArr = KeyPair.getPublicKey('', 'compressed'); + KeyPair.addrArr = KeyPair.PubKeyArr.slice(1); + KeyPair.addrStr = global.GetHexFromArr(KeyPair.addrArr); + KeyPair.addr = KeyPair.addrArr; + return KeyPair; + } + nonce2++; + } + throw "ERROR. Key pair not found. Try another password!"; +}; +global.GetKeyPairTest = function(password, Power) { + var KeyPair: any = crypto.createECDH('secp256k1'); + var private2 = global.shaarr(password); + for (var nonce2 = 0; nonce2 < 1000000000; nonce2++) { + private2[31] = nonce2 & 0xFF; + private2[30] = (nonce2 >> 8) & 0xFF; + private2[29] = (nonce2 >> 16) & 0xFF; + private2[28] = (nonce2 >> 24) & 0xFF; + KeyPair.setPrivateKey(Buffer.from(private2)); + var Data = KeyPair.getPublicKey('', 'compressed'); + if (Data[0] === 2) { + if (Power) { + var nBits = GetPowPower(Data.slice(1)); + if (nBits < Power) + continue; + } + KeyPair.PubKeyArr = Data; + KeyPair.addrArr = KeyPair.PubKeyArr.slice(1); + KeyPair.addrStr = global.GetHexFromArr(KeyPair.addrArr); + KeyPair.addr = KeyPair.addrArr; + return KeyPair; + } + } + throw "ERROR. Key pair not found. Try another password!"; +}; + +function GetArrFromValue(Num) { + var arr = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + arr[0] = Num & 0xFF; + arr[1] = (Num >>> 8) & 0xFF; + arr[2] = (Num >>> 16) & 0xFF; + arr[3] = (Num >>> 24) & 0xFF; + var NumH = Math.floor(Num / 4294967296); + arr[4] = NumH & 0xFF; + arr[5] = (NumH >>> 8) & 0xFF; + return arr; +}; + +function GetHashWithNonce(hash0, nonce) { + return shaarr2(hash0, GetArrFromValue(nonce)); +}; +global.GetHashWithValues = GetHashWithValues; + +function GetHashWithValues(hash0, value1, value2, bNotCopy) { + var hash; + if (bNotCopy) + hash = hash0; + else + hash = hash0.slice(); + hash[0] = value1 & 0xFF; + hash[1] = (value1 >>> 8) & 0xFF; + hash[2] = (value1 >>> 16) & 0xFF; + hash[3] = (value1 >>> 24) & 0xFF; + hash[4] = value2 & 0xFF; + hash[5] = (value2 >>> 8) & 0xFF; + hash[6] = (value2 >>> 16) & 0xFF; + hash[7] = (value2 >>> 24) & 0xFF; + var arrhash = global.shaarr(hash); + return arrhash; +}; + +function GetPowPower(arrhash) { + var SumBit = 0; + if (arrhash) + for (var i = 0; i < arrhash.length; i++) { + var CurSum = Math.clz32(arrhash[i]) - 24; + SumBit += CurSum; + if (CurSum !== 8) + break; + } + return SumBit; +}; + +function GetPowValue(arrhash) { + var value = (arrhash[0] << 23) * 2 + (arrhash[1] << 16) + (arrhash[2] << 8) + arrhash[3]; + value = value * 256 + arrhash[4]; + value = value * 256 + arrhash[5]; + return value; +}; +global.CreateNoncePOWExtern = CreateNoncePOWExtern; + +function CreateNoncePOWExtern(arr0, BlockNum, count, startnone) { + var arr = []; + for (var i = 0; i < arr0.length; i++) + arr[i] = arr0[i]; + if (!startnone) + startnone = 0; + var maxnonce = 0; + var supervalue = MAX_SUPER_VALUE_POW; + for (var nonce = startnone; nonce <= startnone + count; nonce++) { + var arrhash = GetHashWithValues(arr, nonce, BlockNum, true); + var value = GetPowValue(arrhash); + if (value < supervalue) { + maxnonce = nonce; + supervalue = value; + } + } + return maxnonce; +}; +global.CreateNoncePOWExternMinPower = CreateNoncePOWExternMinPower; + +function CreateNoncePOWExternMinPower(arr0, BlockNum, MinPow) { + var arr = []; + for (var i = 0; i < arr0.length; i++) + arr[i] = arr0[i]; + var nonce = 0; + while (1) { + var arrhash = GetHashWithValues(arr, nonce, BlockNum, true); + var power = GetPowPower(arrhash); + if (power >= MinPow) { + return nonce; + } + nonce++; + } +}; +global.CreateNoncePOWInner = function(arr0, count) { + var Hash; + var arr = arr0.slice(); + var maxnonce = 0; + var supervalue = MAX_SUPER_VALUE_POW; + for (var nonce = 0; nonce < count; nonce++) { + var hashTest = GetHashWithNonce(arr, nonce); + var value = GetPowValue(hashTest); + if (value < supervalue) { + maxnonce = nonce; + supervalue = value; + Hash = hashTest; + } + } + return { nonce: maxnonce, Hash: Hash }; +}; +global.CreateAddrPOW = function(SeqHash, AddrArr, MaxHash, Start, CountNonce, BlockNum) { + var MaxNonce = 0; + var bFind = 0; + for (var nonce = Start; nonce < Start + CountNonce; nonce++) { + AddrArr[6] = nonce & 0xFF; + AddrArr[7] = (nonce >>> 8) & 0xFF; + AddrArr[8] = (nonce >>> 16) & 0xFF; + AddrArr[9] = (nonce >>> 24) & 0xFF; + var HashTest = shaarrblock2(SeqHash, AddrArr, BlockNum); + if (global.CompareArr(MaxHash, HashTest) >= 0) { + MaxHash = HashTest; + MaxNonce = nonce; + bFind = 1; + } + } + if (bFind) { + AddrArr[6] = MaxNonce & 0xFF; + AddrArr[7] = (MaxNonce >>> 8) & 0xFF; + AddrArr[8] = (MaxNonce >>> 16) & 0xFF; + AddrArr[9] = (MaxNonce >>> 24) & 0xFF; + } + return { MaxHash: MaxHash, LastNonce: nonce, MaxNonce: MaxNonce, bFind: bFind }; +}; + +function IsZeroArr(arr) { + if (arr) + for (var i = 0; i < arr.length; i++) { + if (arr[i]) + return false; + } + return true; +}; + +function CalcHashFromArray(ArrHashes, bOriginalSeq) { + if (bOriginalSeq === undefined) + ArrHashes.sort(CompareArr); + var Buf = []; + for (var i = 0; i < ArrHashes.length; i++) { + var Value = ArrHashes[i]; + for (var n = 0; n < Value.length; n++) + Buf.push(Value[n]); + } + if (Buf.length === 0) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + else + if (Buf.length === 32) + return Buf; + var Hash = global.shaarr(Buf); + return Hash; +}; + +function CalcHash3FromArray(ArrHashes, bOriginalSeq) { + if (bOriginalSeq === undefined) + ArrHashes.sort(CompareArr); + var Buf = []; + for (var i = 0; i < ArrHashes.length; i++) { + var Value = ArrHashes[i]; + for (var n = 0; n < Value.length; n++) + Buf.push(Value[n]); + } + if (Buf.length === 0) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + else + if (Buf.length === 32) + return Buf; + var Hash = global.sha3(Buf); + return Hash; +}; + +function CalcMerkl3FromArray(Arr, Tree0?) { + var Tree, bSort; + if (Tree0) { + bSort = 0; + Tree = Tree0; + } + else { + bSort = 1; + Tree = { Levels: [], Full: true }; + } + Tree.Levels.push(Arr); + if (Arr.length < 2) { + if (Arr.length === 0) + Tree.Root = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + else { + if (Arr[0].length === 32) + Tree.Root = Arr[0]; + else + Tree.Root = global.sha3(Arr[0]); + } + return Tree; + } + if (bSort) { + Arr.sort(CompareArr); + } + var Arr2 = []; + var len = Math.floor(Arr.length / 2); + for (var i = 0; i < len; i++) { + var Hash = sha3arr2(Arr[i * 2], Arr[i * 2 + 1]); + Arr2.push(Hash); + } + if (len * 2 !== Arr.length) { + Arr2.push(Arr[Arr.length - 1]); + } + return CalcMerkl3FromArray(Arr2, Tree); +}; + +function CalcMerkl0FromArray(Arr, Tree0?) { + var Tree, bSort; + if (Tree0) { + bSort = 0; + Tree = Tree0; + } + else { + bSort = 1; + Tree = { Levels: [], Full: true }; + } + Tree.Levels.push(Arr); + if (Arr.length < 2) { + if (Arr.length === 0) + Tree.Root = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + else { + if (Arr[0].length === 32) + Tree.Root = Arr[0]; + else + Tree.Root = global.shaarr(Arr[0]); + } + return Tree; + } + if (bSort) { + Arr.sort(CompareArr); + } + var Arr2 = []; + var len = Math.floor(Arr.length / 2); + for (var i = 0; i < len; i++) { + var Hash = shaarr2(Arr[i * 2], Arr[i * 2 + 1]); + Arr2.push(Hash); + } + if (len * 2 !== Arr.length) { + Arr2.push(Arr[Arr.length - 1]); + } + return CalcMerkl0FromArray(Arr2, Tree); +}; + +function CalcMerklFromArray(BlockNum, Arr) { + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) { + return CalcMerkl3FromArray(Arr); + } + else { + return CalcMerkl0FromArray(Arr); + } +}; + +function CalcTreeHashFromArrBody(BlockNum, arrContent) { + if (arrContent) { + var arrHASH = []; + for (var i = 0; i < arrContent.length; i++) { + var HASH; + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) + HASH = global.sha3(arrContent[i]); + else + HASH = global.shaarr(arrContent[i]); + arrHASH.push(HASH); + } + var Tree = CalcMerklFromArray(BlockNum, arrHASH); + return Tree.Root; + } + else { + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } +}; + +function TestMerklTree() { + var h1 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var h2 = global.sha3("2"); + var h3 = global.sha3("3"); + var h4 = global.sha3("4"); + var h5 = global.sha3("5"); + var Tree: any = { RecalcCount: 0 }; + var CalcMap = {}; + Tree.LevelsHash = [[h1, h2]]; + Tree.RecalcCount = 0; + CalcMap[0] = 1; + CalcMap[1] = 1; + UpdateMerklTree(Tree, CalcMap, 0); + CalcMap = {}; + Tree.LevelsHash[0] = [h1, h2, h3, h4]; + Tree.RecalcCount = 0; + CalcMap[2] = 1; + CalcMap[3] = 1; + UpdateMerklTree(Tree, CalcMap, 0); + CalcMap = {}; + Tree.LevelsHash[0] = [h1, h2, h3]; + Tree.RecalcCount = 0; + CalcMap[Tree.LevelsHash[0].length - 1] = 1; + UpdateMerklTree(Tree, CalcMap, 0); + global.ToLog("Root=" + global.GetHexFromArr(Tree.Root)); + global.ToLog("RecalcCount=" + Tree.RecalcCount); + return Tree; +}; +if (0) + setTimeout(function() { + TestMerkleProof(100); + global.ToLog("=========END========="); + process.exit(0); + }); + +function TestMerkleProof(CountTest) { + for (var R = 0; R < CountTest; R++) { + var CountItems = Math.floor(Math.random() * CountTest); + var Tree: any = { RecalcCount: 0 }; + var CalcMap = {}; + Tree.LevelsHash = []; + Tree.LevelsHash[0] = []; + for (var i = 0; i < CountItems; i++) { + CalcMap[i] = 1; + Tree.LevelsHash[0][i] = global.sha3("" + i + "-" + R); + } + UpdateMerklTree(Tree, CalcMap, 0); + global.ToLog("Hash1=" + global.GetHexFromArr(Tree.Root) + " CountItems:" + CountItems); + var FirstNum = Math.floor(Math.random() * CountItems / 2); + var LastNum = Math.floor(CountItems / 2 + Math.random() * CountItems / 2); + var Ret = GetMerkleProof(Tree.LevelsHash, FirstNum, LastNum); + var ArrM = Tree.LevelsHash[0].slice(FirstNum, LastNum + 1); + var Hash2 = CheckMerkleProof(Ret.ArrL, ArrM, Ret.ArrR); + global.ToLog("Hash2=" + global.GetHexFromArr(Hash2) + " FirstNum=" + FirstNum + "/" + LastNum); + if (global.CompareArr(Tree.Root, Hash2) !== 0) + throw ("=========ERROR HASHTEST=============="); + else + global.ToLog("=========OK=============="); + } +}; + +function GetMerkleProof(LevelsHash, FirstNum, LastNum) { + var ArrL = []; + var ArrR = []; + var CurL = FirstNum; + var CurR = LastNum; + for (var L = 0; L < LevelsHash.length; L++) { + var LevelArr = LevelsHash[L]; + if (CurL % 2 === 1) + ArrL[L] = LevelArr[CurL - 1]; + if (CurR % 2 === 0 && CurR + 1 < LevelArr.length) + ArrR[L] = LevelArr[CurR + 1]; + CurL = Math.floor(CurL / 2); + CurR = Math.floor(CurR / 2); + } + return { ArrL: ArrL, ArrR: ArrR }; +}; + +function CheckMerkleProof(ArrL, ArrM, ArrR) { + var L = 0; + var Arr2 = ArrM; + while (true) { + var Arr = [].concat(Arr2); + if (ArrL[L]) + Arr.unshift(ArrL[L]); + if (ArrR[L]) + Arr.push(ArrR[L]); + if (Arr.length <= 1 && L >= ArrL.length && L >= ArrR.length) { + if (!Arr.length) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + return Arr[0]; + } + var length2 = Math.floor(Arr.length / 2); + Arr2 = []; + for (i = 0; i < length2; i++) { + var Hash = global.sha3(arr2(Arr[i * 2], Arr[i * 2 + 1])); + Arr2.push(Hash); + } + if (Arr.length / 2 > length2) + Arr2.push(Arr[Arr.length - 1]); + L++; + } +}; + +function UpdateMerklTree(Tree, CalcMap: any, NumLevel) { + var HashArr = Tree.LevelsHash[NumLevel]; + if (!HashArr || !HashArr.length) { + Tree.LevelsHash.length = NumLevel + 1; + Tree.MaxLevel = NumLevel; + Tree.Root = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + else + if (HashArr.length === 1) { + Tree.LevelsHash.length = NumLevel + 1; + Tree.MaxLevel = NumLevel; + Tree.Root = HashArr[0]; + } + else { + var CalcMap2 = {}; + var HashArr2 = Tree.LevelsHash[NumLevel + 1]; + if (!HashArr2) { + HashArr2 = []; + Tree.LevelsHash[NumLevel + 1] = HashArr2; + } + var len2 = Math.floor(HashArr.length / 2); + HashArr2.length = Math.floor(0.5 + HashArr.length / 2); + var Count = 0; + var LastIndex = HashArr.length - 1; + for (var key in CalcMap) { + var i2 = Math.floor(key as any / 2); + if (i2 < len2) { + Count++; + CalcMap2[i2] = 1; + HashArr2[i2] = global.sha3(arr2(HashArr[i2 * 2], HashArr[i2 * 2 + 1])); + } + else { + if (key as any > LastIndex) { + CalcMap2[i2] = 1; + } + else + if (i2 === len2) { + Count++; + CalcMap2[i2] = 1; + HashArr2[i2] = HashArr[key]; + } + } + } + if (Count) { + Tree.RecalcCount += Count; + UpdateMerklTree(Tree, CalcMap2, NumLevel + 1); + } + } +}; +var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649, 0, 2147516545, 2147483648, 32777, + 2147483648, 138, 0, 136, 0, 2147516425, 0, 2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771, 2147483648, + 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648, 2147516545, 2147483648, 32896, 2147483648, 2147483649, + 0, 2147516424, 2147483648]; + +function Mesh(s, Count) { + var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, + b16, b17, b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33, b34, b35, b36, b37, b38, b39, b40, + b41, b42, b43, b44, b45, b46, b47, b48, b49; + for (n = 0; n < Count; n += 2) { + c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40]; + c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41]; + c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42]; + c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43]; + c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44]; + c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45]; + c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46]; + c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47]; + c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48]; + c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49]; + h = c8 ^ ((c2 << 1) | (c3 >>> 31)); + l = c9 ^ ((c3 << 1) | (c2 >>> 31)); + s[0] ^= h; + s[1] ^= l; + s[10] ^= h; + s[11] ^= l; + s[20] ^= h; + s[21] ^= l; + s[30] ^= h; + s[31] ^= l; + s[40] ^= h; + s[41] ^= l; + h = c0 ^ ((c4 << 1) | (c5 >>> 31)); + l = c1 ^ ((c5 << 1) | (c4 >>> 31)); + s[2] ^= h; + s[3] ^= l; + s[12] ^= h; + s[13] ^= l; + s[22] ^= h; + s[23] ^= l; + s[32] ^= h; + s[33] ^= l; + s[42] ^= h; + s[43] ^= l; + h = c2 ^ ((c6 << 1) | (c7 >>> 31)); + l = c3 ^ ((c7 << 1) | (c6 >>> 31)); + s[4] ^= h; + s[5] ^= l; + s[14] ^= h; + s[15] ^= l; + s[24] ^= h; + s[25] ^= l; + s[34] ^= h; + s[35] ^= l; + s[44] ^= h; + s[45] ^= l; + h = c4 ^ ((c8 << 1) | (c9 >>> 31)); + l = c5 ^ ((c9 << 1) | (c8 >>> 31)); + s[6] ^= h; + s[7] ^= l; + s[16] ^= h; + s[17] ^= l; + s[26] ^= h; + s[27] ^= l; + s[36] ^= h; + s[37] ^= l; + s[46] ^= h; + s[47] ^= l; + h = c6 ^ ((c0 << 1) | (c1 >>> 31)); + l = c7 ^ ((c1 << 1) | (c0 >>> 31)); + s[8] ^= h; + s[9] ^= l; + s[18] ^= h; + s[19] ^= l; + s[28] ^= h; + s[29] ^= l; + s[38] ^= h; + s[39] ^= l; + s[48] ^= h; + s[49] ^= l; + b0 = s[0]; + b1 = s[1]; + b32 = (s[11] << 4) | (s[10] >>> 28); + b33 = (s[10] << 4) | (s[11] >>> 28); + b14 = (s[20] << 3) | (s[21] >>> 29); + b15 = (s[21] << 3) | (s[20] >>> 29); + b46 = (s[31] << 9) | (s[30] >>> 23); + b47 = (s[30] << 9) | (s[31] >>> 23); + b28 = (s[40] << 18) | (s[41] >>> 14); + b29 = (s[41] << 18) | (s[40] >>> 14); + b20 = (s[2] << 1) | (s[3] >>> 31); + b21 = (s[3] << 1) | (s[2] >>> 31); + b2 = (s[13] << 12) | (s[12] >>> 20); + b3 = (s[12] << 12) | (s[13] >>> 20); + b34 = (s[22] << 10) | (s[23] >>> 22); + b35 = (s[23] << 10) | (s[22] >>> 22); + b16 = (s[33] << 13) | (s[32] >>> 19); + b17 = (s[32] << 13) | (s[33] >>> 19); + b48 = (s[42] << 2) | (s[43] >>> 30); + b49 = (s[43] << 2) | (s[42] >>> 30); + b40 = (s[5] << 30) | (s[4] >>> 2); + b41 = (s[4] << 30) | (s[5] >>> 2); + b22 = (s[14] << 6) | (s[15] >>> 26); + b23 = (s[15] << 6) | (s[14] >>> 26); + b4 = (s[25] << 11) | (s[24] >>> 21); + b5 = (s[24] << 11) | (s[25] >>> 21); + b36 = (s[34] << 15) | (s[35] >>> 17); + b37 = (s[35] << 15) | (s[34] >>> 17); + b18 = (s[45] << 29) | (s[44] >>> 3); + b19 = (s[44] << 29) | (s[45] >>> 3); + b10 = (s[6] << 28) | (s[7] >>> 4); + b11 = (s[7] << 28) | (s[6] >>> 4); + b42 = (s[17] << 23) | (s[16] >>> 9); + b43 = (s[16] << 23) | (s[17] >>> 9); + b24 = (s[26] << 25) | (s[27] >>> 7); + b25 = (s[27] << 25) | (s[26] >>> 7); + b6 = (s[36] << 21) | (s[37] >>> 11); + b7 = (s[37] << 21) | (s[36] >>> 11); + b38 = (s[47] << 24) | (s[46] >>> 8); + b39 = (s[46] << 24) | (s[47] >>> 8); + b30 = (s[8] << 27) | (s[9] >>> 5); + b31 = (s[9] << 27) | (s[8] >>> 5); + b12 = (s[18] << 20) | (s[19] >>> 12); + b13 = (s[19] << 20) | (s[18] >>> 12); + b44 = (s[29] << 7) | (s[28] >>> 25); + b45 = (s[28] << 7) | (s[29] >>> 25); + b26 = (s[38] << 8) | (s[39] >>> 24); + b27 = (s[39] << 8) | (s[38] >>> 24); + b8 = (s[48] << 14) | (s[49] >>> 18); + b9 = (s[49] << 14) | (s[48] >>> 18); + s[0] = b0 ^ (~b2 & b4); + s[1] = b1 ^ (~b3 & b5); + s[10] = b10 ^ (~b12 & b14); + s[11] = b11 ^ (~b13 & b15); + s[20] = b20 ^ (~b22 & b24); + s[21] = b21 ^ (~b23 & b25); + s[30] = b30 ^ (~b32 & b34); + s[31] = b31 ^ (~b33 & b35); + s[40] = b40 ^ (~b42 & b44); + s[41] = b41 ^ (~b43 & b45); + s[2] = b2 ^ (~b4 & b6); + s[3] = b3 ^ (~b5 & b7); + s[12] = b12 ^ (~b14 & b16); + s[13] = b13 ^ (~b15 & b17); + s[22] = b22 ^ (~b24 & b26); + s[23] = b23 ^ (~b25 & b27); + s[32] = b32 ^ (~b34 & b36); + s[33] = b33 ^ (~b35 & b37); + s[42] = b42 ^ (~b44 & b46); + s[43] = b43 ^ (~b45 & b47); + s[4] = b4 ^ (~b6 & b8); + s[5] = b5 ^ (~b7 & b9); + s[14] = b14 ^ (~b16 & b18); + s[15] = b15 ^ (~b17 & b19); + s[24] = b24 ^ (~b26 & b28); + s[25] = b25 ^ (~b27 & b29); + s[34] = b34 ^ (~b36 & b38); + s[35] = b35 ^ (~b37 & b39); + s[44] = b44 ^ (~b46 & b48); + s[45] = b45 ^ (~b47 & b49); + s[6] = b6 ^ (~b8 & b0); + s[7] = b7 ^ (~b9 & b1); + s[16] = b16 ^ (~b18 & b10); + s[17] = b17 ^ (~b19 & b11); + s[26] = b26 ^ (~b28 & b20); + s[27] = b27 ^ (~b29 & b21); + s[36] = b36 ^ (~b38 & b30); + s[37] = b37 ^ (~b39 & b31); + s[46] = b46 ^ (~b48 & b40); + s[47] = b47 ^ (~b49 & b41); + s[8] = b8 ^ (~b0 & b2); + s[9] = b9 ^ (~b1 & b3); + s[18] = b18 ^ (~b10 & b12); + s[19] = b19 ^ (~b11 & b13); + s[28] = b28 ^ (~b20 & b22); + s[29] = b29 ^ (~b21 & b23); + s[38] = b38 ^ (~b30 & b32); + s[39] = b39 ^ (~b31 & b33); + s[48] = b48 ^ (~b40 & b42); + s[49] = b49 ^ (~b41 & b43); + s[0] ^= RC[n]; + s[1] ^= RC[n + 1]; + } +}; + +function WriteNumToArr0(body, Num) { + body[0] ^= Num & 0xFF; + body[1] ^= (Num >>> 8) & 0xFF; + body[2] ^= (Num >>> 16) & 0xFF; + body[3] ^= (Num >>> 24) & 0xFF; +}; + +function ClientHex(Str, nonce) { + var arr = [0, 0, 0, 0]; + for (var i = 0; i < Str.length; i++) + arr[4 + i] = Str.charCodeAt(i); + WriteNumToArr0(arr, nonce); + Mesh(arr, 60); + return global.GetHexFromArr(arr) + "-" + nonce; +}; +global.ClientHex = ClientHex; +var GlobalCryptID = 0; +var DeltaTimeCryptID = new Date(2018, 1, 1) as any - 0; + +function Encrypt(Arr, Arr2, ArrSecret) { + const StartLen = 9; + var arrRnd: any = Buffer.alloc(StartLen); + GlobalCryptID++; + arrRnd.writeUInt32LE(GlobalCryptID, 1, 4); + var Time = Math.floor((Date.now() - DeltaTimeCryptID) / 1000); + arrRnd.writeUInt32LE(Time, 5, 4); + Arr2[0] = Arr[0]; + for (var i = 1; i < StartLen; i++) + Arr2[i] = arrRnd[i]; + var SecretBuf = Buffer.concat([Arr2.slice(0, StartLen), ArrSecret]); + DoSecret(Arr, Arr2, SecretBuf, 9); +}; + +function Decrypt(Arr, Arr2, ArrSecret) { + const StartLen = 9; + var SecretBuf = Buffer.concat([Arr.slice(0, StartLen), ArrSecret]); + DoSecret(Arr, Arr2, SecretBuf, StartLen); +}; + +function DoSecret(Arr, Arr2, SecretBuf, StartLen) { + var CryptID = SecretBuf.readUInt32LE(1, 4); + var Pos = StartLen; + while (Pos < Arr.length) { + var CurBuf = global.shaarr(SecretBuf); + for (var i = 0; i < 32 && Pos < Arr.length; i++ , Pos++) { + Arr2[Pos] = Arr[Pos] ^ CurBuf[i]; + } + CryptID++; + SecretBuf.writeUInt32LE(CryptID, 5, 4); + } +}; + +function TestEncryptDecrypt() { + var ArrSecret = Buffer.from([1, 1, 1, 1, 1, 1]); + var Arr = GetArrFromStr(" Secret message", 64); + var Arr2 = Buffer.from(new Uint8Array(Arr.length)); + var Arr3 = Buffer.from(new Uint8Array(Arr.length)); + console.log("Message:"); + console.log(Arr); + console.log("-------------------"); + Encrypt(Arr, Arr2, ArrSecret); + console.log("Encrypt:"); + console.log(Arr2); + console.log("-------------------"); + Decrypt(Arr2, Arr3, ArrSecret); + console.log("Decrypt:"); + console.log(Utf8ArrayToStr(Arr3.slice(9))); +}; + +function toUTF8Array(str) { + var utf8 = []; + for (var i = 0; str && i < str.length; i++) { + var charcode = str.charCodeAt(i); + if (charcode < 0x80) + utf8.push(charcode); + else + if (charcode < 0x800) { + utf8.push(0xc0 | (charcode >> 6), 0x80 | (charcode & 0x3f)); + } + else + if (charcode < 0xd800 || charcode >= 0xe000) { + utf8.push(0xe0 | (charcode >> 12), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); + } + else { + i++; + charcode = 0x10000 + (((charcode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff)); + utf8.push(0xf0 | (charcode >> 18), 0x80 | ((charcode >> 12) & 0x3f), 0x80 | ((charcode >> 6) & 0x3f), 0x80 | (charcode & 0x3f)); + } + } + return utf8; +}; + +function Utf8ArrayToStr(array) { + var out, i, len, c; + var char2, char3; + out = ""; + len = array.length; + i = 0; + while (i < len) { + c = array[i++]; + switch (c >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + out += String.fromCharCode(c); + break; + case 12: + case 13: + char2 = array[i++]; + out += String.fromCharCode(((c & 0x1F) << 6) | (char2 & 0x3F)); + break; + case 14: + char2 = array[i++]; + char3 = array[i++]; + out += String.fromCharCode(((c & 0x0F) << 12) | ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); + break; + } + } + for (var i: any = 0; i < out.length; i++) { + if (out.charCodeAt(i) === 0) { + out = out.substr(0, i); + break; + } + } + return out; +}; + +function GetArr32FromStr(Str) { + return GetArrFromStr(Str, 32); +}; + +function GetArrFromStr(Str, Len) { + var arr = toUTF8Array(Str); + for (var i = arr.length; i < Len; i++) { + arr[i] = 0; + } + return arr.slice(0, Len); +}; +global.CalcHash3FromArray = CalcHash3FromArray; +global.CalcHashFromArray = CalcHashFromArray; +global.CalcMerklFromArray = CalcMerklFromArray; +global.CalcTreeHashFromArrBody = CalcTreeHashFromArrBody; +global.UpdateMerklTree = UpdateMerklTree; +global.GetMerkleProof = GetMerkleProof; +global.CheckMerkleProof = CheckMerkleProof; +global.IsZeroArr = IsZeroArr; +global.GetHashWithNonce = GetHashWithNonce; +global.GetPowPower = GetPowPower; +global.GetArrFromValue = GetArrFromValue; +global.GetPowValue = GetPowValue; +global.Mesh = Mesh; +global.Encrypt = Encrypt; +global.Decrypt = Decrypt; +global.toUTF8Array = toUTF8Array; +global.Utf8ArrayToStr = Utf8ArrayToStr; +global.GetArrFromStr = GetArrFromStr; +global.IsDeveloperAccount = function(Key) { + for (var i = 0; i < global.DEVELOP_PUB_KEY_ARR.length; i++) + if (global.CompareArr(Key, global.DEVELOP_PUB_KEY_ARR[i]) === 0) { + return 1; + } + return 0; +}; +global.DEVELOP_PUB_KEY_ARR = ["0222263942b11f7a78e11c43903094f870a2bf728bc8be085023b4eaf4e6228cd9", "02250c8c8f7f7e1468cdc5e9b9203841ba14250e2f480f77ebcd502f3e691506d8", + "027c0caec4e6f8f08d220f6dab24bb6f53d3f1d7b95231216805d9fac85d34a95f", "025defd5b884cc02f6948cd0d62b03d7b7445bf942206ab935158b6be8f0f7a2ce", + "024a97d69cd81c965f162b4b8b7b506263bc8aec8dbcea9eec59f73b5b470a0be1",]; +let DEVELOP_PUB_KEY_ARR: any = global.DEVELOP_PUB_KEY_ARR; +for (var i = 0; i < DEVELOP_PUB_KEY_ARR.length; i++) + DEVELOP_PUB_KEY_ARR[i] = Buffer.from(global.GetArrFromHex(DEVELOP_PUB_KEY_ARR[i])); +global.DEVELOP_PUB_KEY = DEVELOP_PUB_KEY_ARR[0]; +global.DEVELOP_PUB_KEY0 = Buffer.from(global.GetArrFromHex("022e80aa78bc07c72781fac12488096f0bfa7b4f48fbab0f2a92e208d1ee3654df")); +let LOCAL_RUN = global.LOCAL_RUN; +if (LOCAL_RUN) { + global.DEVELOP_PUB_KEY0 = Buffer.from(global.GetArrFromHex("026A04AB98D9E4774AD806E302DDDEB63BEA16B5CB5F223EE77478E861BB583EB3")); + global.DEVELOP_PUB_KEY = global.DEVELOP_PUB_KEY0; +} +global.ARR_PUB_KEY = ["027ae0dce92d8be1f893525b226695ddf0fe6ad756349a76777ff51f3b59067d70", "02769165a6f9950d023a415ee668b80bb96b5c9ae2035d97bdfb44f356175a44ff", + "021566c6feb5495594fc4bbea27795e1db5a663b3fe81ea9846268d5c394e24c23", "0215accbc993e67216c9b7f3912b29b91671864e861e61ab73589913c946839efa", + "0270e0c5acb8eefe7faddac45503da4885e02fb554975d12907f6c33ac6c6bdba5", "0202f2aad628f46d433faf70ba6bf12ab9ed96a46923b592a72508dc43af36cb80", + "0254f373fc44ac4a3e80ec8cb8cc3693a856caa82e0493067bdead78ce8ec354b8", "027617f9511b0b0cdbda8f3e17907732731296321846f3fd6fd19460f7227d9482", +]; +let GetHexFromArr = global.GetHexFromArr; +if (global.TEST_NETWORK || LOCAL_RUN) { + for (var i = 0; i < 100; i++) + global.ARR_PUB_KEY[i] = global.GetHexFromArr(global.DEVELOP_PUB_KEY0); + global.DEVELOP_PUB_KEY_ARR = [global.DEVELOP_PUB_KEY0]; + global.DEVELOP_PUB_KEY = DEVELOP_PUB_KEY_ARR[0]; +} diff --git a/src/core/db/block-db.ts b/src/core/db/block-db.ts new file mode 100644 index 0000000..aa4e785 --- /dev/null +++ b/src/core/db/block-db.ts @@ -0,0 +1,1026 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const fs = require('fs'); +const DBLib = require("./db"); +const DBRow = require("./db-row"); +global.BlockDB = new DBLib(); +global.BLOCK_HEADER_SIZE = 150; +const FILE_NAME_HEADER = "block-header"; +const FILE_NAME_BODY = "block-body"; +const FORMAT_STREAM_HEADER = "{\ + VersionDB:byte,\ + TreeHash:hash,\ + AddrHash:hash,\ + PrevHash:hash,\ + SumHash:hash,\ + SumPow:uint,\ + TrDataPos:uint,\ + TrDataLen:uint32,\ + Reserv500:uint\ + }"; +const WorkStructStreamHeader = {}; +global.BLOCK_HEADER_SIZE2 = 6; +const FORMAT_HEADER_VERSION2 = "{FilePos:uint}"; +const FILE_NAME_HEADER2 = "block-header2"; +const WorkStructHeader2 = {}; +const DEFAULT_DB_VERSION = 2; +module.exports = class CDB extends require("../code") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + var bWriteMode = (global.PROCESS_NAME === "MAIN"); + global.DB_VERSION = DEFAULT_DB_VERSION + var FileItem1 = BlockDB.OpenDBFile(FILE_NAME_HEADER, bWriteMode); + var FileItem2 = BlockDB.OpenDBFile(FILE_NAME_HEADER2, bWriteMode); + if (FileItem2.size) + global.DB_VERSION = 2 + else + if (FileItem1.size) + global.DB_VERSION = 1 + BlockDB.OpenDBFile(FILE_NAME_BODY, bWriteMode) + this.DBHeader100 = new DBRow("block-header100", 32 + 32, "{Hash100:hash,Hash:hash}", !bWriteMode) + this.BlockNumDB = 0 + this.BlockNumDBMin = 0 + this.ClearBufMap() + setTimeout(function() { + SERVER.ReadStateTX() + }, 10) + } + ReadStateTX() { + var StateTX = global.DApps.Accounts.DBStateTX.Read(0); + if (StateTX) { + this.BlockNumDBMin = StateTX.BlockNumMin + } + } + LoadMemBlocksOnStart() { + this.CurrentBlockNum = GetCurrentBlockNumByTime() + for (var i = this.BlockNumDB - BLOCK_COUNT_IN_MEMORY; i <= this.BlockNumDB; i++) + if (i >= 0) { + if (i >= this.BlockNumDB - BLOCK_PROCESSING_LENGTH * 5) + this.GetBlock(i, true, true) + else + this.GetBlock(i, true, false) + } + } + GetMaxNumBlockDB() { + var FileItem, BlockNum; + if (global.DB_VERSION === 2) { + FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER2) + BlockNum = (FileItem.size / BLOCK_HEADER_SIZE2) - 1 + } + else { + FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER) + BlockNum = (FileItem.size / BLOCK_HEADER_SIZE) - 1 + } + return BlockNum; + } + FindStartBlockNum() { + this.ReadStateTX() + var BlockNum = this.GetMaxNumBlockDB(); + if (global.NO_CHECK_BLOCKNUM_ONSTART) { + this.BlockNumDB = this.CheckBlocksOnStartFoward(BlockNum - 2, 0) + ToLog("START_BLOCK_NUM:" + this.BlockNumDB, 2) + return; + } + BlockNum = this.CheckBlocksOnStartReverse(BlockNum) + this.BlockNumDB = this.CheckBlocksOnStartFoward(BlockNum - 2000, 0) + this.BlockNumDB = this.CheckBlocksOnStartFoward(this.BlockNumDB - 100, 1) + if (this.BlockNumDB >= global.BLOCK_PROCESSING_LENGTH2) { + this.TruncateBlockDB(this.BlockNumDB) + } + ToLog("START_BLOCK_NUM:" + this.BlockNumDB, 2) + this.CheckOnStartComplete = 1 + } + CheckBlocksOnStartReverse(StartNum) { + var delta = 1; + var Count = 0; + var PrevBlock; + for (var num = StartNum; num >= this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2; num -= delta) { + var Block = this.ReadBlockHeaderDB(num); + if (!Block || IsZeroArr(Block.SumHash)) { + delta++ + Count = 0 + continue; + } + var PrevBlock = this.ReadBlockHeaderDB(num - 1); + if (!PrevBlock || IsZeroArr(PrevBlock.SumHash)) { + Count = 0 + continue; + } + var SumHash = shaarr2(PrevBlock.SumHash, Block.Hash); + if (global.CompareArr(SumHash, Block.SumHash) === 0) { + delta = 1 + Count++ + if (Count > COUNT_BLOCKS_FOR_LOAD / 10) + return num; + } + else { + delta++ + Count = 0 + } + } + return 0; + } + CheckBlocksOnStartFoward(StartNum, bCheckBody) { + var PrevBlock; + if (StartNum < this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) + StartNum = this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2 + var MaxNum = global.DApps.Accounts.GetHashedMaxBlockNum(); + var BlockNumTime = GetCurrentBlockNumByTime(); + if (BlockNumTime < MaxNum) + MaxNum = BlockNumTime + var arr = []; + for (var num = StartNum; num <= MaxNum; num++) { + var Block; + if (bCheckBody) + Block = this.ReadBlockDB(num) + else + Block = this.ReadBlockHeaderDB(num) + if (!Block) + return num > 0 ? num - 1 : 0; + if (num % 100000 === 0) + ToLog("CheckBlocksOnStartFoward: " + num) + if (bCheckBody) { + var TreeHash = CalcTreeHashFromArrBody(Block.BlockNum, Block.arrContent); + if (global.CompareArr(Block.TreeHash, TreeHash) !== 0) { + ToLog("BAD TreeHash block=" + Block.BlockNum) + return num > 0 ? num - 1 : 0; + } + } + if (PrevBlock) { + if (arr.length !== BLOCK_PROCESSING_LENGTH) { + var start = num - global.BLOCK_PROCESSING_LENGTH2; + for (var n = 0; n < BLOCK_PROCESSING_LENGTH; n++) { + var Prev = this.ReadBlockHeaderDB(start + n); + arr.push(Prev.Hash) + } + } + else { + arr.shift() + var Prev = this.ReadBlockHeaderDB(num - BLOCK_PROCESSING_LENGTH - 1); + arr.push(Prev.Hash) + } + var PrevHash = CalcHashFromArray(arr, true); + var SeqHash = this.GetSeqHash(Block.BlockNum, PrevHash, Block.TreeHash); + var Value = GetHashFromSeqAddr(SeqHash, Block.AddrHash, Block.BlockNum, PrevHash); + if (global.CompareArr(Value.Hash, Block.Hash) !== 0) { + ToLog("=================== FIND ERR Hash in " + Block.BlockNum + " bCheckBody=" + bCheckBody) + return num > 0 ? num - 1 : 0; + } + var SumHash = shaarr2(PrevBlock.SumHash, Block.Hash); + if (global.CompareArr(SumHash, Block.SumHash) !== 0) { + ToLog("=================== FIND ERR SumHash in " + Block.BlockNum) + return num > 0 ? num - 1 : 0; + } + } + PrevBlock = Block + } + return num > 0 ? num - 1 : 0; + } + WriteBlockDB(Block) { + var startTime = process.hrtime(); + if (Block.TrCount === 0 && !IsZeroArr(Block.TreeHash)) { + ToLogTrace("ERROR WRITE TrCount BLOCK:" + Block.BlockNum) + throw "ERROR WRITE"; + } + var Ret = this.WriteBodyDB(Block); + if (Ret) { + Ret = this.WriteBlockDBFinaly(Block) + } + ADD_TO_STAT_TIME("MAX:WriteBlockDB", startTime) + ADD_TO_STAT_TIME("WriteBlockDB", startTime) + return Ret; + } + WriteBlockDBFinaly(Block) { + var Ret = this.WriteBlockHeaderDB(Block); + if (Ret) { + if (Block.TrDataLen === 0 && !IsZeroArr(Block.TreeHash)) { + ToLogTrace("ERROR WRITE FINAL TrDataLen BLOCK") + throw "ERROR WRITE"; + } + this.OnWriteBlock(Block) + if (Block.BlockNum > this.BlockNumDBMin) + this.BlockNumDB = Block.BlockNum + Block.bSave = true + } + return Ret; + } + PreSaveDataTreeToDB(Block) { + var Ret = this.WriteBodyDB(Block); + if (Ret) { + Ret = this.WriteBlockHeaderDB(Block, 1) + } + return Ret; + } + WriteBodyResultDB(Block) { + var arrTr = Block.arrContentResult; + if (Block.TrDataPos && Block.TrDataLen && Block.VersionBody && arrTr && arrTr.length) { + var FileItem = BlockDB.OpenDBFile(FILE_NAME_BODY, 1); + var FD = FileItem.fd; + var Size = arrTr.length * 6; + var Position = Block.TrDataPos + Block.TrDataLen - Size; + if (FileItem.size < Position + Size) { + TO_ERROR_LOG("DB", 241, "Error Position in WriteBodyResultDB on block: " + Block.BlockNum) + return false; + } + var BufWrite = BufLib.GetNewBuffer(Size); + for (var i = 0; i < arrTr.length; i++) { + BufWrite.Write(arrTr[i], "uint") + } + var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position); + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB", 242, "Error write to file block-chain : " + written + " <> " + BufWrite.length) + return false; + } + } + return true; + } + WriteBodyDB(Block) { + var FileItem = BlockDB.OpenDBFile(FILE_NAME_BODY, 1); + var FD = FileItem.fd; + var Position = FileItem.size; + Block.TrDataPos = Position + var arrTr = Block.arrContent; + if (!arrTr || arrTr.length === 0) { + Block.TrCount = 0 + Block.TrDataLen = 0 + return true; + } + var TrDataLen = 4; + var arrSize = []; + for (var i = 0; i < arrTr.length; i++) { + var body = arrTr[i]; + arrSize[i] = 2 + body.length + TrDataLen += arrSize[i] + } + Block.VersionBody = 1 + TrDataLen += arrTr.length * 6 + var BufWrite = BufLib.GetNewBuffer(TrDataLen); + BufWrite.Write(arrTr.length, "uint16") + BufWrite.Write(Block.VersionBody, "uint16") + for (var i = 0; i < arrTr.length; i++) { + var body = arrTr[i]; + BufWrite.Write(body, "tr") + } + var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position); + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB", 240, "Error write to file block-chain : " + written + " <> " + BufWrite.length) + return false; + } + FileItem.size += TrDataLen + Block.TrCount = arrTr.length + Block.TrDataLen = TrDataLen + return true; + } + WriteBlockHeaderDB(Block, bPreSave) { + if (!bPreSave && Block.BlockNum > this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) { + if (USE_CHECK_SAVE_DB) + if (!this.CheckSeqHashDB(Block, "WriteBlockHeaderDB")) + return false; + this.WriteBlockHeader100(Block) + this.TruncateBlockDBInner(Block) + this.BlockNumDB = Block.BlockNum - 1 + var PrevBlock = this.ReadBlockHeaderDB(Block.BlockNum - 1); + if (!PrevBlock) { + ToLogTrace("Cant write header block:" + Block.BlockNum + " prev block not found") + throw "ERR: PREV BLOCK NOT FOUND"; + return false; + } + Block.SumHash = shaarr2(PrevBlock.SumHash, Block.Hash) + Block.SumPow = PrevBlock.SumPow + GetPowPower(Block.PowHash) + } + if (global.DB_VERSION === 2) { + return this.WriteBlockHeaderToFile2(Block); + } + var BufWrite = BufLib.GetNewBuffer(BLOCK_HEADER_SIZE); + this.BlockHeaderToBuf(BufWrite, Block) + var Res = this.WriteBufHeaderToFile1(BufWrite, Block.BlockNum); + return Res; + } + WriteBlockHeaderToFile2(Block) { + var BufWrite, FileItem, written; + var BlockNum = Math.trunc(Block.BlockNum); + this.ClearBufMap() + Block.VersionDB = global.DB_VERSION + BufWrite = BufLib.GetBufferFromObject(Block, FORMAT_STREAM_HEADER, 200, WorkStructStreamHeader) + FileItem = BlockDB.OpenDBFile(FILE_NAME_BODY, 1) + if (!Block.FilePos) { + if (!FileItem.size) + FileItem.size = 100 + Block.FilePos = FileItem.size + } + written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Block.FilePos) + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB", 242, "Error write to file block-chain : " + written + " <> " + BufWrite.length) + return false; + } + if (Block.FilePos >= FileItem.size) { + FileItem.size = Block.FilePos + BufWrite.length + } + FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1) + var Position = BlockNum * BLOCK_HEADER_SIZE2; + BufWrite = BufLib.GetBufferFromObject(Block, FORMAT_HEADER_VERSION2, BLOCK_HEADER_SIZE2, WorkStructHeader2) + written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Position) + if (Position >= FileItem.size) { + FileItem.size = Position + BufWrite.length + } + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB", 262, "Error write to file block-header :" + written + " <> " + BufWrite.length) + return false; + } + else { + return true; + } + } + WriteBufHeaderToFile1(BufWrite, BlockNum) { + BlockNum = Math.trunc(BlockNum) + this.ClearBufMap() + var FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER, 1); + var Position = BlockNum * BLOCK_HEADER_SIZE; + var written = fs.writeSync(FileItem.fd, BufWrite, 0, BufWrite.length, Position); + if (Position >= FileItem.size) { + FileItem.size = Position + BufWrite.length + } + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB", 260, "Error write to file block-header :" + written + " <> " + BufWrite.length) + return false; + } + else { + return true; + } + } + WriteBlockHeader100(Block) { + return; + if (Block.BlockNum % 100 !== 0) + return; + var Hash100; + var Num = Block.BlockNum / 100; + if (Num <= 0) { + Hash100 = [] + } + else { + var PrevHash100 = []; + var PrevData = this.DBHeader100.Read(Num - 1); + if (PrevData) { + PrevHash100 = PrevData.Hash100 + } + else + if (Num > 1) { + ToLog("NOT FIND PEVHASH100 BlockNum=" + Block.BlockNum, 2) + return; + } + Hash100 = sha3arr2(PrevHash100, Block.Hash) + } + this.DBHeader100.Write({ Num: Num, Hash100: Hash100, Hash: Block.Hash }) + } + TruncateBlockDBInner100(LastBlock) { + return; + this.DBHeader100.Truncate(Math.trunc(LastBlock.BlockNum / 100)) + } + ReadBlockDB(Num) { + if (!Num) + Num = 0 + Num = Math.trunc(Num) + var Block = this.ReadBlockHeaderDB(Num); + if (Block && Block.TrDataLen) { + var Ret = this.ReadBlockBodyDB(Block); + if (!Ret) + return undefined; + } + else { + if (Block && !IsZeroArr(Block.TreeHash)) { + ToLogTrace("ERROR arrContent on BlockNum=" + Num) + return undefined; + } + } + return Block; + } + ReadBlockBodyDB(Block) { + var FileItem = BlockDB.OpenDBFile(FILE_NAME_BODY); + if (Block.TrDataLen > MAX_BLOCK_SIZE * 2) { + ToLogTrace("Error value TrDataLen, BlockNum=" + Block.BlockNum) + return false; + } + var Position = Block.TrDataPos; + var BufRead = BufLib.GetNewBuffer(Block.TrDataLen); + var bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position); + if (bytesRead !== BufRead.length) { + TO_ERROR_LOG("DB", 272, "Error read block-body file: " + FileItem.name + " from POS:" + Position + " bytesRead=" + bytesRead + " of " + BufRead.length + " BlockNum=" + Block.BlockNum) + return false; + } + Block.arrContent = [] + Block.arrContentResult = [] + var TrCount = BufRead.Read("uint16"); + Block.VersionBody = BufRead.Read("uint16") + if (TrCount <= MAX_TRANSACTION_COUNT) { + for (var i = 0; i < TrCount; i++) { + var body = BufRead.Read("tr"); + if (!body) + break; + Block.arrContent[i] = body + } + if (Block.VersionBody === 1) { + var Size = TrCount * 6; + BufRead.len = Block.TrDataLen - Size + for (var i = 0; i < TrCount; i++) { + Block.arrContentResult[i] = BufRead.Read("uint") + } + } + } + Block.TrCount = Block.arrContent.length + return true; + } + ReadBlockHeaderDB(BlockNum) { + if (global.DB_VERSION === 2) { + return this.ReadBlockHeaderDB2(BlockNum); + } + if (BlockNum < 0) { + return undefined; + } + BlockNum = Math.trunc(BlockNum) + var Block, BufRead, FileItem, bytesRead, Position; + BufRead = BufLib.GetNewBuffer(BLOCK_HEADER_SIZE) + Position = BlockNum * BLOCK_HEADER_SIZE + var FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER); + bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) + if (bytesRead !== BufRead.length) + return undefined; + Block = this.BufToBlockHeader(BufRead, BlockNum) + if (Block) { + Block.bSave = true + Block.Prepared = true + } + return Block; + } + ReadBlockHeaderDB2(BlockNum) { + var Block, BufRead, FileItem, bytesRead, Position; + if (BlockNum < 0) { + return undefined; + } + BlockNum = Math.trunc(BlockNum) + Position = BlockNum * BLOCK_HEADER_SIZE2 + FileItem = BlockDB.OpenDBFile(FILE_NAME_HEADER2) + BufRead = BufLib.GetNewBuffer(BLOCK_HEADER_SIZE2) + bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) + if (bytesRead !== BufRead.length) + return undefined; + Block = BufLib.GetObjectFromBuffer(BufRead, FORMAT_HEADER_VERSION2, WorkStructHeader2) + if (!Block.FilePos) { + return undefined; + } + Position = Block.FilePos + FileItem = BlockDB.OpenDBFile(FILE_NAME_BODY) + BufRead = BufLib.GetNewBuffer(200) + bytesRead = fs.readSync(FileItem.fd, BufRead, 0, BufRead.length, Position) + Block = BufLib.GetObjectFromBuffer(BufRead, FORMAT_STREAM_HEADER, WorkStructStreamHeader) + if (Block.VersionDB !== global.DB_VERSION) { + throw ("ERROR Block.VersionDB"); + return undefined; + } + Block.FilePos = Position + Block.VersionDB = global.DB_VERSION + Block.bSave = true + Block.Prepared = true + return this.PrepareBlockFields(Block, BlockNum); + } + ReadBlockHeaderFromMapDB(BlockNum) { + var Block = this.MapHeader[BlockNum]; + if (!Block) { + Block = this.ReadBlockHeaderDB(BlockNum) + this.MapHeader[BlockNum] = Block + } + return Block; + } + SetTruncateBlockDB(BlockNum) { + BlockNum = Math.trunc(BlockNum) + if (BlockNum < global.BLOCK_PROCESSING_LENGTH2) + BlockNum = global.BLOCK_PROCESSING_LENGTH2 + if (this.UseTruncateBlockDB) { + if (BlockNum < this.UseTruncateBlockDB) + this.UseTruncateBlockDB = BlockNum + } + else { + this.UseTruncateBlockDB = BlockNum + } + } + TruncateBlockDB(LastBlockNum) { + this.UseTruncateBlockDB = undefined + var Block = this.ReadBlockDB(LastBlockNum); + if (!Block) { + ToLog("************ ERROR TruncateBlockDB - not found block=" + LastBlockNum, 2) + return; + } + this.WriteBlockDB(Block) + } + TruncateBlockDBInner(LastBlock) { + var FItem1, size; + if (global.DB_VERSION === 2) { + FItem1 = BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1) + size = (LastBlock.BlockNum + 1) * BLOCK_HEADER_SIZE2 + } + else { + FItem1 = BlockDB.OpenDBFile(FILE_NAME_HEADER, 1) + size = (LastBlock.BlockNum + 1) * BLOCK_HEADER_SIZE + } + if (size < 0) + size = 0 + if (FItem1.size > size) { + FItem1.size = size + fs.ftruncateSync(FItem1.fd, FItem1.size) + } + this.TruncateStat(LastBlock.BlockNum) + this.TruncateBlockDBInner100(LastBlock) + } + ClearDataBase() { + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) + global.TX_PROCESS.RunRPC("ClearDataBase", {}) + var FItem1 = BlockDB.OpenDBFile(FILE_NAME_HEADER, 1); + FItem1.size = 0 + fs.ftruncateSync(FItem1.fd, FItem1.size) + var FItem12 = BlockDB.OpenDBFile(FILE_NAME_HEADER2, 1); + FItem12.size = 0 + fs.ftruncateSync(FItem12.fd, FItem12.size) + var FItem2 = BlockDB.OpenDBFile(FILE_NAME_BODY, 1); + FItem2.size = 0 + fs.ftruncateSync(FItem2.fd, FItem2.size) + this.DBHeader100.Truncate(- 1) + global.DB_VERSION = DEFAULT_DB_VERSION + this.BlockNumDB = 0 + this.BlockNumDBMin = 0 + this.ClearBufMap() + this.ClearStat() + this.CreateGenesisBlocks() + this.StartSyncBlockchain() + } + ClearBufMap() { + this.MapHeader = {} + } + Close() { + this.ClearBufMap() + this.ReadStateTX() + BlockDB.CloseDBFile(FILE_NAME_HEADER) + BlockDB.CloseDBFile(FILE_NAME_HEADER2) + BlockDB.CloseDBFile(FILE_NAME_BODY) + this.DBHeader100.Close() + } + RewriteAllTransactions() { + if (TX_PROCESS.Worker) { + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) { + global.TX_PROCESS.RunRPC("RewriteAllTransactions", {}) + return 1; + } + } + return 0; + } + BlockHeaderToBuf(BufWrite, Block) { + Block.Reserv500 = 0 + var len = BufWrite.len; + BufWrite.Write(Block.TreeHash, "hash") + BufWrite.Write(Block.AddrHash, "hash") + BufWrite.Write(Block.PrevHash, "hash") + BufWrite.Write(Block.SumHash, "hash") + BufWrite.Write(Block.SumPow, "uint") + BufWrite.Write(Block.Reserv500, "uint") + BufWrite.Write(Block.TrDataPos, "uint") + BufWrite.Write(Block.TrDataLen, "uint32") + BufWrite.len = len + BLOCK_HEADER_SIZE + } + BufToBlockHeader(BufRead, Num) { + var Block = {}; + var len = BufRead.len; + Block.TreeHash = BufRead.Read("hash") + Block.AddrHash = BufRead.Read("hash") + Block.PrevHash = BufRead.Read("hash") + Block.SumHash = BufRead.Read("hash") + Block.SumPow = BufRead.Read("uint") + Block.Reserv500 = BufRead.Read("uint") + Block.TrDataPos = BufRead.Read("uint") + Block.TrDataLen = BufRead.Read("uint32") + Block.TrCount = 0 + BufRead.len = len + BLOCK_HEADER_SIZE + return this.PrepareBlockFields(Block, Num); + } + PrepareBlockFields(Block, Num) { + Block.AddInfo = AddInfoBlock.bind(Block) + Block.Info = "" + Block.BlockNum = Num + Block.SeqHash = this.GetSeqHash(Block.BlockNum, Block.PrevHash, Block.TreeHash) + if (Block.BlockNum >= global.BLOCK_PROCESSING_LENGTH2) { + CalcHashBlockFromSeqAddr(Block) + } + else { + Block.Hash = this.GetHashGenesis(Block.BlockNum) + Block.PowHash = Block.Hash + } + Block.Power = GetPowPower(Block.PowHash) + if (IsZeroArr(Block.Hash)) + return undefined; + return Block; + } + GetRows(start, count, Filter, bMinerName) { + if (Filter) { + Filter = Filter.trim() + Filter = Filter.toUpperCase() + } + var MaxAccount = global.DApps.Accounts.GetMaxAccount(); + var WasError = 0; + var arr = []; + for (var num = start; true; num++) { + var Block = this.ReadBlockHeaderDB(num); + if (!Block) + break; + Block.Num = Block.BlockNum + if (Block.AddrHash) { + Block.Miner = ReadUintFromArr(Block.AddrHash, 0) + if (Block.BlockNum < 16 || Block.Miner > MaxAccount) + Block.Miner = 0 + if (bMinerName && Block.Miner) { + var Item = global.DApps.Accounts.ReadState(Block.Miner); + if (Item && Item.Name) + Block.MinerName = Item.Name.substr(0, 8) + else + Block.MinerName = "" + } + var Value = GetHashFromSeqAddr(Block.SeqHash, Block.AddrHash, Block.BlockNum, Block.PrevHash); + Block.Hash1 = Value.Hash1 + Block.Hash2 = Value.Hash2 + } + if (Filter) { + var Num = Block.BlockNum; + var Bytes = Block.TrDataLen; + var Pow = Block.Power; + var Miner = Block.Miner; + var Date = DateFromBlock(Block.BlockNum); + try { + if (!eval(Filter)) + continue; + } + catch (e) { + if (!WasError) + ToLog(e) + WasError = 1 + } + } + arr.push(Block) + count-- + if (count < 1) + break; + } + return arr; + } + GetTrRows(BlockNum, start, count) { + var arr = []; + var Block = this.ReadBlockDB(BlockNum); + if (Block && Block.arrContent) + for (var num = start; num < start + count; num++) { + if (num < 0) + continue; + if (num >= Block.arrContent.length) + break; + var Tr = { body: Block.arrContent[num] }; + this.CheckCreateTransactionObject(Tr, 1) + Tr.Num = num + Tr.Type = Tr.body[0] + Tr.Length = Tr.body.length + Tr.Body = [] + for (var j = 0; j < Tr.body.length; j++) + Tr.Body[j] = Tr.body[j] + var App = DAppByType[Tr.Type]; + if (App) { + Tr.Script = App.GetScriptTransaction(Tr.body) + if (BlockNum >= this.BlockNumDBMin) + Tr.Verify = App.GetVerifyTransaction(Block, BlockNum, Tr.Num, Tr.body) + else + Tr.Verify = 0 + if (Tr.Verify >= 1) { + Tr.VerifyHTML = "✔" + if (Tr.Verify > 1) { + Tr.VerifyHTML += "(" + Tr.Verify + ")" + } + } + else + if (Tr.Verify == - 1) + Tr.VerifyHTML = "✘" + else + Tr.VerifyHTML = "" + } + else { + Tr.Script = "" + Tr.VerifyHTML = "" + } + arr.push(Tr) + } + return arr; + } + ClearStat() { + var MAX_ARR_PERIOD = MAX_STAT_PERIOD * 2 + 10; + this.StatMap = { + StartPos: 0, StartBlockNum: 0, Length: 0, "ArrPower": new Float64Array(MAX_ARR_PERIOD), "ArrPowerMy": new Float64Array(MAX_ARR_PERIOD), + } + } + TruncateStat(LastBlockNum) { + if (this.StatMap) { + var LastNumStat = this.StatMap.StartBlockNum + this.StatMap.Length; + var Delta = LastNumStat - LastBlockNum; + if (Delta > 0) { + this.StatMap.Length -= Delta + if (this.StatMap.Length < 0) + this.StatMap.Length = 0 + } + this.StatMap.CaclBlockNum = 0 + } + } + GetStatBlockchainPeriod(Param) { + var StartNum = Param.BlockNum; + if (!Param.Count || Param.Count < 0) + Param.Count = 1000 + if (!Param.Miner) + Param.Miner = 0 + if (!Param.Adviser) + Param.Adviser = 0 + var Map = {}; + var ArrList = new Array(Param.Count); + var i = 0; + for (var num = StartNum; num < StartNum + Param.Count; num++) { + var Power = 0, PowerMy = 0, Nonce = 0; + if (num <= this.BlockNumDB) { + var Block = this.ReadBlockHeaderDB(num); + if (Block) { + Power = GetPowPower(Block.PowHash) + var Miner = ReadUintFromArr(Block.AddrHash, 0); + var Nonce = ReadUintFromArr(Block.AddrHash, 6); + if (Param.Miner < 0) { + if (Param.Adviser) { + var Adviser = global.DApps.Accounts.GetAdviserByMiner(Map, Miner); + if (Adviser === Param.Adviser) + PowerMy = Power + } + else { + PowerMy = Power + } + } + else + if (Miner === Param.Miner && !Param.bMinerLess) { + PowerMy = Power + } + else + if (Miner <= Param.Miner && Param.bMinerLess) { + PowerMy = Power + } + } + } + ArrList[i] = PowerMy + if (Param.bNonce && PowerMy) + ArrList[i] = Nonce + i++ + } + var AvgValue = 0; + for (var j = 0; j < ArrList.length; j++) { + if (ArrList[j]) + AvgValue += ArrList[j] + } + if (ArrList.length > 0) + AvgValue = AvgValue / ArrList.length + const MaxSizeArr = 1000; + var StepTime = 1; + while (ArrList.length >= MaxSizeArr) { + if (Param.bNonce) + ArrList = ResizeArrMax(ArrList) + else + ArrList = ResizeArrAvg(ArrList) + StepTime = StepTime * 2 + } + return { ArrList: ArrList, AvgValue: AvgValue, steptime: StepTime }; + } + GetStatBlockchain(name, MinLength) { + if (!MinLength) + return []; + var MAX_ARR_PERIOD = MAX_STAT_PERIOD * 2 + 10; + if (!this.StatMap) { + this.ClearStat() + } + var MaxNumBlockDB = this.GetMaxNumBlockDB(); + if (this.StatMap.CaclBlockNum !== MaxNumBlockDB || this.StatMap.CalcMinLength !== MinLength) { + this.StatMap.CaclBlockNum = MaxNumBlockDB + this.StatMap.CalcMinLength = MinLength + var start = MaxNumBlockDB - MinLength + 1; + var finish = MaxNumBlockDB + 1; + var StartPos = this.StatMap.StartPos; + var ArrPower = this.StatMap.ArrPower; + var ArrPowerMy = this.StatMap.ArrPowerMy; + var StartNumStat = this.StatMap.StartBlockNum; + var FinishNumStat = this.StatMap.StartBlockNum + this.StatMap.Length - 1; + var CountReadDB = 0; + var arr = new Array(MinLength); + var arrmy = new Array(MinLength); + for (var num = start; num < finish; num++) { + var i = num - start; + var i2 = (StartPos + i) % MAX_ARR_PERIOD; + if (num >= StartNumStat && num <= FinishNumStat && (num < finish - 10)) { + arr[i] = ArrPower[i2] + arrmy[i] = ArrPowerMy[i2] + } + else { + CountReadDB++ + var Power = 0, PowerMy = 0; + if (num <= MaxNumBlockDB) { + var Block = this.ReadBlockHeaderDB(num); + if (Block) { + Power = GetPowPower(Block.PowHash) + var Miner = ReadUintFromArr(Block.AddrHash, 0); + if (Miner === GENERATE_BLOCK_ACCOUNT) { + PowerMy = Power + } + } + } + arr[i] = Power + arrmy[i] = PowerMy + ArrPower[i2] = arr[i] + ArrPowerMy[i2] = arrmy[i] + if (num > FinishNumStat) { + this.StatMap.StartBlockNum = num - this.StatMap.Length + this.StatMap.Length++ + if (this.StatMap.Length > MAX_ARR_PERIOD) { + this.StatMap.Length = MAX_ARR_PERIOD + this.StatMap.StartBlockNum++ + this.StatMap.StartPos++ + } + } + } + } + this.StatMap["POWER_BLOCKCHAIN"] = arr + this.StatMap["POWER_MY_WIN"] = arrmy + } + var arr = this.StatMap[name]; + if (!arr) + arr = [] + var arrT = this.StatMap["POWER_BLOCKCHAIN"]; + for (var i = 0; i < arrT.length; i++) + if (!arrT[i]) { + this.StatMap = undefined + break; + } + return arr; + } + GetHashGenesis(Num) { + return [Num + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Num + 1]; + } + GetSeqHash(BlockNum, PrevHash, TreeHash) { + var arr = [GetArrFromValue(BlockNum), PrevHash, TreeHash]; + var SeqHash = CalcHashFromArray(arr, true); + return SeqHash; + } + CheckCreateTicketObject(Tr, BlockNum, SetTxID) { + if (!Tr.HashPow && Tr.HashTicket) { + Tr.num = BlockNum + var FullHashTicket = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (var i = 0; i < global.TR_TICKET_HASH_LENGTH; i++) + FullHashTicket[i] = Tr.HashTicket[i] + WriteUintToArrOnPos(FullHashTicket, Tr.num, global.TR_TICKET_HASH_LENGTH) + Tr.HashPow = global.sha3(FullHashTicket) + Tr.power = GetPowPower(Tr.HashPow) + Tr.TimePow = Tr.power + if (SetTxID) + Tr.TxID = GetHexFromArr(FullHashTicket.slice(0, TR_TICKET_HASH_LENGTH + 6)) + } + } + CheckCreateTransactionObject(Tr, SetTxID, NotPrioritet) { + if (!Tr.HashPow) { + var Body = Tr.body; + Tr.IsTx = 1 + Tr.num = ReadUintFromArr(Body, Body.length - 12) + if (Tr.num >= global.BLOCKNUM_TICKET_ALGO) + Tr.HASH = global.sha3(Body) + else + Tr.HASH = global.shaarr(Body) + Tr.HashTicket = Tr.HASH.slice(0, global.TR_TICKET_HASH_LENGTH) + this.CheckCreateTicketObject(Tr, Tr.num, SetTxID) + Tr.Prioritet = MAX_LENGTH_SENDER_MAP + if (!NotPrioritet && this.GetSenderPrioritet) { + var App = DAppByType[Body[0]]; + if (App) { + Tr.SenderNum = App.GetSenderNum(Tr.num, Body) + if (Tr.SenderNum && Tr.SenderNum > 0) { + Tr.Prioritet = this.GetSenderPrioritet(Tr.num, Tr.SenderNum) + Tr.TimePow = Tr.Prioritet + Tr.power + } + } + } + } + } + BlockChainToBuf(WriteNum, StartNum, EndBlockNum) { + if (StartNum === undefined) + return BufLib.GetNewBuffer(10); + var GetLength = EndBlockNum - StartNum + 1; + var arr = []; + var arr0 = this.PrevBlockChainArr; + if (arr0 && arr0.length) { + var Block = arr0[arr0.length - 1]; + if (Block.BlockNum >= StartNum && Block.BlockNum <= EndBlockNum) { + var BlockDB = this.ReadBlockHeaderDB(Block.BlockNum); + if (!BlockDB || global.CompareArr(Block.SumHash, BlockDB.SumHash) !== 0) { + arr0 = undefined + } + else { + } + } + } + var i0 = 0; + for (var num = StartNum; num <= EndBlockNum; num++) { + var Block = undefined; + if (arr0) { + for (var i = i0; i < arr0.length; i++) { + i0 = i + var Block0 = arr0[i]; + if (Block0.BlockNum === num) { + Block = Block0 + break; + } + } + } + if (!Block) + Block = this.ReadBlockHeaderDB(num) + if (!Block || !Block.Prepared || !Block.Hash) + break; + arr.push(Block) + } + this.PrevBlockChainArr = arr + return this.ArrHeaderToBuf(WriteNum, arr); + } + ArrHeaderToBuf(StartNum, arr) { + var CountSend = arr.length - global.BLOCK_PROCESSING_LENGTH2; + var BufWrite; + if (CountSend <= 0) { + BufWrite = BufLib.GetNewBuffer(10) + } + else { + var BufSize = 6 + 4 + global.BLOCK_PROCESSING_LENGTH2 * 32 + 32 + 6 + CountSend * 64; + BufWrite = BufLib.GetNewBuffer(BufSize) + BufWrite.Write(StartNum, "uint") + BufWrite.Write(CountSend, "uint32") + for (var i = 0; i < arr.length; i++) { + var Block = arr[i]; + if (i < global.BLOCK_PROCESSING_LENGTH2) { + BufWrite.Write(Block.Hash, "hash") + } + else { + if (i === global.BLOCK_PROCESSING_LENGTH2) { + BufWrite.Write(Block.SumHash, "hash") + BufWrite.Write(Block.SumPow, "uint") + } + BufWrite.Write(Block.TreeHash, "hash") + BufWrite.Write(Block.AddrHash, "hash") + } + } + } + return BufWrite; + } +}; + +function AddInfo(Block, Str, BlockNumStart) { + if (!global.STAT_MODE) + return; + if (!Block.Info) + Block.Info = Str; + else + if (Block.Info.length < 2000) { + var timesend = "" + SERVER.CurrentBlockNum - BlockNumStart; + var now = GetCurrentTime(); + timesend += ".[" + now.getSeconds().toStringZ(2) + "." + now.getMilliseconds().toStringZ(3) + "]"; + Str = timesend + ": " + Str; + Block.Info += "\n" + Str; + } +}; +global.AddInfoChain = function(Str) { + if (!global.STAT_MODE) + return; + if (this.BlockNumStart > GetCurrentBlockNumByTime() - HISTORY_BLOCK_COUNT) + AddInfo(this, Str, this.BlockNumStart); +}; +global.AddInfoBlock = function(Block, Str) { + if (!global.STAT_MODE) + return; + if (Block && Block.BlockNum && Block.BlockNum > GetCurrentBlockNumByTime() - HISTORY_BLOCK_COUNT) + AddInfo(Block, Str, Block.BlockNum); +}; +global.GetNodeStrPort = function(Node) { + if (!Node) + return ""; + if (LOCAL_RUN) + return "" + Node.port; + else { + if (!Node.ip) + return ""; + var arr = Node.ip.split("."); + return "" + arr[2] + "." + arr[3]; + } +}; diff --git a/src/core/db/db-row.ts b/src/core/db/db-row.ts new file mode 100644 index 0000000..61c876e --- /dev/null +++ b/src/core/db/db-row.ts @@ -0,0 +1,229 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as fs from 'fs' + +module.exports = class CDBState extends require("./db") +{ + private FileName; + private DataSize; + private Format; + private WorkStruct; + private FileNameFull; + private LastHash; + private WasUpdate; + private BufMap; + private BufMapCount; + + constructor(FileName, DataSize, Format, bReadOnly) { + super() + this.FileName = FileName + this.DataSize = DataSize + this.Format = Format + this.WorkStruct = {} + var FI = this.OpenDBFile(this.FileName, !bReadOnly); + this.FileNameFull = FI.fname + this.LastHash = undefined + this.WasUpdate = 1 + this.BufMap = {} + this.BufMapCount = 0 + setInterval(this.CheckBufMap.bind(this), 1000) + } + GetMaxNum() { + var FI = this.OpenDBFile(this.FileName); + var Num = Math.floor(FI.size / this.DataSize) - 1; + return Num; + } + CheckNewNum(Data) { + if (Data.Num === undefined) + Data.Num = this.GetMaxNum() + 1 + } + Write(Data, RetBuf) { + var startTime = process.hrtime(); + this.LastHash = undefined + this.WasUpdate = 1 + this.CheckNewNum(Data) + Data.Num = Math.trunc(Data.Num) + this.DeleteMap(Data.Num) + var BufWrite = global.BufLib.GetBufferFromObject(Data, this.Format, this.DataSize, this.WorkStruct, 1); + var Position = Data.Num * this.DataSize; + var FI = this.OpenDBFile(this.FileName, 1); + var written = fs.writeSync(FI.fd, BufWrite, 0, BufWrite.length, Position); + if (written !== BufWrite.length) { + global.TO_ERROR_LOG("DB-ROW", 10, "Error write to file:" + written + " <> " + BufWrite.length) + return false; + } + if (RetBuf) { + RetBuf.Buf = BufWrite + } + if (Position >= FI.size) { + FI.size = Position + this.DataSize + } + global.ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime) + global.ADD_TO_STAT("ROWS_WRITE") + return true; + } + Read(Num, GetBufOnly?) { + Num = Math.trunc(Num) + var Data; + if (isNaN(Num) || Num < 0 || Num > this.GetMaxNum()) { + return undefined; + } + var BufRead = this.GetMap(Num); + if (!BufRead) { + BufRead = global.BufLib.GetNewBuffer(this.DataSize) + var Position = Num * this.DataSize; + var FI = this.OpenDBFile(this.FileName); + var bytesRead = fs.readSync(FI.fd, BufRead, 0, BufRead.length, Position); + if (bytesRead !== BufRead.length) + return undefined; + this.SetMap(Num, BufRead) + } + if (GetBufOnly) { + return BufRead; + } + try { + Data = global.BufLib.GetObjectFromBuffer(BufRead, this.Format, this.WorkStruct) + } + catch (e) { + global.ToLog("DBROW:" + e) + return undefined; + } + Data.Num = Num + return Data; + } + GetRows(start, count) { + var arr = []; + for (var num = start; num < start + count; num++) { + var Data = this.Read(num); + if (!Data) + break; + arr.push(Data) + } + return arr; + } + Truncate(LastNum) { + var startTime = process.hrtime(); + LastNum = Math.trunc(LastNum) + var Position = (LastNum + 1) * this.DataSize; + if (Position < 0) + Position = 0 + var FI = this.OpenDBFile(this.FileName, 1); + if (Position < FI.size) { + this.LastHash = undefined + this.WasUpdate = 1 + if (LastNum < 0) + global.ToLog("Truncate " + this.FileName + " from 0", 2) + FI.size = Position + fs.ftruncateSync(FI.fd, FI.size) + this.BufMap = {} + this.BufMapCount = 0 + } + global.ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime) + } + DeleteHistory(BlockNumFrom) { + var MaxNum = this.GetMaxNum(); + if (MaxNum === - 1) + return; + for (var num = MaxNum; num >= 0; num--) { + var ItemCheck = this.Read(num); + if (!ItemCheck) + break; + if (ItemCheck.BlockNum < BlockNumFrom) { + if (num < MaxNum) { + this.Truncate(num) + } + return; + } + } + this.Truncate(- 1) + } + FastFindBlockNum(BlockNum) { + var MaxNum = this.GetMaxNum(); + if (MaxNum === - 1) + return; + var StartNum = 0; + var EndNum = MaxNum; + var CurNum = Math.trunc(MaxNum / 2); + while (true) { + var Item = this.Read(CurNum); + if (Item) { + if (Item.BlockNum > BlockNum) { + EndNum = CurNum - 1 + var Delta = CurNum - StartNum; + if (Delta === 0) + return "NoHistory"; + Delta = Math.trunc((1 + Delta) / 2) + CurNum = CurNum - Delta + } + else + if (Item.BlockNum < BlockNum) { + StartNum = CurNum + 1 + var Delta = EndNum - CurNum; + if (Delta === 0) + return "NoPresent"; + Delta = Math.trunc((1 + Delta) / 2) + CurNum = CurNum + Delta + } + else + if (Item.BlockNum === BlockNum) + break; + } + else { + throw "Error read num"; + return; + } + } + var num = CurNum; + while (true) { + num-- + if (num < 0) + return CurNum; + var Item = this.Read(num); + if (Item) { + if (Item.BlockNum === BlockNum) + CurNum = num + else + return CurNum; + } + else { + throw "Error read num"; + return; + } + } + } + SetMap(Num, Value) { + this.BufMap[Num] = Value + this.BufMapCount++ + } + GetMap(Num) { + return this.BufMap[Num]; + } + DeleteMap(Num) { + if (this.BufMap[Num]) { + delete this.BufMap[Num] + this.BufMapCount-- + } + } + CheckBufMap() { + if (this.BufMapCount > 1000) { + this.ClearBufMap() + } + } + ClearBufMap() { + this.BufMap = {} + this.BufMapCount = 0 + } + Close() { + this.ClearBufMap() + this.CloseDBFile(this.FileName) + } +}; diff --git a/src/core/db/db.ts b/src/core/db/db.ts new file mode 100644 index 0000000..e439963 --- /dev/null +++ b/src/core/db/db.ts @@ -0,0 +1,106 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as fs from 'fs' + +module.exports = class { + private DBMap; + private LastHash; + private WasUpdate; + private WasCheckPathDB; + + constructor() { + this.DBMap = {} + } + CheckPathDB() { + var Path = global.global.GetDataPath("DB"); + global.global.CheckCreateDir(Path) + } + CloseDBFile(name, bdelete) { + this.LastHash = undefined + this.WasUpdate = 1 + var Item = this.DBMap[name]; + if (Item) { + let bDelete = bdelete; + let Name = name; + fs.close(Item.fd, function(err) { + if (!err) { + if (bDelete) { + var fname = global.global.GetDataPath("DB/" + Name); + fs.unlink(fname, function(err) { + if (err) + global.ToLog(err) + }) + } + } + else { + global.ToLog(err) + } + }) + delete this.DBMap[name] + } + } + OpenDBFile(name, bWrite, bExist) { + if (bWrite && global.READ_ONLY_DB) { + global.ToLogTrace("CANNOT WRITE - DB IN READ_ONLY MODE!!!") + process.exit() + } + if (bWrite) + CheckStartOneProcess(name + "-run") + this.LastHash = undefined + this.WasUpdate = 1 + var Item = this.DBMap[name]; + if (Item === undefined) { + if (!this.WasCheckPathDB) { + this.CheckPathDB() + this.WasCheckPathDB = true + } + var fname = global.global.GetDataPath("DB/" + name); + if (!fs.existsSync(fname)) { + if (bExist) { + this.DBMap[name] = null + return null; + } + var fd = fs.openSync(fname, "w+"); + fs.closeSync(fd) + } + var fd = fs.openSync(fname, "r+"); + var stat = fs.statSync(fname); + var size = stat.size; + Item = { name: name, fname: fname, fd: fd, size: size, FillRows: 0, CountRows: 0, } + this.DBMap[name] = Item + } + return Item; + } +}; +var MapCheckProcess = {}; +var BlockDB = new module.exports(); + +function CheckStartOneProcess(Name) { + if (global.UpdateMode) + return; + if (global.READ_ONLY_DB || MapCheckProcess[Name]) + return; + MapCheckProcess[Name] = 1; + var path = global.global.GetDataPath("DB/" + Name); + if (fs.existsSync(path)) { + fs.unlinkSync(path); + } + try { + BlockDB.OpenDBFile(Name); + } + catch (e) { + global.ToLog("****** DETECT START ANOTHER PROCESS for: " + Name); + global.ToLogTrace("EXIT"); + process.exit(); + } +}; +global.CheckStartOneProcess = CheckStartOneProcess; diff --git a/src/core/geo.ts b/src/core/geo.ts new file mode 100644 index 0000000..d0cdf89 --- /dev/null +++ b/src/core/geo.ts @@ -0,0 +1,77 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +import * as fs from 'fs' +import './library' + +var BufIP; +var MapNames = {}, FileIp = "./SITE/DB/iplocation.db", FileNames = "./SITE/DB/locationnames.csv", Format = "{Value:uint32,Length:uint32, id:uint32, latitude:uint32, longitude:uint32}", + FormatStruct = {}; + +function SetGeoLocation(e) { + if (!e.ip || !BufIP || !BufIP.length) + return !1; + var t = IPToUint(e.ip), i = FindItem(BufIP, 20, t); + return i && (e.latitude = i.latitude, e.longitude = i.longitude, e.name = MapNames[i.id]), e.Geo = 1, !0; +}; + +function ReadItem(e, t) { + return BufIP.len = e * t, global.BufLib.Read(BufIP, Format, void 0, FormatStruct); +}; + +function FindItem(e, t, i) { + var n, r = Math.trunc(e.length / t), a = (ReadItem(0, t), ReadItem(r, t), 0), u = r, o = Math.trunc(i * r / 4294967296); + r <= o && (o = r - 1), o < a && (o = a); + for (var f = 40; 0 < f;) { + if (f-- , !(n = ReadItem(o, t))) + return void global.ToLog("GEO FindItem - Error read num: " + o); + if (n.Value > i) { + if (u = o - 1, 0 === (l = o - a)) + return; + o -= l = Math.trunc((1 + l) / 2); + } + else + if (n.Value < i) { + if (n.Value + n.Length >= i) + return n; + var l; + if (a = o + 1, 0 === (l = u - o)) + return; + o += l = Math.trunc((1 + l) / 2); + } + else + if (n.Value === i) + return n; + } +}; + +function Init() { + if (fs.existsSync(FileIp) && fs.existsSync(FileNames)) { + BufIP = fs.readFileSync(FileIp); + for (var e = fs.readFileSync(FileNames), t = 0; ;) { + var i = e.indexOf("\n", t); + if (i < 0) + break; + var n = e.toString("utf-8", t, i - 1); + t = i + 1; + var r = n.split(","), a = parseInt(r[0]); + if (a) { + 0; + var u = r[10]; + u || (u = r[7]), u || (u = r[5]), MapNames[a] = u; + } + } + } +}; + +function IPToUint(e) { + var t = e.split("."); + return 256 * (256 * (256 * + t[0] + + t[1]) + + t[2]) + + t[3]; +}; +global.SetGeoLocation = SetGeoLocation, Init(); diff --git a/src/core/html-server.ts b/src/core/html-server.ts new file mode 100644 index 0000000..7afe003 --- /dev/null +++ b/src/core/html-server.ts @@ -0,0 +1,1710 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import './crypto-library' +import './log' + +import * as crypto from 'crypto'; +const os = require('os'); + +var BlockTree = new STreeBuffer(300 * 1000, global.CompareItemHashSimple, "number"); +const http = require('http'), net = require('net'), url = require('url'), fs = require('fs'), querystring = require('querystring'); +var ContenTypeMap = {}; +ContenTypeMap["js"] = "application/javascript"; +ContenTypeMap["css"] = "text/css"; +ContenTypeMap["wav"] = "audio/wav"; +ContenTypeMap["mp3"] = "audio/mpeg"; +ContenTypeMap["mp4"] = "video/mp4"; +ContenTypeMap["ico"] = "image/vnd.microsoft.icon"; +ContenTypeMap["png"] = "image/png"; +ContenTypeMap["gif"] = "image/gif"; +ContenTypeMap["jpg"] = "image/jpeg"; +ContenTypeMap["html"] = "text/html"; +ContenTypeMap["txt"] = "text/plain"; +ContenTypeMap["csv"] = "text/csv"; +ContenTypeMap["svg"] = "image/svg+xml"; +ContenTypeMap[""] = "application/octet-stream"; +ContenTypeMap["zip"] = "application/zip"; +ContenTypeMap["pdf"] = "application/pdf"; +ContenTypeMap["exe"] = "application/octet-stream"; +ContenTypeMap["msi"] = "application/octet-stream"; +ContenTypeMap["woff"] = "application/font-woff"; +ContenTypeMap[".js"] = "application/javascript"; +ContenTypeMap["html"] = "text/html"; +ContenTypeMap["psd"] = "application/octet-stream"; +global.HTTPCaller = {}; + +let { + ToLog, + ToError, + DApps, + SERVER, + MAX_TRANSACTION_COUNT +} = global + +function DoCommand(response, Type, Path, params, remoteAddress) { + var F = global.HTTPCaller[params[0]]; + if (F) { + if (Type !== "POST") { + response.end(); + return; + } + response.writeHead(200, { 'Content-Type': 'text/plain' }); + var Ret = F(params[1], response); + if (Ret === null) + return; + try { + var Str = JSON.stringify(Ret); + response.end(Str); + } + catch (e) { + global.ToLog("ERR PATH:" + Path); + global.ToLog(e); + response.end(); + } + return; + } + var method = params[0]; + method = method.toLowerCase(); + if (method === "dapp" && params.length === 2) + method = "DappTemplateFile"; + switch (method) { + case "": + SendWebFile(response, "./HTML/wallet.html"); + break; + case "file": + SendBlockFile(response, params[1], params[2]); + break; + case "DappTemplateFile": + DappTemplateFile(response, params[1]); + break; + case "smart": + DappSmartCodeFile(response, params[1]); + break; + case "client": + DappClientCodeFile(response, params[1]); + break; + default: + { + if (Path.indexOf(".") === - 1) + global.ToError("Error path:" + Path + " remoteAddress=" + remoteAddress); + var path = params[params.length - 1]; + if (typeof path !== "string") + path = "ErrorPath"; + else + if (path.indexOf("..") >= 0 || path.indexOf("\\") >= 0 || path.indexOf("/") >= 0) + path = "ErrorFilePath"; + if (path.indexOf(".") < 0) + path += ".html"; + var type = Path.substr(Path.length - 3, 3); + switch (type) { + case ".js": + path = "./HTML/JS/" + path; + break; + case "css": + path = "./HTML/CSS/" + path; + break; + case "wav": + case "mp3": + path = "./HTML/SOUND/" + path; + break; + case "svg": + case "png": + case "gif": + case "jpg": + case "ico": + path = "./HTML/PIC/" + path; + break; + case "pdf": + case "zip": + case "exe": + case "msi": + path = "./HTML/FILES/" + path; + break; + default: + path = "./HTML/" + path; + break; + } + SendWebFile(response, path, Path); + break; + } + } +}; +global.DappTemplateFile = DappTemplateFile; + +function DappTemplateFile(response, StrNum) { + var Num = parseInt(StrNum); + if (Num && Num <= global.DApps.Smart.GetMaxNum()) { + var Data = global.DApps.Smart.ReadSmart(Num); + if (Data) { + response.writeHead(200, { 'Content-Type': 'text/html', "X-Frame-Options": "sameorigin" }); + var Str = fs.readFileSync("HTML/dapp-frame.html", { encoding: "utf8" }); + Str = Str.replace(/#template-number#/g, StrNum); + Str = Str.replace(/DAPP Loading.../g, Data.Name); + Str = Str.replace(/.\/tera.ico/g, "/file/" + Data.IconBlockNum + "/" + Data.IconTrNum); + response.end(Str); + return; + } + } + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(); +}; +global.DappSmartCodeFile = DappSmartCodeFile; + +function DappSmartCodeFile(response, StrNum) { + var Num = parseInt(StrNum); + if (Num && Num <= global.DApps.Smart.GetMaxNum()) { + var Data = global.DApps.Smart.ReadSmart(Num); + if (Data) { + response.writeHead(200, { 'Content-Type': 'application/javascript' }); + response.end(Data.Code); + return; + } + } + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(); +}; +global.DappClientCodeFile = DappClientCodeFile; + +function DappClientCodeFile(response, StrNum) { + var Num = parseInt(StrNum); + if (Num && Num <= global.DApps.Smart.GetMaxNum()) { + var Data = global.DApps.Smart.ReadSmart(Num); + if (Data) { + response.writeHead(200, { 'Content-Type': "text/plain" }); + response.end(Data.HTML); + return; + } + } + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(); +}; +global.HTTPCaller.DappSmartHTMLFile = function(Params) { + var Data = global.DApps.Smart.ReadSmart(ParseNum(Params.Smart)); + if (Data) { + if (global.DEV_MODE && Params.DebugPath) { + global.ToLog("Load: " + Params.DebugPath); + Data.HTML = fs.readFileSync(Params.DebugPath, { encoding: "utf8" }); + } + return { result: 1, Body: Data.HTML }; + } + return { result: 0 }; +}; +global.SendBlockFile = SendBlockFile; + +function SendBlockFile(response, BlockNum, TrNum) { + BlockNum = parseInt(BlockNum); + TrNum = parseInt(TrNum); + if (BlockNum && BlockNum <= global.SERVER.GetMaxNumBlockDB() && TrNum <= MAX_TRANSACTION_COUNT) { + var Block = global.SERVER.ReadBlockDB(BlockNum); + if (Block && Block.arrContent) { + SendToResponceFile(response, Block, TrNum); + return; + } + else + if (!Block || !Block.TrDataPos) { + LoadBlockFromNetwork({ BlockNum: BlockNum }, function(Err, Block) { + if (Err) { + SendToResponce404(response); + } + else { + SendToResponceFile(response, Block, TrNum); + } + }); + return; + } + } + SendToResponce404(response); +}; + +function SendToResponceFile(response, Block, TrNum) { + var Body = Block.arrContent[TrNum]; + if (Body && Body.data) + Body = Body.data; + if (Body && Body[0] === global.TYPE_TRANSACTION_FILE) { + var TR = global.DApps.File.GetObjectTransaction(Body); + if (TR.ContentType.toLowerCase().indexOf("html") >= 0) + response.writeHead(200, { 'Content-Type': "text/plain" }); + else + response.writeHead(200, { 'Content-Type': TR.ContentType }); + response.end(TR.Data); + } + else { + SendToResponce404(response); + } +}; + +function SendToResponce404(response) { + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(); +}; +HTTPCaller.DappBlockFile = function(Params, response) { + Params.BlockNum = ParseNum(Params.BlockNum); + Params.TrNum = ParseNum(Params.TrNum); + if (!Params.TrNum) + Params.TrNum = 0; + if (Params.BlockNum && Params.BlockNum <= global.SERVER.GetMaxNumBlockDB() && Params.TrNum <= MAX_TRANSACTION_COUNT) { + var Block = global.SERVER.ReadBlockDB(Params.BlockNum); + if (Block && Block.arrContent) { + SendToResponceDappFile(response, Block, Params.TrNum); + return null; + } + else + if (!Block || !Block.TrDataPos) { + LoadBlockFromNetwork(Params, function(Err, Block) { + if (Err) { + SendToResponceResult0(response); + } + else { + SendToResponceDappFile(response, Block, Params.TrNum); + } + }); + return null; + } + } + return { result: 0 }; +}; + +function SendToResponceDappFile(response, Block, TrNum) { + var Result = { result: 0 }; + var Body = Block.arrContent[TrNum]; + if (Body) { + var Type = Body[0]; + if (Type === global.TYPE_TRANSACTION_FILE) { + var TR = global.DApps.File.GetObjectTransaction(Body); + Result = { result: 1, Type: Type, ContentType: TR.ContentType, Name: TR.Name, Body: TR.Data.toString('utf8') }; + } + else { + var App = DAppByType[Type]; + if (App) { + Body = JSON.parse(App.GetScriptTransaction(Body)); + } + Result = { result: 1, Type: Type, Body: Body }; + } + } + var Str = JSON.stringify(Result); + response.end(Str); +}; + +function SendToResponceResult0(response) { + if (response) + response.end("{\"result\":0}"); +}; +var glBlock0; +HTTPCaller.DappStaticCall = function(Params, response) { + global.DApps.Accounts.BeginBlock(); + global.DApps.Accounts.BeginTransaction(); + global.TickCounter = 100000; + var Account = global.DApps.Accounts.ReadStateTR(ParseNum(Params.Account)); + if (!Account) { + return { result: 0, RetValue: "Error account Num: " + Params.Account }; + } + if (!glBlock0) + glBlock0 = global.SERVER.ReadBlockHeaderDB(0); + var RetValue; + try { + RetValue = RunSmartMethod(glBlock0, Account.Value.Smart, Account, 0, 0, undefined, Params.MethodName, Params.Params, 1); + } + catch (e) { + return { result: 0, RetValue: "" + e }; + } + var Str = JSON.stringify({ result: 1, RetValue: RetValue }); + if (Str.length > 16000) { + return { result: 0, RetValue: "Error result length (more 16000)" }; + } + response.end(Str); + return null; +}; +HTTPCaller.DappInfo = function(Params, responce, ObjectOnly) { + var SmartNum = ParseNum(Params.Smart); + if (global.TX_PROCESS && global.TX_PROCESS.Worker) + global.TX_PROCESS.Worker.send({ cmd: "SetSmartEvent", Smart: SmartNum }); + var Account; + var Smart = global.DApps.Smart.ReadSimple(SmartNum); + if (Smart) { + delete Smart.HTML; + delete Smart.Code; + Account = global.DApps.Accounts.ReadState(Smart.Account); + try { + Account.SmartState = global.BufLib.GetObjectFromBuffer(Account.Value.Data, Smart.StateFormat, {}); + if (typeof Account.SmartState === "object") + Account.SmartState.Num = Account.Num; + } + catch (e) { + if (!Account) + Account = {}; + Account.SmartState = {}; + } + } + DeleteOldEvents(SmartNum); + var Context = GetUserContext(Params); + var EArr = GetEventArray(SmartNum, Context); + var WLData = HTTPCaller.DappWalletList(Params); + var ArrLog = []; + for (var i = 0; i < ArrLogClient.length; i++) { + var Item = ArrLogClient[i]; + if (!Item.final) + continue; + ArrLog.push(Item); + } + var Ret = { + result: 1, DELTA_CURRENT_TIME: DELTA_CURRENT_TIME, MIN_POWER_POW_TR: MIN_POWER_POW_TR, FIRST_TIME_BLOCK: FIRST_TIME_BLOCK, + CONSENSUS_PERIOD_TIME: CONSENSUS_PERIOD_TIME, PRICE_DAO: PRICE_DAO(SERVER.BlockNumDB), NEW_SIGN_TIME: NEW_SIGN_TIME, Smart: Smart, + Account: Account, ArrWallet: WLData.arr, ArrEvent: EArr, ArrLog: ArrLog, + }; + if (global.WALLET) { + Ret.WalletIsOpen = (global.WALLET.WalletOpen !== false); + Ret.WalletCanSign = (global.WALLET.WalletOpen !== false && global.WALLET.KeyPair.WasInit); + Ret.PubKey = global.WALLET.KeyPair.PubKeyStr; + } + if (!ObjectOnly) { + Ret.CurTime = Date.now(); + Ret.CurBlockNum = GetCurrentBlockNumByTime(); + Ret.BlockNumDB = global.SERVER.BlockNumDB; + Ret.MaxAccID = global.DApps.Accounts.GetMaxAccount(); + Ret.MaxDappsID = global.DApps.Smart.GetMaxNum(); + } + return Ret; +}; +HTTPCaller.DappWalletList = function(Params) { + var arr0 = global.DApps.Accounts.GetWalletAccountsByMap(WALLET.AccountMap); + var arr = []; + for (var i = 0; i < arr0.length; i++) { + if (Params.AllAccounts || arr0[i].Value.Smart === Params.Smart) { + arr.push(arr0[i]); + } + } + var Ret = { result: 1, arr: arr, }; + return Ret; +}; +HTTPCaller.DappAccountList = function(Params) { + var arr = global.DApps.Accounts.GetRowsAccounts(Params.StartNum, Params.CountNum, undefined, 1); + return { arr: arr, result: 1 }; +}; +HTTPCaller.DappSmartList = function(Params) { + var arr = global.DApps.Smart.GetRows(Params.StartNum, Params.CountNum, undefined, undefined, Params.GetAllData, Params.TokenGenerate); + return { arr: arr, result: 1 }; +}; +HTTPCaller.DappBlockList = function(Params, response) { + Params.Filter = undefined; + return HTTPCaller.GetBlockList(Params, response, 1); +}; +HTTPCaller.DappTransactionList = function(Params, response) { + Params.Filter = undefined; + Params.Param3 = Params.BlockNum; + return HTTPCaller.GetTransactionAll(Params, response); +}; +var sessionid = GetHexFromAddres(crypto.randomBytes(20)); +HTTPCaller.RestartNode = function(Params) { + global.RestartNode(); + return { result: 1 }; +}; +HTTPCaller.ToLogServer = function(Str) { + ToLogClient(Str); + return { result: 1 }; +}; +HTTPCaller.FindMyAccounts = function(Params) { + global.WALLET.FindMyAccounts(1); + return { result: 1 }; +}; +HTTPCaller.GetAccount = function(id) { + id = parseInt(id); + var arr = global.DApps.Accounts.GetRowsAccounts(id, 1); + return { Item: arr[0], result: 1 }; +}; +HTTPCaller.GetAccountList = function(Params) { + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Accounts.GetRowsAccounts(Params.StartNum, Params.CountNum, Params.Filter); + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetDappList = function(Params) { + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Smart.GetRows(Params.StartNum, Params.CountNum, Params.Filter, Params.Filter2, 1); + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetBlockList = function(Params, response, bOnlyNum) { + if (!Params.CountNum) + Params.CountNum = 1; + if (Params.StartNum < global.SERVER.BlockNumDBMin) { + let CountWait = 0; + var WasWait = 0; + for (var BlockNum = Params.StartNum; BlockNum < Params.StartNum + Params.CountNum; BlockNum++) { + var Block = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (!Block) { + CountWait++; + WasWait = 1; + LoadBlockFromNetwork({ BlockNum: BlockNum }, function(Err, Block) { + CountWait--; + if (CountWait === 0) { + var arr = global.SERVER.GetRows(Params.StartNum, Params.CountNum, Params.Filter); + var Result = { arr: arr, result: 1 }; + response.end(JSON.stringify(Result)); + } + }); + } + } + if (WasWait) + return null; + } + var arr = global.SERVER.GetRows(Params.StartNum, Params.CountNum, Params.Filter, !bOnlyNum); + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetTransactionAll = function(Params, response) { + if (!Params.CountNum) + Params.CountNum = 1; + var BlockNum = Params.Param3; + if (BlockNum < global.SERVER.BlockNumDBMin) { + var Block = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (!Block) { + LoadBlockFromNetwork({ BlockNum: BlockNum }, function(Err, Block) { + var Result; + if (Err) { + Result = { arr: [], result: 0 }; + } + else { + var arr = global.SERVER.GetTrRows(Block.BlockNum, Params.StartNum, Params.CountNum, Params.Filter); + Result = { arr: arr, result: 1 }; + } + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; + } + } + var arr = global.SERVER.GetTrRows(BlockNum, Params.StartNum, Params.CountNum, Params.Filter); + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetActList = function(Params) { + var arr = global.DApps.Accounts.GetActList(Params.StartNum, Params.CountNum, Params.Filter); + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetHashList = function(Params) { + var arr = global.DApps.Accounts.DBAccountsHash.GetRows(Params.StartNum, Params.CountNum, Params.Filter); + for (var i = 0; i < arr.length; i++) { + var item = arr[i]; + item.BlockNum = item.Num * PERIOD_ACCOUNT_HASH; + item.Hash100 = []; + if (item.BlockNum % 100 === 0) { + var Data = global.SERVER.DBHeader100.Read(item.BlockNum / 100); + if (Data) + item.Hash100 = Data.Hash100; + } + } + return { arr: arr, result: 1 }; +}; +HTTPCaller.GetHistoryAct = function(Params) { + var arr = global.WALLET.GetHistory(Params.StartNum, Params.CountNum, Params.Filter); + return { arr: arr, result: 1 }; +}; +var LastTimeGetHashRate = 0; +var LastHashRate = 0; +var HashRateOneSec = 0; +HTTPCaller.GetWalletInfo = function(Params) { + var Constants = {}; + for (var i = 0; i < global.CONST_NAME_ARR.length; i++) { + var key = global.CONST_NAME_ARR[i]; + Constants[key] = global[key]; + } + var MaxHistory = 0; + var Delta = Date.now() - LastTimeGetHashRate; + if (Delta >= 1000) { + if (Delta < 1100) + HashRateOneSec = global.HASH_RATE - LastHashRate; + LastHashRate = global.HASH_RATE; + LastTimeGetHashRate = Date.now(); + } + var StateTX = global.DApps.Accounts.DBStateTX.Read(0); + var TXBlockNum = 0; + if (StateTX) + TXBlockNum = StateTX.BlockNum; + var Ret = { + result: 1, WalletOpen: global.WALLET.WalletOpen, WalletIsOpen: (global.WALLET.WalletOpen !== false), WalletCanSign: (global.WALLET.WalletOpen !== false && global.WALLET.KeyPair.WasInit), + CODE_VERSION: CODE_VERSION, MAX_TRANSACTION_LIMIT: MAX_TRANSACTION_LIMIT, VersionNum: global.UPDATE_CODE_VERSION_NUM, RelayMode: global.SERVER.RelayMode, + BlockNumDB: global.SERVER.BlockNumDB, CurBlockNum: GetCurrentBlockNumByTime(), CurTime: Date.now(), IsDevelopAccount: IsDeveloperAccount(WALLET.PubKeyArr), + AccountMap: global.WALLET.AccountMap, ArrLog: ArrLogClient, MaxAccID: global.DApps.Accounts.GetMaxAccount(), MaxActNum: global.DApps.Accounts.GetActsMaxNum(), + MaxDappsID: global.DApps.Smart.GetMaxNum(), NeedRestart: global.NeedRestart, ip: global.SERVER.ip, port: global.SERVER.port, NET_WORK_MODE: global.NET_WORK_MODE, + INTERNET_IP_FROM_STUN: global.INTERNET_IP_FROM_STUN, HistoryMaxNum: MaxHistory, DELTA_CURRENT_TIME: DELTA_CURRENT_TIME, FIRST_TIME_BLOCK: FIRST_TIME_BLOCK, + CONSENSUS_PERIOD_TIME: CONSENSUS_PERIOD_TIME, NEW_SIGN_TIME: NEW_SIGN_TIME, DATA_PATH: (DATA_PATH.substr(1, 1) === ":" ? DATA_PATH : GetNormalPathString(process.cwd() + "/" + DATA_PATH)), + NodeAddrStr: global.SERVER.addrStr, STAT_MODE: global.STAT_MODE, HTTPPort: global.HTTP_PORT_NUMBER, HTTPPassword: HTTP_PORT_PASSWORD, + CONSTANTS: Constants, CheckPointBlockNum: CHECK_POINT.BlockNum, MiningAccount: global.GENERATE_BLOCK_ACCOUNT, CountMiningCPU: GetCountMiningCPU(), + CountRunCPU: global.ArrMiningWrk.length, MiningPaused: global.MiningPaused, HashRate: HashRateOneSec, MIN_POWER_POW_TR: MIN_POWER_POW_TR, + PRICE_DAO: PRICE_DAO(SERVER.BlockNumDB), NWMODE: global.NWMODE, PERIOD_ACCOUNT_HASH: PERIOD_ACCOUNT_HASH, MAX_ACCOUNT_HASH: global.DApps.Accounts.DBAccountsHash.GetMaxNum(), + TXBlockNum: TXBlockNum, SpeedSignLib: global.SpeedSignLib, + }; + if (Params.Account) + Ret.PrivateKey = global.GetHexFromArr(WALLET.GetPrivateKey(WALLET.AccountMap[Params.Account])); + else + Ret.PrivateKey = global.GetHexFromArr(WALLET.GetPrivateKey()); + Ret.PublicKey = global.WALLET.KeyPair.PubKeyStr; + return Ret; +}; +HTTPCaller.GetCurrentInfo = HTTPCaller.GetWalletInfo; +HTTPCaller.TestSignLib = function() { + global.TestSignLib(); +}; +HTTPCaller.GetWalletAccounts = function() { + var Ret = { result: 1, arr: global.DApps.Accounts.GetWalletAccountsByMap(WALLET.AccountMap), }; + Ret.PrivateKey = global.WALLET.KeyPair.PrivKeyStr; + Ret.PublicKey = global.WALLET.KeyPair.PubKeyStr; + return Ret; +}; +HTTPCaller.SetWalletKey = function(PrivateKeyStr) { + global.WALLET.SetPrivateKey(PrivateKeyStr, true); + return { result: 1 }; +}; +HTTPCaller.SetWalletPasswordNew = function(Password) { + global.WALLET.SetPasswordNew(Password); + return { result: 1 }; +}; +HTTPCaller.OpenWallet = function(Password) { + var res = global.WALLET.OpenWallet(Password); + return { result: res }; +}; +HTTPCaller.CloseWallet = function() { + var res = global.WALLET.CloseWallet(); + return { result: res }; +}; +HTTPCaller.GetSignTransaction = function(TR) { + var Sign = global.WALLET.GetSignTransaction(TR); + return { Sign: Sign, result: 1 }; +}; +HTTPCaller.GetSignFromHEX = function(Params) { + var Arr = global.GetArrFromHex(Params.Hex); + var Sign; + if (Params.Account) + Sign = global.WALLET.GetSignFromArr(Arr, global.WALLET.AccountMap[Params.Account]); + else + Sign = global.WALLET.GetSignFromArr(Arr); + return { Sign: Sign, result: 1 }; +}; +HTTPCaller.SendTransactionHex = function(Params) { + var body = global.GetArrFromHex(Params.Hex); + var Result = { result: 1 }; + var Res = global.SERVER.AddTransactionOwn({ body: body, ToAll: 1 }); + Result.sessionid = sessionid; + Result.text = AddTrMap[Res]; + var final = false; + if (Res <= 0 && Res !== - 3) + final = true; + ToLogClient("Send: " + Result.text, global.GetHexFromArr(sha3(body)), final); + return Result; +}; +HTTPCaller.SendDirectCode = function(Params, response) { + var Result; + if (Params.TX) { + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) { + global.TX_PROCESS.RunRPC("EvalCode", Params.Code, function(Err, Ret) { + Result = { result: !Err, sessionid: sessionid, text: Ret, }; + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; + } + else { + Result = "No send to TX"; + } + } + else { + try { + var ret = eval(Params.Code); + Result = JSON.stringify(ret, "", 4); + } + catch (e) { + Result = "" + e; + } + } + var Struct = { result: 1, sessionid: sessionid, text: Result }; + return Struct; +}; +HTTPCaller.SetMining = function(MiningAccount) { + global.WALLET.SetMiningAccount(parseInt(MiningAccount)); + return { result: 1 }; +}; + +function CheckCorrectDevKey() { + if (global.WALLET.WalletOpen === false) { + var StrErr = "Not open wallet"; + ToLogClient(StrErr); + return { result: 0, text: StrErr }; + } + if (!IsDeveloperAccount(WALLET.PubKeyArr)) { + var StrErr = "Not developer key"; + ToLogClient(StrErr); + return { result: 0, text: StrErr }; + } + return true; +}; +HTTPCaller.SendECode = function(Param) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (Param.All) { + global.SERVER.ConnectToAll(); + var arr = global.SERVER.GetActualNodes(); + for (var i = 0; i < arr.length; i++) { + var Node = arr[i]; + global.SERVER.SendECode(Param, Node); + } + return { result: 1, text: "Sent to " + arr.length + " nodes" }; + } + var Node = FindNodeByAddr(Param.Addr, 1); + if (Node === undefined) + return { result: 0, text: "Node not found" }; + if (Node === false) + return { result: 0, text: "Node not active - reconnect" }; + global.SERVER.SendECode(Param, Node); + return { result: 1, text: "Send" }; +}; +HTTPCaller.SetCheckPoint = function(BlockNum) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (!BlockNum) + BlockNum = global.SERVER.BlockNumDB; + else + BlockNum = parseInt(BlockNum); + if (SetCheckPointOnBlock(BlockNum)) + return { result: 1, text: "Set check point on BlockNum=" + BlockNum }; + else + return { result: 0, text: "Error on check point BlockNum=" + BlockNum }; +}; + +function SetCheckPointOnBlock(BlockNum) { + if (global.WALLET.WalletOpen === false) + return 0; + var Block = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (!Block) + return 0; + var SignArr = arr2(Block.Hash, GetArrFromValue(Block.BlockNum)); + var Sign = secp256k1.sign(SHA3BUF(SignArr, Block.BlockNum), global.WALLET.KeyPair.getPrivateKey('')).signature; + global.CHECK_POINT = { BlockNum: BlockNum, Hash: Block.Hash, Sign: Sign }; + global.SERVER.ResetNextPingAllNode(); + return 1; +}; +global.SetCheckPointOnBlock = SetCheckPointOnBlock; +var idSetTimeSetCheckPoint; +HTTPCaller.SetAutoCheckPoint = function(Param) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (idSetTimeSetCheckPoint) + clearInterval(idSetTimeSetCheckPoint); + idSetTimeSetCheckPoint = undefined; + if (Param.Set) + idSetTimeSetCheckPoint = setInterval(RunSetCheckPoint, Param.Period * 1000); + return { result: 1, text: "AutoCheck: " + Param.Set + " each " + Param.Period + " sec" }; +}; +var SumCheckPow = 0; +var CountCheckPow = 0; + +function RunSetCheckPoint() { + if (!SERVER.BlockNumDB) + return; + if (SERVER.BlockNumDB < 2100000) + return; + var Delta = GetCurrentBlockNumByTime() - global.SERVER.BlockNumDB; + if (Delta > 16) + return; + var BlockNum = global.SERVER.BlockNumDB - global.CheckPointDelta; + var Block = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (Block) { + var Power = GetPowPower(Block.PowHash); + if (Power < 30) { + global.ToLog("CANNOT SET CHECK POINT Power=" + Power + " BlockNum=" + BlockNum); + return; + } + CountCheckPow++; + SumCheckPow += Power; + var AvgPow = SumCheckPow / CountCheckPow; + if (CountCheckPow > 10) { + if (Power < AvgPow - 2) { + global.ToLog("**************** CANNOT SET CHECK POINT Power=" + Power + "/" + AvgPow + " BlockNum=" + BlockNum); + return; + } + } + SetCheckPointOnBlock(BlockNum); + global.ToLog("SET CHECK POINT Power=" + Power + "/" + AvgPow + " BlockNum=" + BlockNum); + } +}; +HTTPCaller.SetNewCodeVersion = function(Data) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + var Ret = global.SERVER.SetNewCodeVersion(Data, global.WALLET.KeyPair.getPrivateKey('')); + global.SERVER.ResetNextPingAllNode(); + return { result: 1, text: Ret }; +}; +HTTPCaller.SetCheckNetConstant = function(Data) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (!Data) { + ToLogClient("Data not set"); + return { result: 0, text: "Data not set" }; + } + Data.Num = GetCurrentBlockNumByTime(); + Data.BlockNum = GetCurrentBlockNumByTime() + 10; + var SignArr = global.SERVER.GetSignCheckNetConstant(Data); + Data.Sign = secp256k1.sign(SHA3BUF(SignArr), global.WALLET.KeyPair.getPrivateKey('')).signature; + global.SERVER.CheckNetConstant({ NetConstant: Data }, { addrStr: "local" }); + global.SERVER.ResetNextPingAllNode(); + return { result: 1, text: "Set NET_CONSTANT BlockNum=" + Data.BlockNum }; +}; +HTTPCaller.SetCheckDeltaTime = function(Data) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (!Data || !Data.Num) { + ToLogClient("Num not set"); + return { result: 0 }; + } + var SignArr = global.SERVER.GetSignCheckDeltaTime(Data); + Data.Sign = secp256k1.sign(SHA3BUF(SignArr), global.WALLET.KeyPair.getPrivateKey('')).signature; + global.CHECK_DELTA_TIME = Data; + global.SERVER.ResetNextPingAllNode(); + return { result: 1, text: "Set check time Num=" + Data.Num }; +}; +var idAutoCorrTime; +HTTPCaller.SetAutoCorrTime = function(bSet) { + var Ret = CheckCorrectDevKey(); + if (Ret !== true) + return Ret; + if (idAutoCorrTime) + clearInterval(idAutoCorrTime); + idAutoCorrTime = undefined; + if (bSet) + idAutoCorrTime = setInterval(RunAutoCorrTime, 1000); + return { result: 1, text: "Auto correct: " + bSet }; +}; +var StartCheckTimeNum = 0; + +function RunAutoCorrTime() { + if (global.WALLET.WalletOpen === false) + return; + if (GetCurrentBlockNumByTime() > StartCheckTimeNum && Math.abs(global.DELTA_CURRENT_TIME) >= 120) { + var AutoDelta = - Math.trunc(global.DELTA_CURRENT_TIME); + var Data = { Num: GetCurrentBlockNumByTime(), bUse: 1, bAddTime: 1 }; + if (AutoDelta < 0) { + AutoDelta = - AutoDelta; + Data.bAddTime = 0; + } + Data.DeltaTime = 40; + Data.StartBlockNum = Data.Num + 5; + Data.EndBlockNum = Data.StartBlockNum + Math.trunc(AutoDelta / Data.DeltaTime); + var SignArr = global.SERVER.GetSignCheckDeltaTime(Data); + Data.Sign = secp256k1.sign(SHA3BUF(SignArr), global.WALLET.KeyPair.getPrivateKey('')).signature; + global.CHECK_DELTA_TIME = Data; + global.SERVER.ResetNextPingAllNode(); + StartCheckTimeNum = Data.EndBlockNum + 1; + global.ToLog("Auto corr time Num:" + Data.Num + " AutoDelta=" + AutoDelta); + } +}; +HTTPCaller.SaveConstant = function(SetObj) { + var WasUpdate = global.USE_AUTO_UPDATE; + for (var key in SetObj) { + global[key] = SetObj[key]; + } + SAVE_CONST(true); + global.SERVER.DO_CONSTANT(); + if (!WasUpdate && global.USE_AUTO_UPDATE && CODE_VERSION.VersionNum && global.UPDATE_CODE_VERSION_NUM < CODE_VERSION.VersionNum) { + global.SERVER.UseCode(CODE_VERSION.VersionNum, true); + } + if (SetObj.DoRestartNode) + global.RestartNode(); + else { + if (SetObj.DoMining) + global.RunStopPOWProcess(); + } + return { result: 1 }; +}; +HTTPCaller.SetHTTPParams = function(SetObj) { + global.HTTP_PORT_NUMBER = SetObj.HTTPPort; + global.HTTP_PORT_PASSWORD = SetObj.HTTPPassword; + SAVE_CONST(true); + if (SetObj.DoRestartNode) + global.RestartNode(); + return { result: 1 }; +}; +HTTPCaller.SetNetMode = function(SetObj) { + if (!global.NET_WORK_MODE) + global.NET_WORK_MODE = {}; + for (var key in SetObj) { + global.NET_WORK_MODE[key] = SetObj[key]; + } + if (NET_WORK_MODE) { + global.START_IP = NET_WORK_MODE.ip; + global.START_PORT_NUMBER = NET_WORK_MODE.port; + } + SAVE_CONST(true); + if (SetObj.DoRestartNode) + global.RestartNode(); + return { result: 1 }; +}; +HTTPCaller.GetAccountKey = function(Num) { + var Result = {}; + Result.result = 0; + var KeyPair = global.WALLET.GetAccountKey(Num); + if (KeyPair) { + Result.result = 1; + Result.PubKeyStr = global.GetHexFromArr(KeyPair.getPublicKey('', 'compressed')); + } + return Result; +}; +HTTPCaller.GetHotArray = function(Param) { + var ArrTree = global.SERVER.GetTransferTree(); + if (!ArrTree) + return { result: 0 }; + for (var Level = 0; Level < ArrTree.length; Level++) { + var arr = ArrTree[Level]; + if (arr) + for (var n = 0; n < arr.length; n++) { + arr[n].GetTiming = 0; + } + } + var BlockCounts = 0; + if (Param && Param.CountBlock) + for (var i = global.SERVER.CurrentBlockNum - Param.CountBlock; i <= global.SERVER.CurrentBlockNum - Param.CountBlock; i++) { + var Block = global.SERVER.GetBlock(i); + if (!Block || !Block.Active || !Block.LevelsTransfer) { + continue; + } + BlockCounts++; + for (var n = 0; n < Block.LevelsTransfer.length; n++) { + var Transfer = Block.LevelsTransfer[n]; + for (var Addr in Transfer.TransferNodes) { + var Item = Transfer.TransferNodes[Addr]; + Item.Node.GetTiming += Item.GetTiming; + } + } + } + for (var Level = 0; Level < ArrTree.length; Level++) { + var arr = ArrTree[Level]; + if (!arr) + continue; + arr.sort(SortNodeHot); + for (var n = 0; n < arr.length; n++) { + arr[n] = GetCopyNode(arr[n], BlockCounts); + } + } + + function SortNodeHot(a, b) { + if (b.Hot !== a.Hot) + return b.Hot - a.Hot; + if (b.BlockProcessCount !== a.BlockProcessCount) + return b.BlockProcessCount - a.BlockProcessCount; + if (a.DeltaTime !== b.DeltaTime) + return a.DeltaTime - b.DeltaTime; + return a.id - b.id; + }; + return { result: 1, ArrTree: ArrTree }; +}; + +function GetCopyNode(Node, BlockCounts) { + if (!Node) + return; + if (Node.Socket && Node.Socket.Info) { + Node.Info += Node.Socket.Info + "\n"; + Node.Socket.Info = ""; + } + if (!Node.PrevInfo) + Node.PrevInfo = ""; + var GetTiming = 0; + if (BlockCounts !== 0) + GetTiming = Math.trunc(Node.GetTiming / BlockCounts) / 1000; + var Item = { + VersionNum: Node.VersionNum, NoSendTx: Node.NoSendTx, GetNoSendTx: Node.GetNoSendTx, DirectMAccount: Node.DirectMAccount, + id: Node.id, ip: Node.ip, portweb: Node.portweb, port: Node.port, TransferCount: Node.TransferCount, GetTiming: GetTiming, ErrCountAll: Node.ErrCountAll, + LevelCount: Node.LevelCount, LevelEnum: Node.LevelEnum, TimeTransfer: GetStrOnlyTimeUTC(new Date(Node.LastTimeTransfer)), BlockProcessCount: Node.BlockProcessCount, + DeltaTime: Node.DeltaTime, DeltaTimeM: Node.DeltaTimeM, DeltaGlobTime: Node.DeltaGlobTime, PingNumber: Node.PingNumber, NextConnectDelta: Node.NextConnectDelta, + NextGetNodesDelta: Node.NextGetNodesDelta, NextHotDelta: Node.NextHotDelta, Name: Node.Name, addrStr: Node.addrStr, CanHot: Node.CanHot, + Active: Node.Active, Hot: Node.Hot, Info: Node.PrevInfo + Node.Info, InConnectArr: Node.WasAddToConnect, Level: Node.Level, TransferBlockNum: Node.TransferBlockNum, + TransferSize: Node.TransferSize, TransferBlockNumFix: Node.TransferBlockNumFix, CurBlockNum: Node.CurBlockNum, + }; + return Item; +}; +HTTPCaller.GetBlockchainStat = function(Param) { + var Result = global.SERVER.GetStatBlockchainPeriod(Param); + Result.result = 1; + Result.sessionid = sessionid; + return Result; +}; +HTTPCaller.GetAllCounters = function(Params, response) { + let Result = GET_STATS(); + Result.result = 1; + Result.sessionid = sessionid; + Result.STAT_MODE = global.STAT_MODE; + if (!global.TX_PROCESS || !global.TX_PROCESS.RunRPC) + return Result; + global.TX_PROCESS.RunRPC("GET_STATS", "", function(Err, Params) { + Result.result = !Err; + if (Result.result) { + AddStatData(Params, Result, "TX"); + } + if (global.WEB_PROCESS && global.WEB_PROCESS.RunRPC) { + global.WEB_PROCESS.RunRPC("GET_STATS", "", function(Err, Params) { + Result.result = !Err; + if (Result.result) { + AddStatData(Params, Result, "WEB"); + } + response.end(JSON.stringify(Result)); + }); + } + else { + response.end(JSON.stringify(Result)); + } + }); + return null; +}; + +function AddStatData(Params, Result, Prefix) { + for (var name in Params.stats) { + for (var key in Params.stats[name]) { + var Item = Params.stats[name][key]; + Result.stats[name][key + "-" + Prefix] = Item; + } + } +}; +HTTPCaller.SetStatMode = function(flag) { + if (flag) + StartCommonStat(); + global.STAT_MODE = flag; + SAVE_CONST(true); + global.TX_PROCESS.RunRPC("LOAD_CONST"); + return { result: 1, sessionid: sessionid, STAT_MODE: global.STAT_MODE }; +}; +HTTPCaller.ClearStat = function() { + global.ClearCommonStat(); + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) { + global.TX_PROCESS.RunRPC("ClearCommonStat", "", function(Err, Params) { + }); + } + if (global.WEB_PROCESS && global.WEB_PROCESS.RunRPC) { + global.WEB_PROCESS.RunRPC("ClearCommonStat", "", function(Err, Params) { + }); + } + return { result: 1, sessionid: sessionid, STAT_MODE: global.STAT_MODE }; +}; +HTTPCaller.RewriteAllTransactions = function(Param) { + RewriteAllTransactions(); + return { result: 1, sessionid: sessionid }; +}; +HTTPCaller.RewriteTransactions = function(Param) { + var Ret = global.SERVER.ReWriteDAppTransactions(Param.BlockCount); + return { result: Ret, sessionid: sessionid }; +}; +HTTPCaller.TruncateBlockChain = function(Param) { + var StartNum = global.SERVER.BlockNumDB - Param.BlockCount; + var MinBlock = global.DApps.Accounts.GetMinBlockAct(); + if (MinBlock > StartNum) { + global.ToLog("Cant Truncate BlockChain. Very long length. Max length=" + (SERVER.BlockNumDB - MinBlock), 0); + return { result: 0, sessionid: sessionid }; + } + global.SERVER.TruncateBlockDB(StartNum); + return { result: 1, sessionid: sessionid }; +}; +HTTPCaller.ClearDataBase = function(Param) { + BlockTree.Clear(); + global.SERVER.ClearDataBase(); + return { result: 1, sessionid: sessionid }; +}; +HTTPCaller.CleanChain = function(Param) { + if (global.CleanChain) { + var StartNum = global.SERVER.BlockNumDB - Param.BlockCount; + global.CleanChain(StartNum); + return { result: 1, sessionid: sessionid }; + } + return { result: 0, sessionid: sessionid }; +}; +HTTPCaller.GetArrStats = function(Keys, response) { + var arr = GET_STATDIAGRAMS(Keys); + let Result = { result: 1, sessionid: sessionid, arr: arr, STAT_MODE: global.STAT_MODE }; + if (!global.TX_PROCESS || !global.TX_PROCESS.RunRPC) + return Result; + var Keys2 = []; + for (var i = 0; i < Keys.length; i++) { + var Str = Keys[i]; + if (Str.substr(Str.length - 3) == "-TX") + Keys2.push(Str.substr(0, Str.length - 3)); + } + global.TX_PROCESS.RunRPC("GET_STATDIAGRAMS", Keys2, function(Err, Arr) { + Result.result = !Err; + if (Result.result) { + for (var i = 0; i < Arr.length; i++) { + var Item = Arr[i]; + Item.name = Item.name + "-TX"; + Result.arr.push(Item); + } + } + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; +}; +HTTPCaller.GetBlockChain = function(type) { + if (!global.SERVER || !SERVER.LoadedChainList) { + return { result: 0 }; + } + var MainChains = {}; + for (var i = 0; i < global.SERVER.LoadedChainList.length; i++) { + var chain = global.SERVER.LoadedChainList[i]; + if (chain && !chain.Deleted) + MainChains[chain.id] = true; + } + var arrBlocks = []; + var arrLoadedChainList = []; + var arrLoadedBlocks = []; + for (var key in global.SERVER.BlockChain) { + var Block = global.SERVER.BlockChain[key]; + if (Block) { + arrBlocks.push(CopyBlockDraw(Block, MainChains)); + } + } + AddChainList(arrLoadedChainList, global.SERVER.LoadedChainList, true); + AddMapList(arrLoadedBlocks, type, global.SERVER.MapMapLoaded, MainChains); + var ArrLoadedChainList = global.HistoryBlockBuf.LoadValue("LoadedChainList", 1); + if (ArrLoadedChainList) + for (var List of ArrLoadedChainList) { + AddChainList(arrLoadedChainList, List); + } + var ArrMapMapLoaded = global.HistoryBlockBuf.LoadValue("MapMapLoaded", 1); + if (ArrMapMapLoaded) + for (var List of ArrMapMapLoaded) { + AddMapList(arrLoadedBlocks, type, List); + } + var obj = { + LastCurrentBlockNum: global.SERVER.GetLastCorrectBlockNum(), CurrentBlockNum: global.SERVER.CurrentBlockNum, LoadedChainList: arrLoadedChainList, + LoadedBlocks: arrLoadedBlocks, BlockChain: arrBlocks, port: global.SERVER.port, DELTA_CURRENT_TIME: DELTA_CURRENT_TIME, memoryUsage: process.memoryUsage(), + IsDevelopAccount: IsDeveloperAccount(WALLET.PubKeyArr), LoadedChainCount: global.SERVER.LoadedChainList.length, StartLoadBlockTime: global.SERVER.StartLoadBlockTime, + sessionid: sessionid, result: 1 + }; + var obj2 = HTTPCaller.GetHotArray(); + obj.ArrTree = obj2.ArrTree; + arrBlocks = []; + arrLoadedChainList = []; + arrLoadedBlocks = []; + return obj; +}; +HTTPCaller.GetHistoryTransactions = function(Params) { + if (typeof Params === "object" && Params.AccountID) { + var Account = global.DApps.Accounts.ReadState(Params.AccountID); + if (!Account) + return { result: 0 }; + if (!Params.Count) + Params.Count = 100; + var arr = global.DApps.Accounts.GetHistory(Params.AccountID, Params.Count, Params.NextPos); + if (Params.GetDescription) { + for (var i = 0; i < arr.length; i++) { + var Item = arr[i]; + var Block = global.SERVER.ReadBlockDB(Item.BlockNum); + if (!Block || (!Block.arrContent)) + continue; + var Body = Block.arrContent[Item.TrNum]; + if (!Body) + continue; + var TR = global.DApps.Accounts.GetObjectTransaction(Body); + if (TR) + Item.Description = TR.Description; + } + } + var Result = { + Value: { SumCOIN: Account.Value.SumCOIN, SumCENT: Account.Value.SumCENT }, Name: Account.Name, Currency: Account.Currency, + MaxBlockNum: GetCurrentBlockNumByTime(), FIRST_TIME_BLOCK: FIRST_TIME_BLOCK, result: arr.length > 0 ? 1 : 0, History: arr + }; + return Result; + } + return { result: 0 }; +}; + +function GetCopyBlock(Block) { + var Result = { + BlockNum: Block.BlockNum, bSave: Block.bSave, TreeHash: GetHexFromAddres(Block.TreeHash), AddrHash: GetHexFromAddres(Block.AddrHash), + PrevHash: GetHexFromAddres(Block.PrevHash), SumHash: GetHexFromAddres(Block.SumHash), SumPow: Block.SumPow, TrDataPos: Block.TrDataPos, + TrDataLen: Block.TrDataLen, SeqHash: GetHexFromAddres(Block.SeqHash), Hash: GetHexFromAddres(Block.Hash), Power: GetPowPower(Block.PowHash), + TrCount: Block.TrCount, arrContent: Block.arrContent, + }; + return Result; +}; +var AddrLength = 16; + +function GetHexFromAddresShort(Hash) { + return GetHexFromAddres(Hash).substr(0, AddrLength); +}; + +function GetHexFromStrShort(Str) { + if (Str === undefined) + return Str; + else + return Str.substr(0, AddrLength); +}; +var glid = 0; + +function GetGUID(Block) { + if (!Block) + return "------"; + if (!Block.guid) { + glid++; + Block.guid = glid; + } + return Block.guid; +}; + +function CopyBlockDraw(Block, MainChains) { + var MinerID = 0; + var MinerName = ""; + if (Block.AddrHash) { + var Num = ReadUintFromArr(Block.AddrHash, 0); + MinerID = Num; + var Item = global.DApps.Accounts.ReadState(Num); + if (Item && Item.Name) + MinerName = Item.Name.substr(0, 8); + } + var CheckPoint = 0; + if (Block.BlockNum === CHECK_POINT.BlockNum) + CheckPoint = 1; + var Mining; + if (SERVER.MiningBlock === Block) + Mining = 1; + else + Mining = 0; + GetGUID(Block); + var Item = { + guid: Block.guid, Active: Block.Active, bSave: Block.bSave, Prepared: Block.Prepared, BlockNum: Block.BlockNum, Hash: GetHexFromAddresShort(Block.Hash), + SumHash: GetHexFromAddresShort(Block.SumHash), SeqHash: GetHexFromAddresShort(Block.SeqHash), TreeHash: GetHexFromAddresShort(Block.TreeHash), + AddrHash: GetHexFromAddresShort(Block.AddrHash), MinerID: MinerID, MinerName: MinerName, Comment1: Block.Comment1, Comment2: Block.Comment2, + SumPow: Block.SumPow, Info: Block.Info, TreeLoaded: Block.TreeEq, AddToLoad: Block.AddToLoad, LoadDB: Block.LoadDB, FindBlockDB: Block.FindBlockDB, + TrCount: Block.TrCount, ArrLength: 0, TrDataLen: Block.TrDataLen, Power: GetPowPower(Block.PowHash), CheckPoint: CheckPoint, Mining: Mining, + TransferSize: Block.TransferSize, HasErr: Block.HasErr, + }; + if (Block.chain) + Item.chainid = Block.chain.id; + if (Block.LoadDB !== undefined) + Item.bSave = Block.LoadDB; + if (Block.arrContent) + Item.TrCount = Block.arrContent.length; + Item.BlockDown = GetGUID(Block.BlockDown); + if (MainChains && Item.chainid) { + Item.Main = MainChains[Item.chainid]; + } + return Item; +}; + +function CopyChainDraw(Chain, bWasRecursive, bMain) { + if (!Chain) + return Chain; + GetGUID(Chain); + var Item = { + guid: Chain.guid, id: Chain.id, chainid: Chain.id, bSave: Chain.LoadDB, FindBlockDB: Chain.FindBlockDB, GetFindDB: Chain.GetFindDB(), + BlockNum: Chain.BlockNumStart, Hash: GetHexFromAddresShort(Chain.HashStart), Comment1: Chain.Comment1, Comment2: Chain.Comment2, + StopSend: Chain.StopSend, SumPow: 0, Info: Chain.Info, IsSum: Chain.IsSum, Main: bMain, + }; + if (Chain.IsSumStart) { + Item.SumHash = Item.Hash; + Item.Hash = "-------"; + } + if (Chain.RootChain) { + var rootChain = Chain.GetRootChain(); + if (rootChain) { + Item.rootid = rootChain.id; + if (!bWasRecursive) + Item.root = CopyChainDraw(rootChain, true); + } + } + else + Item.rootid = ""; + if (Chain.BlockHead) { + Item.HashMaxStr = GetGUID(Chain.BlockHead); + Item.BlockNumMax = Chain.BlockHead.BlockNum; + } + else { + Item.HashMaxStr = "------"; + } + return Item; +}; + +function AddChainList(arrLoadedChainList, LoadedChainList, bMain) { + for (var chain of LoadedChainList) { + if (chain) { + arrLoadedChainList.push(CopyChainDraw(chain, false, bMain)); + } + } +}; + +function AddMapList(arrLoadedBlocks, type, MapMapLoaded, MainChains) { + for (var key in MapMapLoaded) { + var map = MapMapLoaded[key]; + if (map) { + for (var key in map) { + var Block = map[key]; + if (key.substr(1, 1) === ":") + continue; + if (!Block.Send || type === "reload") { + arrLoadedBlocks.push(CopyBlockDraw(Block, MainChains)); + Block.Send = true; + } + } + } + } +}; +var MapFileHTML5 = {}; + +function SendWebFile(response, name?, StrCookie?, bParsing?) { + var type = name.substr(name.length - 4, 4); + if (type.substr(0, 1) === ".") + type = type.substr(1); + var Path = "./" + name; + if (!fs.existsSync(Path)) { + if (type === "ico") { + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(); + return; + } + var data = "Not found: " + name; + response.end(data); + return; + } + var StrContentType = ContenTypeMap[type]; + if (!StrContentType || StrContentType === "text/html") { + var Headers = { 'Content-Type': 'text/html', "X-Frame-Options": "sameorigin" }; + if (StrCookie) + Headers['Set-Cookie'] = StrCookie; + response.writeHead(200, Headers); + } + else { + if (StrContentType === "application/font-woff") { + response.writeHead(200, { 'Content-Type': StrContentType, 'Access-Control-Allow-Origin': "*" }); + } + else + response.writeHead(200, { 'Content-Type': StrContentType }); + } + if (bParsing && StrContentType === "text/html") { + var data = GetFileHTMLWithParsing(Path); + response.end(data); + return; + } + const stream = fs.createReadStream(Path); + setTimeout(function() { + stream.close(); + stream.push(null); + stream.read(0); + }, 100000); + stream.pipe(response); +}; + +function GetFileHTMLWithParsing(Path) { + var data = global.SendHTMLMap[Path]; + if (!data) { + global.SendHTMLMap[Path] = "-recursion-"; + data = String(fs.readFileSync(Path)); + data = ParseTag(data, "File", 0); + data = ParseTag(data, "Edit", 1); + global.SendHTMLMap[Path] = data; + } + return data; +}; +var glEditNum = 0; + +function ParseTag(Str, TagName, bEdit) { + var bWasInject = 0; + var data = ""; + var index = 0; + while (index >= 0) { + index = Str.indexOf("{{" + TagName + "=", index); + if (index >= 0) { + var index2 = Str.indexOf("}}", index + 3 + TagName.length); + if (index2 < 0) { + global.ToLog("Error teg " + TagName + " in " + Path); + break; + } + var Delta = index2 - index; + if (Delta > 210) { + global.ToLog("Error length (more 200) teg File in " + Path); + break; + } + var Path2 = Str.substring(index + 3 + TagName.length, index + Delta); + data += Str.substring(0, index); + if (bEdit) { + if (!bWasInject) { + data = data + GetFileSimple("./SITE/JS/web-edit.html"); + bWasInject = 1; + } + glEditNum++; + data += "
    "; + data += GetFileHTMLFromMarkdown(Path2); + data += "
    "; + data += ""; + } + else { + data += GetFileHTMLWithParsing(Path2); + } + Str = Str.substring(index2 + 2); + index = 0; + } + } + data += Str; + return data; +}; +var MarkLib; + +function GetFileHTMLFromMarkdown(Path) { + var data = global.SendHTMLMap[Path]; + if (!data) { + if (MarkLib === undefined) + MarkLib = require("../HTML/JS/marked.js"); + var Str = ""; + if (fs.existsSync(Path)) + Str = String(fs.readFileSync(Path)); + data = MarkLib(Str); + global.SendHTMLMap[Path] = data; + } + return data; +}; + +function GetFileSimple(Path) { + var Key = "GetFileSimple-" + Path; + var data = global.SendHTMLMap[Key]; + if (!data) { + data = String(fs.readFileSync(Path)); + global.SendHTMLMap[Key] = data; + } + return data; +}; + +function SaveFileSimple(Path, Str) { + global.SendHTMLMap = {}; + var Key = "GetFileSimple-" + Path; + global.SendHTMLMap[Key] = Str; + SaveToFile(Path, Str); +}; +global.SendHTMLMap = {}; +global.SendWebFile = SendWebFile; +global.GetFileHTMLWithParsing = GetFileHTMLWithParsing; +global.GetFileHTMLFromMarkdown = GetFileHTMLFromMarkdown; +global.GetFileSimple = GetFileSimple; +global.SaveFileSimple = SaveFileSimple; + +function GetStrTime(now) { + if (!now) + now = GetCurrentTime(0); + var Str = "" + now.getHours().toStringZ(2); + Str = Str + ":" + now.getMinutes().toStringZ(2); + Str = Str + ":" + now.getSeconds().toStringZ(2); + return Str; +}; + +function OnGetData(arg) { + var response = { + end: function() { + }, writeHead: function() { + }, + }; + var Path = arg.path; + var obj = arg.obj; + if (Path.substr(0, 1) === "/") + Path = Path.substr(1); + var params = Path.split('/', 5); + var Ret; + var F = HTTPCaller[params[0]]; + if (F) { + if (obj) + Ret = F(obj); + else + Ret = F(params[1], params[2], params[3]); + } + else { + Ret = { result: 0 }; + } + return Ret; +}; + +function parseCookies(rc) { + var list = {}; + rc && rc.split(';').forEach(function(cookie) { + var parts = cookie.split('='); + list[parts.shift().trim()] = decodeURI(parts.join('=')); + }); + return list; +}; +global.SetSafeResponce = SetSafeResponce; + +function SetSafeResponce(response) { + if (!response.Safe) { + response.Safe = 1; + response._end = response.end; + response._writeHead = response.writeHead; + response.end = function() { + try { + if (arguments && arguments[0] && arguments[0].length) { + global.ADD_TO_STAT("HTTP_SEND", arguments[0].length); + } + response._end.apply(response, arguments); + } + catch (e) { + global.ToError("H##1"); + global.ToError(e); + } + }; + response.writeHead = function() { + try { + response._writeHead.apply(response, arguments); + } + catch (e) { + global.ToError("H##2"); + global.ToError(e); + } + }; + } +}; +if (global.HTTP_PORT_NUMBER) { + var ClientTokenMap = {}; + var ClientIPMap = {}; + setInterval(function() { + ClientTokenMap = {}; + }, 24 * 3600 * 1000); + var port = global.HTTP_PORT_NUMBER; + var HTTPServer = http.createServer(function(request, response) { + if (!request.headers) + return; + if (!request.socket || !request.socket.remoteAddress) + return; + var remoteAddress = request.socket.remoteAddress.replace(/^.*:/, ''); + if (remoteAddress === "1") + remoteAddress = "127.0.0.1"; + var CheckPassword; + if (!global.HTTP_PORT_PASSWORD && remoteAddress.indexOf("127.0.0.1") < 0) + return; + if (global.HTTP_IP_CONNECT && remoteAddress.indexOf("127.0.0.1") < 0 && global.HTTP_IP_CONNECT.indexOf(remoteAddress) < 0) + return; + CheckPassword = 1; + SetSafeResponce(response); + if (!global.SERVER) { + response.writeHead(404, { 'Content-Type': 'text/html' }); + response.end(""); + return; + } + var fromURL = url.parse(request.url); + var Path = querystring.unescape(fromURL.path); + if (!ClientIPMap[remoteAddress]) { + ClientIPMap[remoteAddress] = 1; + global.ToLog("CONNECT TO HTTP ACCESS FROM: " + remoteAddress, 0); + global.ToLog("Path: " + Path, 0); + } + if (CheckPassword && global.HTTP_PORT_PASSWORD) { + var StrPort = ""; + if (global.HTTP_PORT_NUMBER !== 80) + StrPort = global.HTTP_PORT_NUMBER; + var cookies = parseCookies(request.headers.cookie); + var cookies_token = cookies["token" + StrPort]; + var cookies_hash = cookies["hash" + StrPort]; + if (cookies_token && cookies_hash && ClientTokenMap[cookies_token] === 0) { + if (cookies_hash.substr(0, 4) !== "0000") { + SendWebFile(response, "./HTML/password.html", "token" + StrPort + "=" + cookies_token + ";path=/"); + return; + } + var nonce = 0; + var index = cookies_hash.indexOf("-"); + if (index > 0) { + nonce = parseInt(cookies_hash.substr(index + 1)); + if (!nonce) + nonce = 0; + } + var hash = ClientHex(cookies_token + "-" + global.HTTP_PORT_PASSWORD, nonce); + if (hash === cookies_hash) { + ClientTokenMap[cookies_token] = 1; + } + else { + SendWebFile(response, "./HTML/password.html", "token" + StrPort + "=" + cookies_token + ";path=/"); + return; + } + } + if (!cookies_token || !ClientTokenMap[cookies_token]) { + var StrToken = global.GetHexFromArr(crypto.randomBytes(16)); + ClientTokenMap[StrToken] = 0; + SendWebFile(response, "./HTML/password.html", "token" + StrPort + "=" + StrToken + ";path=/"); + return; + } + } + var params = Path.split('/', 6); + params.splice(0, 1); + var Type = request.method; + if (Type === "POST") { + let Response = response; + let Params = params; + let postData = ""; + request.addListener("data", function(postDataChunk) { + if (postData.length < 70000 && postDataChunk.length < 70000) + postData += postDataChunk; + }); + request.addListener("end", function() { + var Data; + try { + Data = JSON.parse(postData); + } + catch (e) { + global.ToError("--------Error data parsing : " + Params[0] + " " + postData.substr(0, 200)); + Response.writeHead(405, { 'Content-Type': 'text/html' }); + Response.end("Error data parsing"); + } + if (Params[0] === "HTML") + DoCommand(response, Type, Path, [Params[1], Data], remoteAddress); + else + DoCommand(response, Type, Path, [Params[0], Data], remoteAddress); + }); + } + else { + DoCommand(response, Type, Path, params, remoteAddress); + } + }).listen(port, LISTEN_IP, function() { + global.HTTP_SERVER_START_OK = 1; + global.ToLog("Run HTTP-server on " + LISTEN_IP + ":" + port); + }); + HTTPServer.on('error', function(err) { + global.ToError("H##3"); + global.ToError(err); + }); +} +if (global.ELECTRON) { + const ipcMain = require('electron').ipcMain; + ipcMain.on('GetData', function(event, arg) { + event.returnValue = OnGetData(arg); + }); +} +exports.SendData = OnGetData; + +function RunConsole(StrRun) { + var Str = fs.readFileSync("./EXPERIMENTAL/!run-console.js", { encoding: "utf8" }); + if (StrRun) + Str += "\n" + StrRun; + try { + var ret = eval(Str); + } + catch (e) { + ret = e.message + "\n" + e.stack; + } + return ret; +}; +var WebWalletUser = {}; + +function GetUserContext(Params) { + if (typeof Params.Key !== "string") + Params.Key = "" + Params.Key; + var StrKey = Params.Key + "-" + Params.Session; + var Context = WebWalletUser[StrKey]; + if (!Context) { + Context = { NumDappInfo: 0, PrevDappInfo: "", NumAccountList: 0, PrevAccountList: "", LastTime: 0, FromEventNum: 0 }; + WebWalletUser[StrKey] = Context; + } + return Context; +}; +global.GetUserContext = GetUserContext; +global.EventNum = 0; +global.EventMap = {}; + +function AddDappEventToGlobalMap(Data) { + global.EventNum++; + Data.EventNum = global.EventNum; + Data.EventDate = Date.now(); + var Arr = global.EventMap[Data.Smart]; + if (!Arr) { + Arr = []; + global.EventMap[Data.Smart] = Arr; + } + if (Arr.length < 1000) { + Arr.push(Data); + } +}; +global.AddDappEventToGlobalMap = AddDappEventToGlobalMap; + +function DeleteOldEvents(SmartNum) { + var CurDate = Date.now(); + var Arr = global.EventMap[SmartNum]; + while (Arr && Arr.length) { + var Event = Arr[0]; + if (!Event || CurDate - Event.EventDate < 5000) { + break; + } + Arr.splice(0, 1); + } +}; + +function GetEventArray(SmartNum, Context) { + var Arr = global.EventMap[SmartNum]; + if (!Arr || Arr.length === 0) { + return []; + } + var FromEventNum = Context.FromEventNum; + var ArrRet = []; + for (var i = 0; i < Arr.length; i++) { + var Event = Arr[i]; + if (Event.EventNum >= FromEventNum) + ArrRet.push(Event); + } + if (ArrRet.length) { + Context.FromEventNum = ArrRet[ArrRet.length - 1].EventNum + 1; + } + return ArrRet; +}; +HTTPCaller.GetHashRate = function(ArrParams) { + var CurBlockNum = GetCurrentBlockNumByTime(); + var ResArr = []; + for (var i = 0; i < ArrParams.length; i++) { + var Item = ArrParams[i]; + if (!Item) { + ResArr[i] = undefined; + continue; + } + if (Item.BlockNum1 < 0) + Item.BlockNum1 = 0; + if (Item.BlockNum2 > CurBlockNum) + Item.BlockNum2 = CurBlockNum; + var Delta = Item.BlockNum2 - Item.BlockNum1; + var Count = Delta; + if (Count > 20) + Count = 20; + else + if (Count <= 0) + Count = 1; + var StepDelta = Math.floor(Delta / Count); + if (StepDelta < 1) + StepDelta = 1; + var CountAvg = 10; + if (i === ArrParams.length - 1) + CountAvg = 3; + var ItervalArr = []; + for (var Num = Item.BlockNum1; Num < Item.BlockNum2; Num += StepDelta) { + var Power; + var Item2 = BlockTree.LoadValue(Num, 1); + if (Item2 && i !== ArrParams.length - 1) { + Power = Item2.Power; + } + else { + var Sum = 0; + var CountSum = 0; + for (var d = 0; d < CountAvg; d++) { + var Block = global.SERVER.ReadBlockHeaderDB(Num + d); + if (Block) { + CountSum++; + Sum += GetPowPower(Block.PowHash); + } + } + if (!CountSum) + CountSum = 1; + Power = Math.floor(Sum / CountSum); + if (Power) + BlockTree.SaveValue(Num, { BlockNum: Num, Power: Power }); + } + ItervalArr.push(Power); + } + ResArr[i] = ItervalArr; + } + return { result: 1, ItervalArr: ResArr }; +}; diff --git a/src/core/library.ts b/src/core/library.ts new file mode 100644 index 0000000..989ea4e --- /dev/null +++ b/src/core/library.ts @@ -0,0 +1,424 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +import * as fs from 'fs' +import * as os from 'os' + +import './constant' +import './log' + +let { + CONSENSUS_PERIOD_TIME, + ToLog, + TO_ERROR_LOG, + SaveToFile, + TimeStart, + LOAD_CONST, + LoadParams, + GetDataPath, + CONST_NAME_ARR, + SaveParams, + SAVE_CONST, + GetDeltaCurrentTime, +} = global + +Number.prototype.toStringZ = function(count) { + var strnum = this.toString(); + if (strnum.length > count) + count = strnum.length; + else + strnum = "0000000000" + strnum; + return strnum.substring(strnum.length - count, strnum.length); +}; +String.prototype.right = function(count) { + if (this.length > count) + return this.substr(this.length - count, count); + else + return this.substr(0, this.length); +}; +if (fs.existsSync("./lib/bintrees")) + global.RBTree = require("../lib/bintrees").RBTree; +else + global.RBTree = require('bintrees').RBTree; +if (fs.existsSync("./lib/ntp-client")) + global.ntpClient = require('../lib/ntp-client'); +else + global.ntpClient = require('ntp-client'); +global.Stun = require('stun'); +global.ZIP = require("zip"); +var strOS = os.platform() + "_" + os.arch(); +if (global.NWMODE) + strOS = strOS + "-nw" + global.NWVERSION; +if (fs.existsSync("./lib/secp256k1/" + strOS + "/secp256k1.node")) { + try { + global.secp256k1 = require('../lib/secp256k1/' + strOS + '/secp256k1.node'); + } + catch (e) { + } +} +if (!global.secp256k1) { + global.secp256k1 = require('secp256k1'); +} +require('../HTML/JS/terahashlib.js'); +require("./crypto-library"); +if (global.USE_PARAM_JS) { + var PathParams = global.GetCodePath("../extern-run.js"); + if (fs.existsSync(PathParams)) + try { + require(PathParams); + } + catch (e) { + console.log(e); + } +} +global.BufLib = require("../core/buffer"); +require('../HTML/JS/sha3.js'); +require('../HTML/JS/coinlib.js'); +global.GetCurrentBlockNumByTime = function GetCurrentBlockNumByTime() { + var CurTimeNum = global.GetCurrentTime() - global.FIRST_TIME_BLOCK; + var StartBlockNum = Math.trunc((CurTimeNum + CONSENSUS_PERIOD_TIME) / CONSENSUS_PERIOD_TIME); + return StartBlockNum; +}; +global.DelDir = function(Path) { + if (Path.substr(Path.length - 1, 1) === "/") + Path = Path.substr(0, Path.length - 1); + if (fs.existsSync(Path)) { + var arr = fs.readdirSync(Path); + for (var i = 0; i < arr.length; i++) { + var name = Path + "/" + arr[i]; + if (fs.statSync(name).isDirectory()) { + global.DelDir(name); + } + else { + if (name.right(9) == "const.lst") + continue; + if (name.right(7) == "log.log") + continue; + fs.unlinkSync(name); + } + } + } +}; +global.SliceArr = function(arr, start, end) { + var ret = []; + for (var i = start; i < end; i++) { + ret[i - start] = arr[i]; + } + return ret; +}; +var nRand = Math.floor(123 + Math.random() * 1000); + +function random(max) { + return Math.floor(Math.random() * max); +}; +global.random = random; +global.AddrLevelArrFromBegin = function(arr1, arr2) { + var Level = 0; + for (var i = 0; i < arr1.length; i++) { + var a1 = arr1[i]; + var a2 = arr2[i]; + for (var b = 0; b < 8; b++) { + if ((a1 & 128) !== (a2 & 128)) + return Level; + a1 = a1 << 1; + a2 = a2 << 1; + Level++; + } + } + return Level; +}; +global.AddrLevelArr = function(arr1, arr2) { + var Level = 0; + for (var i = arr1.length - 1; i >= 0; i--) { + var a1 = arr1[i]; + var a2 = arr2[i]; + for (var b = 0; b < 8; b++) { + if ((a1 & 1) !== (a2 & 1)) + return Level; + a1 = a1 >> 1; + a2 = a2 >> 1; + Level++; + } + } + return Level; +}; +global.SaveToFile = function(name, buf) { + var fs = require('fs'); + var file_handle = fs.openSync(name, "w"); + fs.writeSync(file_handle, buf, 0, buf.length); + fs.closeSync(file_handle); +}; +global.LoadParams = function(filename, DefaultValue) { + try { + if (fs.existsSync(filename)) { + var Str = fs.readFileSync(filename); + if (Str.length > 0) + return JSON.parse(Str as any); + } + } + catch (err) { + TO_ERROR_LOG("MAINLIB", 100, "Error in file:" + filename + "\n" + err); + } + return DefaultValue; +}; +global.SaveParams = function(filename, data) { + SaveToFile(filename, Buffer.from(JSON.stringify(data, undefined, 4))); +}; +global.StartTime = function() { + global.TimeStart = global.GetCurrentTime(); +}; +global.FinishTime = function(Str) { + Str = Str || ""; + var TimeFinish = global.GetCurrentTime(); + var delta = TimeFinish - TimeStart; + console.log(Str + " time: " + delta + " ms"); +}; +global.CompareItemBufFD = function(a, b) { + if (a.FD !== b.FD) + return a.FD - b.FD; + else + return a.Position - b.Position; +}; +global.CompareArr33 = function(a, b) { + for (var i = 0; i < 33; i++) { + if (a[i] !== b[i]) + return a[i] - b[i]; + } + return 0; +}; +global.CompareItemHashSimple = function(a, b) { + if (a.hash < b.hash) + return - 1; + else + if (a.hash > b.hash) + return 1; + else + return 0; +}; +global.CompareItemHash = function(a, b) { + var hasha = a.hash; + var hashb = b.hash; + for (var i = 0; i < hasha.length; i++) { + if (hasha[i] !== hashb[i]) + return hasha[i] - hashb[i]; + } + return 0; +}; +global.CompareItemHash32 = function(a, b) { + var hasha = a.hash; + var hashb = b.hash; + for (var i = 0; i < 32; i++) { + if (hasha[i] !== hashb[i]) + return hasha[i] - hashb[i]; + } + return 0; +}; +global.CompareItemHASH32 = function(a, b) { + var hasha = a.HASH; + var hashb = b.HASH; + for (var i = 0; i < 32; i++) { + if (hasha[i] !== hashb[i]) + return hasha[i] - hashb[i]; + } + return 0; +}; +global.CompareItemHash33 = function(a, b) { + var hasha = a.hash; + var hashb = b.hash; + for (var i = 0; i < 33; i++) { + if (hasha[i] !== hashb[i]) + return hasha[i] - hashb[i]; + } + return 0; +}; +global.CompareItemHashPow = function(a, b) { + return global.CompareArr(a.HashPow, b.HashPow); +}; +global.CompareItemTimePow = function(a, b) { + if (b.TimePow !== a.TimePow) + return b.TimePow - a.TimePow; + else + return global.CompareArr(a.HashPow, b.HashPow); +}; +global.LOAD_CONST = function() { + var Count = 0; + var constants = LoadParams(global.GetDataPath("const.lst"), {}); + if (constants) { + for (var i = 0; i < CONST_NAME_ARR.length; i++) { + var key = CONST_NAME_ARR[i]; + if (constants[key] !== undefined) { + Count++; + global[key] = constants[key]; + } + } + } + return Count; +}; +var WasStartSaveConst = false; + +function SaveConst() { + var constants = {}; + for (var i = 0; i < CONST_NAME_ARR.length; i++) { + var key = CONST_NAME_ARR[i]; + if (global[key] !== undefined) + constants[key] = global[key]; + } + SaveParams(global.GetDataPath("const.lst"), constants); + WasStartSaveConst = false; +}; +global.SAVE_CONST = function(bForce) { + if (bForce) { + SaveConst(); + } + else { + if (!WasStartSaveConst) + setTimeout(SaveConst, 10 * 1000); + WasStartSaveConst = true; + } +}; + +function CheckGlobalTime() { + global.ntpClient.getNetworkTime("pool.ntp.org", 123, function(err, NetTime) { + if (err) { + TO_ERROR_LOG("MAINLIB", 110, err); + return; + } + var curTime = new Date; + global.DELTA_CURRENT_TIME = NetTime - (curTime as any); + if (isNaN(global.DELTA_CURRENT_TIME) || typeof global.DELTA_CURRENT_TIME !== "number") + global.DELTA_CURRENT_TIME = 0; + else + if (Math.abs(global.DELTA_CURRENT_TIME) > 24 * 3600 * 1000) + global.DELTA_CURRENT_TIME = 0; + global.ToLog("Get global time: " + NetTime); + SAVE_CONST(); + }); + SAVE_CONST(); +}; +global.CheckGlobalTime = CheckGlobalTime; +global.GetDeltaCurrentTime = function() { + if (isNaN(global.DELTA_CURRENT_TIME) || typeof global.DELTA_CURRENT_TIME !== "number") + global.DELTA_CURRENT_TIME = 0; + return global.DELTA_CURRENT_TIME; +}; +global.GetStrTimeUTC = function(now) { + if (!global.GetCurrentTime) + return ":::"; + if (!now) + now = global.GetCurrentTime(); + var Str = "" + now.getUTCDate(); + Str = Str + "." + (1 + now.getUTCMonth()); + Str = Str + "." + now.getUTCFullYear(); + Str = Str + " " + now.getUTCHours(); + Str = Str + ":" + now.getUTCMinutes(); + Str = Str + ":" + now.getUTCSeconds(); + return Str; +}; +global.GetStrOnlyTimeUTC = function(now) { + if (!global.GetCurrentTime) + return ":::"; + if (!now) + now = global.GetCurrentTime(); + var Str; + Str = "" + now.getUTCHours().toStringZ(2); + Str = Str + ":" + now.getUTCMinutes().toStringZ(2); + Str = Str + ":" + now.getUTCSeconds().toStringZ(2); + return Str; +}; + +function GetSecFromStrTime(Str) { + var arr = Str.split(":"); + var Mult = 3600; + var Sum = 0; + for (var i = 0; i < arr.length; i++) { + Sum += Mult * parseInt(arr[i]); + Mult = Mult / 60; + } + return Sum; +}; +global.GetSecFromStrTime = GetSecFromStrTime; +global.GetCurrentTime = function(Delta_Time) { + if (Delta_Time === undefined) + Delta_Time = GetDeltaCurrentTime(); + var curTime: any = new Date; + var Time = new Date(curTime - (- Delta_Time)); + return Time; +}; + +function DateFromBlock(BlockNum) { + var Str; + var now = new Date(global.FIRST_TIME_BLOCK + BlockNum * 1000); + Str = now.toISOString(); + Str = Str.substr(0, Str.indexOf(".")); + Str = Str.replace("T", " "); + return Str; +}; +global.DateFromBlock = DateFromBlock; +var code_base = ' !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\u0402\u0403\u201a\u0453\u201e\u2026\u2020\u2021\u20ac\u2030\u0409\u2039\u040a\u040c\u040b\u040f\u0452\u2018\u2019\u201c\u201d\u2022\u2013\u2014\ufffd\u2122\u0459\u203a\u045a\u045c\u045b\u045f\xa0\u040e\u045e\u0408\xa4\u0490\xa6\xa7\u0401\xa9\u0404\xab\xac\xad\xae\u0407\xb0\xb1\u0406\u0456\u0491\xb5\xb6\xb7\u0451\u2116\u0454\xbb\u0458\u0405\u0455\u0457\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u044f'; +global.NormalizeName = function(Name) { + var Str = ""; + for (var i = 0; i < Name.length; i++) { + var code = Name.charCodeAt(i); + if (code >= 32) + Str += code_base.charAt(code - 32); + } + return Str; +}; +var glEvalMap = {}; + +function CreateEval(formula, StrParams) { + var Ret = glEvalMap[formula]; + if (!Ret) { + eval("function M(" + StrParams + "){return " + formula + "}; Ret=M;"); + glEvalMap[formula] = Ret; + } + return Ret; +}; +global.CreateEval = CreateEval; +var CPU_Count = os.cpus().length; + +function GetCountMiningCPU() { + if (global.COUNT_MINING_CPU) + return global.COUNT_MINING_CPU; + else { + return CPU_Count - 1; + } +}; +global.GetCountMiningCPU = GetCountMiningCPU; +var AddTrMap = []; +AddTrMap[- 6] = "Inner node error"; +AddTrMap[- 5] = "Bad block num"; +AddTrMap[- 4] = "Bad type transaction"; +AddTrMap[- 3] = "Bad time"; +AddTrMap[- 2] = "Bad PoW"; +AddTrMap[- 1] = "Bad length"; +AddTrMap[0] = "Not add"; +AddTrMap[1] = "OK"; +AddTrMap[2] = "Update OK"; +AddTrMap[3] = "Was send"; +AddTrMap[4] = "Added to timer"; +global.AddTrMap = AddTrMap; + +function GrayConnect() { + if (global.NET_WORK_MODE && !global.NET_WORK_MODE.UseDirectIP) + return 1; + else + return 0; +}; +global.GrayConnect = GrayConnect; +var ResConst = LOAD_CONST(); +if (global.START_SERVER) { + if (!ResConst) { + CheckGlobalTime(); + } + else + if (global.CHECK_GLOBAL_TIME) { + CheckGlobalTime(); + } +} diff --git a/src/core/log-strict.ts b/src/core/log-strict.ts new file mode 100644 index 0000000..c299748 --- /dev/null +++ b/src/core/log-strict.ts @@ -0,0 +1,36 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +import * as fs from 'fs' + +let { + ToLog, + MAX_SIZE_LOG +} = global + +function CheckSizeLogFile(file_name, file_name_prev) { + "use strict"; + let FILE_NAME_LOG = file_name; + let FILE_NAME_LOG_PREV = file_name_prev; + setInterval(function() { + try { + var stat = fs.statSync(FILE_NAME_LOG); + if (stat.size > MAX_SIZE_LOG) { + if (fs.existsSync(FILE_NAME_LOG_PREV)) { + fs.unlinkSync(FILE_NAME_LOG_PREV); + } + fs.renameSync(FILE_NAME_LOG, FILE_NAME_LOG_PREV); + global.ToLog("truncate logfile ok"); + } + } + catch (err) { + } + }, 60000); +}; +global.CheckSizeLogFile = CheckSizeLogFile; diff --git a/src/core/log.ts b/src/core/log.ts new file mode 100644 index 0000000..34d3686 --- /dev/null +++ b/src/core/log.ts @@ -0,0 +1,237 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +import * as fs from 'fs' + +import './constant' +import './log-strict' + +let { + GetDataPath, + START_PORT_NUMBER, + CheckSizeLogFile, + ToError, + ToLog, + GetCurrentTime, + DEBUG_MODE, + SERVER +} = global + +var file_name_info = global.GetDataPath("info.log"), file_name_infoPrev = global.GetDataPath("info-prev.log"); +CheckSizeLogFile(file_name_info, file_name_infoPrev); +var file_name_log = global.GetDataPath("log.log"), file_name_logPrev = global.GetDataPath("log-prev.log"); +CheckSizeLogFile(file_name_log, file_name_logPrev); +var file_name_log_web = global.GetDataPath("web.log"), file_name_log_webPrev = global.GetDataPath("web-prev.log"); +CheckSizeLogFile(file_name_log_web, file_name_log_webPrev); +var StartStatTime, file_name_error = global.GetDataPath("err.log"), file_name_errorPrev = global.GetDataPath("err-prev.log"); + +function ToLogFile(e, t, r?) { + t instanceof Error && (t = t.message + "\n" + t.stack), global.START_SERVER || (t = global.PROCESS_NAME + ": " + t), "MAIN" !== global.PROCESS_NAME && process.send ? process.send({ + cmd: "log", + message: t + }) : (console.log(START_PORT_NUMBER + ": " + global.GetStrOnlyTime() + ": " + t), r || SaveToLogFileSync(e, t)); +}; + +function ToLogClient(e, t, r) { + let ArrLogClient = global.ArrLogClient; + e && (ToLogFile(file_name_log, e), t || (t = ""), ArrLogClient.push({ text: global.GetStrOnlyTime() + " " + e, key: t, final: r }), 13 < ArrLogClient.length && ArrLogClient.shift()); +}; +CheckSizeLogFile(file_name_error, file_name_errorPrev), global.ToLog = function(e, t) { + void 0 === t && (t = 1), t && t > global.LOG_LEVEL || (global.ALL_LOG_TO_CLIENT ? ToLogClient(e, void 0, void 0) : ToLogFile(file_name_log, + e)); +}, global.ToLogWeb = function(e) { +}, global.SmallAddr = function(e) { + return e.substr(0, 5); +}, global.ToErrorTrace = function(e) { + global.ToError(e + ":" + (new Error).stack); +}, global.ToLogTrace = function(e) { + global.ToErrorTrace(e); +}, global.ToInfo = function(e) { + ToLogFile(file_name_info, e, 1); +}, global.ToError = function(e) { + ToLogFile(file_name_error, e); +}, global.ArrLogClient = [], global.ToLogClient = ToLogClient, global.ToLogClient0 = ToLogClient; +var CONTEXT_STATS = { Total: {}, Interval: [] }, CONTEXT_ERRORS = { Total: {}, Interval: [] }, CurStatIndex = 0; +let MAX_STAT_PERIOD = global.MAX_STAT_PERIOD; +function GetCurrentStatIndex() { + var e = 2 * MAX_STAT_PERIOD + 2; + return CurStatIndex % e; +}; + +function ResizeArrMax(e) { + for (var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++) + t[o] = Math.max(e[2 * o], e[2 * o + 1]); + return t; +}; + +function ResizeArrAvg(e) { + for (var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++) + t[o] = (e[2 * o] + e[2 * o + 1]) / 2; + return t; +}; + +function ResizeArr(e) { + for (var t = [], r = Math.trunc(e.length / 2), o = 0; o < r; o++) + t[o] = e[2 * o]; + return t; +}; + +function GetDiagramData(e, t) { + var r, o = 2 * MAX_STAT_PERIOD + 2; + r = "MAX:" === t.substr(0, 4); + for (var n, a = MAX_STAT_PERIOD, l = (GetCurrentStatIndex() - a + o) % o, i = (e.Total, []), T = void 0, g = l; g < l + a; g++) { + var S = g % o; + if (n = e.Interval[S]) { + var _ = n[t]; + void 0 !== _ ? r ? i.push(_) : (void 0 !== T ? i.push(_ - T) : i.push(_), T = _) : i.push(0); + } + } + return i; +}; + +function CalcInterval(e, t, r) { + for (var o, n = 2 * MAX_STAT_PERIOD + 2, a = {}, l = (t - r + n) % n, i = e.Total, T = l; T < l + r; T++) { + var g = T % n; + if (o = e.Interval[g]) + break; + } + if (o) + for (var S in i) + "MAX:" === S.substr(0, 4) ? a[S] = 0 : void 0 === o[S] ? a[S] = i[S] : a[S] = i[S] - o[S]; + return a; +}; + +function AddToStatContext(e, t, r?) { + void 0 === r && (r = 1); + var o = e.Total[t]; + o || (o = 0), "MAX:" === t.substr(0, 4) ? o = Math.max(o, r) : o += r, e.Total[t] = o, StartStatTime || (StartStatTime = global.GetStrOnlyTime(0)); +}; + +function CopyStatInterval(e, t) { + var r = e.Interval[t]; + r || (r = {}, e.Interval[t] = r); + var o = e.Total; + for (var n in o) + r[n] = o[n], "MAX:" === n.substr(0, 4) && (o[n] = 0); +}; + +function SaveToLogFileAsync(e, o) { + fs.open(e, "a", void 0, function(e, r) { + if (e) + console.log("Ошибка Ð¾Ñ‚ÐºÑ€Ñ‹Ñ‚Ð¸Ñ Ð»Ð¾Ð³-файла ошибок"); + else { + var t = global.GetStrTime() + " : " + o + "\r\n"; + fs.write(r, t, null, "utf8", function(e, t) { + e ? console.log("Ошибка запиÑи в лог-файл ошибок!") : fs.close(r, function(e) { + e && console.log(e); + }); + }); + } + }); +}; + +function SaveToLogFileSync(e, t) { + try { + var r = global.GetStrTime() + " : " + t + "\r\n", o = fs.openSync(e, "a"); + fs.writeSync(o, r, null, "utf8"), fs.closeSync(o); + } + catch (e) { + console.log(e.message); + } +}; +global.PrepareStatEverySecond = function() { + CurStatIndex++; + var e = GetCurrentStatIndex(); + CopyStatInterval(CONTEXT_STATS, e), CopyStatInterval(CONTEXT_ERRORS, e); +}, global.TO_ERROR_LOG = function(e, t, r, o, n, a) { + r instanceof Error && (r = r.message + "\n"), "rinfo" === o ? r += " from: " + n.address + ":" + n.port : "node" === o && (r += " from: " + n.ip + ":" + n.port); + var l = e + ":" + t; + global.ToError(" ==ERROR== " + l + " " + r), AddToStatContext(CONTEXT_ERRORS, l), global.ADD_TO_STAT("ERRORS"); +}, global.HASH_RATE = 0, global.ADD_HASH_RATE = function(e) { + e /= 1e6, global.HASH_RATE += e, global.ADD_TO_STAT("HASHRATE", e); +}, global.GET_STAT = function(e) { + var t = CONTEXT_STATS.Total[e]; + return t || (t = 0), t; +}, global.ADD_TO_STAT_TIME = function(e, t, r) { + if (global.STAT_MODE) { + if (r && 2 !== global.STAT_MODE) + return; + var o = process.hrtime(t), n = 1e3 * o[0] + o[1] / 1e6; + global.ADD_TO_STAT(e, n); + } +}, global.ADD_TO_STAT = function(e, t, r) { + if (global.STAT_MODE) { + if (r && 2 !== global.STAT_MODE) + return; + AddToStatContext(CONTEXT_STATS, e, t); + } +}, global.GET_STATDIAGRAMS = function(e) { + GetCurrentTime(); + var t = GetCurrentStatIndex(); + if (!e || !e.length) + return []; + for (var r = [], o = 0; o < e.length; o++) { + var n = e[o], a = GetDiagramData(CONTEXT_STATS, n); + r.push({ name: n, maxindex: t, arr: a, starttime: StartStatTime - 0, steptime: 1 }); + } + var l = void 0; + for (o = 0; o < r.length; o++) { + 0 < (T = r[o].arr).length && (void 0 === l || T.length < l) && (l = T.length); + } + for (o = 0; o < r.length; o++) { + var i = r[o], T = i.arr; + l && T.length > l && (T = T.slice(T.length - l)), l && 0 <= ",POWER_MY_WIN,POWER_BLOCKCHAIN,".indexOf("," + i.name + ",") && (T = global.SERVER.GetStatBlockchain(i.name, + l)); + for (var g = 0, S = 0; S < T.length; S++) + T[S] && (g += T[S]); + 0 < T.length && (g /= T.length); + var _ = 1; + if ("MAX:" === i.name.substr(0, 4)) + for (; 500 <= T.length;) + T = ResizeArrMax(T), _ *= 2; + else + for (; 500 <= T.length;) + T = ResizeArrAvg(T), _ *= 2; + i.AvgValue = g, i.steptime = _, i.arr = T.slice(1); + } + return r; +}, global.GET_STATS = function(e) { + var t = global.GetCurrentTime(), r = GetCurrentStatIndex(); + return { + stats: { + Counter: CONTEXT_STATS.Total, Counter10S: CalcInterval(CONTEXT_STATS, r, 10), Counter10M: CalcInterval(CONTEXT_STATS, + r, 600) + }, errors: { + Counter: CONTEXT_ERRORS.Total, Counter10S: CalcInterval(CONTEXT_ERRORS, r, 10), Counter10M: CalcInterval(CONTEXT_ERRORS, + r, 600) + }, period: (t - StartStatTime) / 1e3, Confirmation: [] + }; +}, global.StartCommonStat = function() { + for (var e in CONTEXT_STATS.Total) + return; + global.ClearCommonStat(); +}, global.ClearCommonStat = function() { + StartStatTime = void (CurStatIndex = 0), CONTEXT_STATS = { Total: {}, Interval: [] }, CONTEXT_ERRORS = { Total: {}, Interval: [] }, + global.HASH_RATE = 0, global.SERVER.ClearStat(); +}, global.ResizeArrAvg = ResizeArrAvg, global.ResizeArrMax = ResizeArrMax, DEBUG_MODE ? global.TO_DEBUG_LOG = function(e, t, r, o) { + DEBUG_MODE && ("rinfo" === t && (e += " from: " + r.address + ":" + r.port + " - " + o.length), global.ToLog(e)); +} : global.TO_DEBUG_LOG = function(e, t, r, o) { +}, global.GetStrOnlyTime = function(e) { + if (!global.GetCurrentTime) + return ":::"; + e || (e = global.GetCurrentTime()); + var t = "" + e.getHours().toStringZ(2); + return t = (t = (t = t + ":" + e.getMinutes().toStringZ(2)) + ":" + e.getSeconds().toStringZ(2)) + "." + e.getMilliseconds().toStringZ(3); +}, global.GetStrTime = function(e) { + if (!global.GetCurrentTime) + return ":::"; + e || (e = global.GetCurrentTime()); + var t = "" + e.getDate().toStringZ(2); + return t = (t = (t = (t = (t = (t = t + "." + (1 + e.getMonth()).toStringZ(2)) + "." + e.getFullYear()) + " " + e.getHours().toStringZ(2)) + ":" + e.getMinutes().toStringZ(2)) + ":" + e.getSeconds().toStringZ(2)) + "." + e.getMilliseconds().toStringZ(3); +}; diff --git a/src/core/node.ts b/src/core/node.ts new file mode 100644 index 0000000..134292b --- /dev/null +++ b/src/core/node.ts @@ -0,0 +1,598 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +require("./library.js"); +const net = require("net"); +var ConnectIDCount = 1; +module.exports = class CNode { + addrStr + ip + port + StartFindList + WhiteConnect + GrayConnect + POW + FirstTime + FirstTimeStr + LastTime + LastTimeError + LastTimeTransfer + FromIP + FromPort + Active + Hot + CanHot + CountChildConnect + BlockProcessCount + VersionOK + VersionNum + Delete + DeltaBan + Name + Info + PrevInfo + StartTimeHot + NextHotDelta + LastTimeGetNode + DeltaGlobTime + CountDeltaTime + DeltaTime + SumDeltaTime + TransferCount + StopGetBlock + LevelCount + LevelEnum + TimeMap + bInit + INFO + DoubleConnectCount + StartTimeConnect + NextConnectDelta + StartTimeGetNodes + NextGetNodesDelta + PingStart + NextPing + SendBlockArr + LoadBlockArr + SendBlockCount + LoadBlockCount + SendBlockCountAll + LoadBlockCountAll + WantHardTrafficArr + WantHardTraffic + CanHardTraffic + BufWriteLength + BufWrite + SendPacket + ConnectCount + TrafficArr + SendTrafficCurrent + SendTrafficLimit + ErrCount + ErrCountAll + SendPacketNum + Socket + Socket2 + constructor(addrStr, ip, port) { + this.addrStr = addrStr + this.ip = ip.trim() + this.port = port + this.StartFindList = 0 + this.WhiteConnect = 0 + this.GrayConnect = 0 + this.POW = 0 + this.FirstTime = 0 + this.FirstTimeStr = "" + this.LastTime = 0 + this.LastTimeError = 0 + this.LastTimeTransfer = 0 + this.FromIP = undefined + this.FromPort = undefined + this.Active = false + this.Hot = false + this.CanHot = false + this.CountChildConnect = 0 + this.BlockProcessCount = 0 + this.VersionOK = false + this.VersionNum = 0 + this.Delete = 0 + this.DeltaBan = 300 + this.Name = "" + this.Info = "" + this.PrevInfo = "" + this.StartTimeHot = 0 + this.NextHotDelta = 1000 + this.ResetNode() + } + ResetNode() { + this.LastTimeGetNode = 0 + this.DeltaGlobTime = 0 + this.CountDeltaTime = 0 + this.DeltaTime = 1000 + this.SumDeltaTime = 0 + this.TransferCount = 0 + this.StopGetBlock = 0 + this.LevelCount = 0 + this.LevelEnum = 100 + this.TimeMap = {} + this.bInit = 1 + this.INFO = {} + this.DoubleConnectCount = 0 + this.StartTimeConnect = 0 + this.NextConnectDelta = 1000 + this.StartTimeGetNodes = 0 + this.NextGetNodesDelta = 1000 + this.PingStart = 0 + this.NextPing = MIN_PERIOD_PING + this.SendBlockArr = [] + this.LoadBlockArr = [] + this.SendBlockCount = 0 + this.LoadBlockCount = 0 + this.SendBlockCountAll = 0 + this.LoadBlockCountAll = 0 + this.WantHardTrafficArr = [] + this.WantHardTraffic = 0 + this.CanHardTraffic = 0 + this.BufWriteLength = 0 + this.BufWrite = Buffer.alloc(0) + this.SendPacket = new RBTree(function(a, b) { + return b.PacketNum - a.PacketNum; + }) + this.ConnectCount = 0 + this.TrafficArr = [] + this.SendTrafficCurrent = 0 + this.SendTrafficLimit = 0 + this.ErrCount = 0 + this.ErrCountAll = 0 + var Prioritet = this.BlockProcessCount; + global.SERVER.SetNodePrioritet(this, Prioritet) + this.SendPacketNum = 0 + } + ConnectStatus() { + if (this.Socket) + return GetSocketStatus(this.Socket); + else + return 0; + } + CreateConnect() { + delete global.SERVER.BAN_IP[this.ip] + let NODE = this; + if (NODE.ConnectStatus()) { + if (NODE.ConnectStatus() === 100) + global.SERVER.AddNodeToActive(NODE) + return; + } + global.AddNodeInfo(NODE, "===CreateConnect===") + global.CloseSocket(NODE.Socket, "CreateConnect") + NODE.SocketStart = Date.now() + NODE.Socket = net.createConnection(NODE.port, NODE.ip, function() { + if (NODE.Socket) { + socketInit(NODE.Socket, "s") + global.AddNodeInfo(NODE, "OK connected *" + NODE.Socket.ConnectID) + NODE.Socket.ConnectToServer = true + SetSocketStatus(NODE.Socket, 2) + } + }) + SetSocketStatus(NODE.Socket, 1) + NODE.Socket.Node = NODE + NODE.Socket.ConnectID = "~C" + ConnectIDCount + ConnectIDCount++ + this.SetEventsProcessing(NODE.Socket, 0) + } + CreateReconnection() { + let NODE = this; + global.AddNodeInfo(NODE, "===CreateReconnection===") + global.CloseSocket(NODE.Socket2, "CreateReconnection") + NODE.SocketStart = Date.now() + NODE.Socket2 = net.createConnection(NODE.port, NODE.ip, function() { + if (NODE.Socket2) { + socketInit(NODE.Socket2, "s") + global.AddNodeInfo(NODE, "OK Reconnected *" + NODE.Socket2.ConnectID) + NODE.Socket2.ConnectToServer = true + SetSocketStatus(NODE.Socket2, 2) + } + }) + SetSocketStatus(NODE.Socket2, 1) + NODE.Socket2.Node = NODE + NODE.Socket2.ConnectID = "~R" + ConnectIDCount + ConnectIDCount++ + this.SetEventsProcessing(NODE.Socket2, 1) + } + SwapSockets() { + if (!this.Socket2) + return; + var SocketOld = this.Socket; + this.Socket = this.Socket2 + this.Socket2 = undefined + this.Socket.Node = this + SetSocketStatus(this.Socket, 100) + this.Socket.Buf = SocketOld.Buf + global.SERVER.LoadBufSocketList.remove(SocketOld) + global.SERVER.LoadBufSocketList.insert(this.Socket) + SocketOld.Buf = undefined + SocketOld.WasClose = 1 + SocketOld.Node = undefined + this.ErrCount = 0 + } + SetEventsProcessing(Socket, Reconnection) { + let SOCKET = Socket; + let NODE = this; + let RECONNECTION = Reconnection; + SOCKET.on('data', function(data) { + if (Socket.WasClose) + return; + if (GetSocketStatus(SOCKET) === 2) { + SetSocketStatus(SOCKET, 3) + var Buf = global.SERVER.GetDataFromBuf(data); + if (Buf) { + var Res = NODE.SendPOWFromClientToServer(SOCKET, Buf.Data); + if (Res) { + return; + } + } + global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method : "=CLIENT ON DATA=") + } + else + if (GetSocketStatus(SOCKET) === 3) { + var Buf = global.SERVER.GetDataFromBuf(data); + if (Buf) { + var Str = Buf.Data; + if (Str && Str.substr(0, 24) === "WAIT_CONNECT_FROM_SERVER") { + global.AddNodeInfo(NODE, "2. CLIENT OK POW") + global.CloseSocket(SOCKET, "WAIT_CONNECT_FROM_SERVER") + NODE.WaitConnectFromServer = 1 + NODE.WaitConnectIP = NODE.ip + try { + NODE.SecretForReconnect = global.GetArrFromHex(Str.substr(25)) + } + catch (e) { + NODE.SecretForReconnect = [] + global.ToLog(e) + } + } + else + if (Str === "OK") { + NODE.NextConnectDelta = 1000 + SetSocketStatus(SOCKET, 100) + global.AddNodeInfo(NODE, "4. CLIENT OK CONNECT") + if (RECONNECTION) { + if (NODE.Socket) + SetSocketStatus(NODE.Socket, 200) + } + else { + if (!NODE.Active) + global.SERVER.AddNodeToActive(NODE) + } + return; + } + else + if (Str === "SELF") { + NODE.Self = 1 + } + else + if (Str === "DOUBLE") { + } + else { + global.AddNodeInfo(NODE, "ERROR:" + Str) + } + } + global.CloseSocket(SOCKET, Buf ? "Method=" + Buf.Method + ":" + Str : "=CLIENT ON DATA=") + } + else { + socketRead(Socket, data) + global.SERVER.OnGetFromTCP(NODE, Socket, data) + } + }) + SOCKET.on('end', function() { + if (GetSocketStatus(SOCKET)) + global.AddNodeInfo(NODE, "Get socket end *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET)) + if (GetSocketStatus(SOCKET) === 200) { + NODE.SwapSockets() + SOCKET.WasClose = 1 + } + }) + SOCKET.on('close', function(err) { + if (SOCKET.ConnectID && GetSocketStatus(SOCKET)) + global.AddNodeInfo(NODE, "Get socket close *" + SOCKET.ConnectID + " Stat: " + SocketStatistic(SOCKET)) + if (!SOCKET.WasClose) { + if (GetSocketStatus(SOCKET) >= 2) { + global.CloseSocket(SOCKET, "GET CLOSE") + } + } + SetSocketStatus(SOCKET, 0) + }) + SOCKET.on('error', function(err) { + if (GetSocketStatus(SOCKET) >= 2) { + global.SERVER.AddCheckErrCount(NODE, 1, "ERR##1 : socket") + global.ADD_TO_STAT("ERRORS") + } + }) + } + SendPOWFromClientToServer(Socket, data) { + var Node = this; + if (Node.ReconnectFromServer) { + Node.ReconnectFromServer = 0 + var Info = this.GetPOWClientData(0); + Info.Reconnect = 1 + Info.SecretForReconnect = Node.SecretForReconnect + var BufWrite = global.BufLib.GetBufferFromObject(Info, FORMAT_POW_TO_SERVER, 1200, {}); + var BufAll = global.SERVER.GetBufFromData("POW_CONNECT7", BufWrite, 1); + Socket.write(BufAll) + return 1; + } + try { + var Buf = global.BufLib.GetObjectFromBuffer(data, FORMAT_POW_TO_CLIENT, {}); + } + catch (e) { + global.SERVER.Sendglobal.CloseSocket(Socket, "FORMAT_POW_TO_CLIENT") + return 0; + } + if (global.CompareArr(Buf.addrArr, global.SERVER.addrArr) === 0) { + Node.Self = true + global.AddNodeInfo(Node, "END: SELF") + global.SERVER.Sendglobal.CloseSocket(Socket, "SELF") + return; + } + var addrStr = GetHexFromAddres(Buf.addrArr); + if (!Node.StartFindList && addrStr !== Node.addrStr) { + global.AddNodeInfo(Node, "END: CHANGED ADDR: " + Node.addrStr.substr(0, 16) + "->" + addrStr.substr(0, 16)) + global.SERVER.Sendglobal.CloseSocket(Socket, "ADDRESS_HAS_BEEN_CHANGED") + return; + } + if (Node.addrStrTemp) { + global.AddNodeInfo(Node, "Set Addr = " + addrStr) + Node.addrStr = addrStr + global.SERVER.CheckNodeMap(Node) + } + var Result = false; + if (Buf.PubKeyType === 2 || Buf.PubKeyType === 3) { + Result = secp256k1.verify(Buffer.from(shaarr(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))) + if (!Result) { + Result = secp256k1.verify(Buffer.from(sha3(addrStr)), Buffer.from(Buf.Sign), Buffer.from([Buf.PubKeyType].concat(Buf.addrArr))) + } + } + if (!Result) { + global.ToLog("END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) + global.AddNodeInfo(Node, "END: ERROR_SIGN_SERVER ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) + global.SERVER.Sendglobal.CloseSocket(Socket, "ERROR_SIGN_SERVER") + return; + } + if (Buf.MIN_POWER_POW_HANDSHAKE > 1 + MIN_POWER_POW_HANDSHAKE) { + global.ToLog("END: BIG_MIN_POWER_POW_HANDSHAKE ADDR: " + addrStr.substr(0, 16) + " from ip: " + Socket.remoteAddress) + return 0; + } + var TestNode = global.SERVER.NodesMap[addrStr]; + if (TestNode && TestNode !== Node) { + if (GetSocketStatus(TestNode.Socket)) { + global.AddNodeInfo(Node, "DoubleConnection find") + Node.DoubleConnection = true + return 0; + } + else { + global.AddNodeInfo(Node, "DoubleConnection find") + TestNode.DoubleConnection = true + } + } + Node.PubKey = Buffer.from([Buf.PubKeyType].concat(Buf.addrArr)) + Node.addrArr = Buf.addrArr + Node.addrStr = addrStr + if (global.CompareArr(SERVER.addrArr, Node.addrArr) === 0) { + Node.Self = 1 + return 0; + } + var Hash = shaarr2(Buf.addrArr, Buf.HashRND); + var nonce = CreateNoncePOWExternMinPower(Hash, 0, Buf.MIN_POWER_POW_HANDSHAKE); + var Info; + if (WALLET.WalletOpen && IsDeveloperAccount(WALLET.PubKeyArr)) { + Info = this.GetPOWClientData(0) + Info.Reconnect = 255 + Info.Sign = secp256k1.sign(SHA3BUF(Hash), WALLET.KeyPair.getPrivateKey('')).signature + Result = CheckDevelopSign(Hash, Info.Sign) + if (!Result) { + throw "ERROR DEVELOPSIGN!"; + } + } + else { + Info = this.GetPOWClientData(nonce) + Info.PubKeyType = global.SERVER.PubKeyType + Info.Sign = secp256k1.sign(Buffer.from(Hash), global.SERVER.KeyPair.getPrivateKey('')).signature + } + var BufWrite = global.BufLib.GetBufferFromObject(Info, FORMAT_POW_TO_SERVER, 1200, {}); + var BufAll = global.SERVER.GetBufFromData("POW_CONNECT6", BufWrite, 1); + Socket.write(BufAll) + return 1; + } + GetPOWClientData(nonce) { + var Node = this; + var Info = {}; + Info.DEF_NETWORK = GetNetworkName() + Info.DEF_VERSION = DEF_VERSION + Info.DEF_CLIENT = DEF_CLIENT + Info.addrArr = global.SERVER.addrArr + Info.ToIP = Node.ip + Info.ToPort = Node.port + Info.FromIP = global.SERVER.ip + Info.FromPort = global.SERVER.port + Info.nonce = nonce + Info.Reconnect = 0 + Info.SendBytes = 0 + Info.SecretForReconnect = [] + Info.Reserv = [] + if (GrayConnect()) + Info.GrayConnect = 1 + return Info; + } + write(BufWrite) { + if (!this.Socket) + return; + global.socketWrite(this.Socket, BufWrite) + try { + this.Socket.write(BufWrite) + } + catch (e) { + global.ToError(e) + this.Socket.WasClose = 1 + this.Socket.SocketStatus = 0 + this.Socket.Node = undefined + } + } +}; +global.socketInit = function(Socket, Str) { + if (!Socket) + return; + Socket.GetBytes = 0; + Socket.SendBytes = 0; + Socket.ConnectID = "" + ConnectIDCount + Str; + ConnectIDCount++; +}; +global.socketRead = function(Socket, Buf) { + Socket.GetBytes += Buf.length; +}; +global.socketWrite = function(Socket, Buf) { + Socket.SendBytes += Buf.length; +}; +global.CloseSocket = function(Socket, StrError?, bHide?) { + if (!Socket || Socket.WasClose) { + if (Socket) + Socket.SocketStatus = 0; + return; + } + var Node = Socket.Node; + if (Socket.Node && Socket.Node.Socket2 === Socket && Socket.Node.Socket && Socket.Node.Socket.SocketStatus === 200) + SetSocketStatus(Socket.Node.Socket, 100); + var StrNode = NodeInfo(Socket.Node); + Socket.WasClose = 1; + Socket.SocketStatus = 0; + Socket.Node = undefined; + Socket.end(); + if (!bHide) + global.AddNodeInfo(Node, "CLOSE " + StrNode + " *" + Socket.ConnectID + " - " + StrError); +}; + +function SetSocketStatus(Socket, Status) { + if (Socket && Socket.SocketStatus !== Status) { + if (Status === 100 && (Socket.SocketStatus !== 3 && Socket.SocketStatus !== 200)) { + ToLogTrace("===================ERROR=================== " + Status); + return; + } + if (Status === 100 && Socket.Node) + Socket.Node.LastTime = global.GetCurrentTime() - 0; + Socket.SocketStatus = Status; + Socket.TimeStatus = Date.now(); + } +}; + +function GetSocketStatus(Socket) { + if (Socket && Socket.SocketStatus) { + if (Socket.SocketStatus !== 100) { + var Delta = Date.now() - Socket.TimeStatus; + if (Delta > MAX_WAIT_PERIOD_FOR_STATUS) { + global.CloseSocket(Socket, "MAX_WAIT_PERIOD_FOR_STATUS = " + Socket.SocketStatus + " time = " + Delta); + } + } + return Socket.SocketStatus; + } + else { + return 0; + } +}; + +function SocketInfo(Socket) { + if (Socket) + return "*" + Socket.ConnectID; + else + return ""; +}; + +function SocketStatistic(Socket) { + if (!Socket) + return ""; + var Str = ""; + if (!Socket.SendBytes) + Socket.SendBytes = 0; + if (!Socket.GetBytes) + Socket.GetBytes = 0; + if (Socket.SendBytes) + Str += " Send=" + Socket.SendBytes; + if (Socket.GetBytes) + Str += " Get=" + Socket.GetBytes; + if (GetSocketStatus(Socket)) + Str += " SocketStatus=" + GetSocketStatus(Socket); + if (Str === "") + Str = "0"; + return Str; +}; + +function NodeInfo(Node) { + if (Node) + return "" + Node.ip + ":" + Node.port + " " + SocketInfo(Node.Socket); + else + return ""; +}; + +function NodeName(Node) { + if (!Node) + return ""; + if (Node.Name) + return Node.Name; + if (LOCAL_RUN) + return "" + Node.port; + else { + return "" + Node.ip + ":" + Node.addrStr.substr(0, 6); + } +}; + +function FindNodeByAddr(Addr, bConnect) { + var Node = global.SERVER.NodesMap[Addr.trim()]; + if (Node && Node.ConnectStatus() === 100) + return Node; + if (Node && bConnect) { + Node.NextConnectDelta = 1000; + global.SERVER.StartConnectTry(Node); + return false; + } + return undefined; +}; + +function AddNodeInfo(Node, Str, bSet) { + if (!global.STAT_MODE) + return; + if (!Node) + return; + if (!Node.Info) + Node.Info = ""; + if (bSet) { + Node.Info = ""; + } + else { + if (Node.Socket && Node.Socket.Info) { + Node.Info += Node.Socket.Info + "\n"; + Node.Socket.Info = ""; + } + } + if (Node.Info.length > 1000) { + Node.PrevInfo = Node.Info; + Node.Info = ""; + } + { + var timesend = GetStrOnlyTimeUTC(); + Str = timesend + " " + Str; + Node.Info += Str + "\n"; + } +}; +global.SocketStatistic = SocketStatistic; +global.GetSocketStatus = GetSocketStatus; +global.SetSocketStatus = SetSocketStatus; +global.NodeInfo = NodeInfo; +global.NodeName = NodeName; +global.SocketInfo = SocketInfo; +global.FindNodeByAddr = FindNodeByAddr; +global.AddNodeInfo = AddNodeInfo; diff --git a/src/core/rest-loader.ts b/src/core/rest-loader.ts new file mode 100644 index 0000000..bc1a875 --- /dev/null +++ b/src/core/rest-loader.ts @@ -0,0 +1,453 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +module.exports = class CRest extends require("./db/block-db") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + } + CheckSyncRest() { + var BlockNumTime = GetCurrentBlockNumByTime(); + var Delta = BlockNumTime - this.BlockNumDB; + if (Delta > REST_START_COUNT + DELTA_BLOCK_ACCOUNT_HASH + 500) { + var BlockNumRest = GetCurrentRestNum(REST_START_COUNT + DELTA_BLOCK_ACCOUNT_HASH + 500); + if (this.BlockNumDB >= this.BlockNumDBMin && this.BlockNumDB <= this.BlockNumDBMin + global.BLOCK_PROCESSING_LENGTH2) { + } + else + if (BlockNumRest > this.BlockNumDB) { + } + else { + this.LoadRestContext = undefined + return; + } + this.LoadRestContext = { + Mode: 0, BlockNum: BlockNumRest, BlockNumRest: BlockNumRest, WasDelta: Delta, BlockNumProof: BlockNumRest + DELTA_BLOCK_ACCOUNT_HASH, + CountProof: COUNT_BLOCKS_FOR_LOAD, StartTimeHistory: Date.now(), MaxTimeOut: 600 * 1000, LoopSyncRest: 1, SendGetHeaderCount: 0, + ReceiveHeaderCount: 0, ArrProof: [], MapSend: {} + } + for (var i = 0; i < this.NodesArr.length; i++) { + this.NodesArr[i].SendRestGetHeader = 0 + } + global.ToLog("**********START REST MODE: " + this.LoadRestContext.BlockNumProof) + } + else { + this.LoadRestContext = undefined + } + } + LoopSyncRest() { + let Context = this.LoadRestContext; + switch (Context.Mode) { + case 0: + var ArrNodes = this.GetActualNodes(); + for (var i = 0; i < ArrNodes.length; i++) { + var Node = ArrNodes[i]; + if (!Node || Node.SendRestGetHeader) { + continue; + } + Node.SendRestGetHeader = 1 + global.ToLog("Send rest get headers from " + Context.BlockNumProof + " to " + NodeName(Node), 2) + this.SendF(Node, { + "Method": "GETBLOCKHEADER", "Data": { Foward: 1, BlockNum: Context.BlockNumProof, Hash: [] }, "Context": { F: this.RETBLOCKHEADER_REST.bind(this) }, + }) + Context.SendGetHeaderCount++ + break; + } + if (Context.ReceiveHeaderCount >= COUNT_NODE_PROOF) { + Context.Mode = 2 + global.ToLog("Next mode: " + Context.Mode + " Receive:" + Context.ReceiveHeaderCount + "/" + Context.SendGetHeaderCount, 2) + } + break; + case 1000: + break; + case 2: + var MapSumPower = {}; + for (var i = 0; i < Context.ArrProof.length; i++) { + var Item = Context.ArrProof[i]; + if (!MapSumPower[Item.SumPower]) + MapSumPower[Item.SumPower] = 0 + MapSumPower[Item.SumPower]++ + } + var MaxCount = 0, MaxPow = 0; + for (var key in MapSumPower) { + if (MapSumPower[key] >= MaxCount) { + MaxCount = MapSumPower[key] + MaxPow = parseInt(key) + } + } + if (MaxCount < 2 || MaxPow === 0) { + global.ToLog("****************************************************************** Error MaxPow - reload.") + this.CheckSyncRest() + return; + } + for (var i = 0; i < Context.ArrProof.length; i++) { + var Item = Context.ArrProof[i]; + if (Item.SumPower !== MaxPow) { + var Str = "BAD SumPower: " + Item.SumPower + "/" + MaxPow; + global.ToLog(Str + " from: " + NodeName(Item.Node), 2) + } + else + if (Item.SumPower && Item.arr.length >= Context.CountProof) { + Item.OK = 1 + Context.BlockProof = Item.arr[0] + } + } + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode + " SumPower:" + MaxPow, 2) + break; + case 3: + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) { + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + var Block = { BlockNum: Context.BlockNumRest }; + this.BlockNumDB = Block.BlockNum + this.BlockNumDBMin = Block.BlockNum + this.WriteBlockHeaderDB(Block) + this.UseTruncateBlockDB = undefined + global.TX_PROCESS.RunRPC("TXPrepareLoadRest", Block.BlockNum, function(Err, Params) { + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + }) + } + break; + case 4: + break; + case 5: + let BlockProof = Context.BlockProof; + var SendCount = 0; + if (BlockProof) + for (var i = 0; i < Context.ArrProof.length; i++) { + let Item = Context.ArrProof[i]; + if (Item.OK) { + SendCount++ + global.ToLog("Send rest get block proof:" + BlockProof.BlockNum + " to " + NodeName(Item.Node), 2) + this.SendF(Item.Node, { + "Method": "GETBLOCK", "Data": { BlockNum: BlockProof.BlockNum, TreeHash: BlockProof.TreeHash }, "Context": { + F: function(Info) { + if (Context.TxProof) + return; + var Data = global.BufLib.GetObjectFromBuffer(Info.Data, FORMAT_BLOCK_TRANSFER, WRK_BLOCK_TRANSFER); + Info.Data = undefined + if (Data.BlockNum !== BlockProof.BlockNum || global.CompareArr(Data.TreeHash, BlockProof.TreeHash) !== 0) { + global.ToLog("Error get proof block from " + NodeName(Item.Node), 2) + return; + } + var TreeHash = CalcTreeHashFromArrBody(Data.BlockNum, Data.arrContent); + if (global.CompareArr(BlockProof.TreeHash, TreeHash) !== 0) { + global.ToLog("Error TreeHash in proof block from " + NodeName(Item.Node), 2) + return; + } + global.ToLog("GET BLOCK proof from " + NodeName(Item.Node), 2) + var FindTx = undefined; + for (var n = 0; n < Data.arrContent.length; n++) { + var Body = Data.arrContent[n]; + if (Body[0] === TYPE_TRANSACTION_ACC_HASH) { + try { + FindTx = global.BufLib.GetObjectFromBuffer(Body, FORMAT_ACCOUNT_HASH3, {}) + } + catch (e) { + global.ToLog("Error parsing Body[" + n + "] block proof: " + e, 2) + continue; + } + break; + } + } + if (!FindTx) + return; + Context.TxProof = FindTx + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + Context.AccTaskList = [] + Context.AccTaskFinished = 0 + var AccCount = FindTx.AccountMax + 1; + for (var n = 0; n < AccCount; n += MAX_ACCOUNTS_TRANSFER) { + var Task = { StartNum: n, Count: MAX_ACCOUNTS_TRANSFER, Time: 0, MapSend: {} }; + if (Task.StartNum + Task.Count > AccCount) + Task.Count = AccCount - Task.StartNum + Context.AccTaskList.push(Task) + } + Context.SmartTaskList = [] + Context.SmartTaskFinished = 0 + for (var n = 0; n < FindTx.SmartCount; n += MAX_SMARTS_TRANSFER) { + var Task = { StartNum: n, Count: MAX_SMARTS_TRANSFER, Time: 0, MapSend: {} }; + if (Task.StartNum + Task.Count > FindTx.SmartCount) + Task.Count = FindTx.SmartCount - Task.StartNum + Context.SmartTaskList.push(Task) + } + } + }, + }) + if (SendCount >= 5) + break; + } + } + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + break; + case 6: + break; + case 7: + if (Context.AccTaskFinished === Context.AccTaskList.length) { + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + break; + } + var CurTime = Date.now(); + for (var i = 0; i < Context.AccTaskList.length; i++) { + let Task = Context.AccTaskList[i]; + var Delta = CurTime - Task.Time; + if (Delta > 5 * 1000 && !Task.OK) { + var Ret = this.GetNextNode(Task, "", 1); + if (Ret.Result) { + global.ToLog("Send GETREST Num:" + Task.StartNum + "-" + Task.Count + " to " + NodeName(Ret.Node), 2) + var SELF = this; + this.SendF(Ret.Node, { + "Method": "GETREST", "Data": { BlockNum: Context.BlockNumRest, AccNum: Task.StartNum, Count: Task.Count, AccHash: Context.TxProof.AccHash }, + "Context": { + F: function(Info) { + if (Task.OK) + return; + var Data = SELF.DataFromF(Info); + if (!Data.Result) + return; + if (Data.Version !== 1) { + global.ToLog("ERROR Version Result GETREST Num:" + Task.StartNum + " from " + NodeName(Info.Node), 2) + return; + } + if (CompareArrL(Data.ProofHash, Context.TxProof.AccHash) !== 0) { + global.ToLog("ERROR PROOF HASH Result GETREST Num:" + Task.StartNum + " Hash: " + global.GetHexFromArr(Data.ProofHash) + "/" + global.GetHexFromArr(Context.TxProof.AccHash) + " from " + NodeName(Info.Node), + 2) + return; + } + var ArrM = []; + for (var i = 0; i < Data.Arr.length; i++) { + ArrM[i] = global.shaarr(Data.Arr[i]) + } + var GetHash = CheckMerkleProof(Data.ProofArrL, ArrM, Data.ProofArrR); + if (CompareArrL(GetHash, Context.TxProof.AccHash) !== 0) { + global.ToLog("ERROR CALC PROOF HASH Result GETREST Num:" + Task.StartNum + " Hash: " + global.GetHexFromArr(GetHash) + "/" + global.GetHexFromArr(Context.TxProof.AccHash) + " from " + NodeName(Info.Node), + 2) + return; + } + global.ToLog("OK Result GETREST Num:" + Task.StartNum + " arr=" + Data.Arr.length + " from " + NodeName(Info.Node), 2) + if (!global.TX_PROCESS || !global.TX_PROCESS.RunRPC) { + global.ToLog("ERROR global.TX_PROCESS") + return; + } + Task.OK = 1 + global.TX_PROCESS.RunRPC("TXWriteAccArr", { StartNum: Task.StartNum, Arr: Data.Arr }, function(Err, Params) { + Context.AccTaskFinished++ + }) + } + }, + }) + Task.Time = CurTime + break; + } + } + } + break; + case 8: + if (Context.SmartTaskFinished === Context.SmartTaskList.length) { + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + break; + } + var CurTime = Date.now(); + for (var i = 0; i < Context.SmartTaskList.length; i++) { + let Task = Context.SmartTaskList[i]; + var Delta = CurTime - Task.Time; + if (Delta > 3 * 1000 && !Task.OK) { + var Ret = this.GetNextNode(Task, "", 1); + if (Ret.Result) { + global.ToLog("Send GETSMART Num:" + Task.StartNum + "-" + Task.Count + " to " + NodeName(Ret.Node), 2) + var SELF = this; + this.SendF(Ret.Node, { + "Method": "GETSMART", "Data": { BlockNum: Context.BlockNumRest, SmartNum: Task.StartNum, Count: Task.Count }, + "Context": { + F: function(Info) { + if (Task.OK) + return; + var Data = SELF.DataFromF(Info); + if (!Data.Result) + return; + global.ToLog("Result GETSMART Num:" + Task.StartNum + " arr=" + Data.Arr.length + " from " + NodeName(Info.Node), 2) + Task.Node = Info.Node + if (!global.TX_PROCESS || !global.TX_PROCESS.RunRPC) + return; + Task.OK = 1 + global.TX_PROCESS.RunRPC("TXWriteSmartArr", { StartNum: Task.StartNum, Arr: Data.Arr }, function(Err, Params) { + Context.SmartTaskFinished++ + }) + } + }, + }) + Task.Time = CurTime + break; + } + } + } + break; + case 9: + if (!global.TX_PROCESS || !global.TX_PROCESS.RunRPC) + return; + var ErrSmartNum = CheckHashSmarts(Context.TxProof.SmartHash); + if (ErrSmartNum > 0) { + var Str = "Error hash in smart num: " + ErrSmartNum; + global.ToLog(Str, 2) + var t = Math.trunc(ErrSmartNum / MAX_SMARTS_TRANSFER); + var Task = Context.SmartTaskList[t]; + if (!Task) { + global.ToLog("error task number: " + t) + Context.Mode = 100 + } + else { + Task.OK = 0 + Context.Mode-- + Context.SmartTaskFinished-- + this.AddToBan(Task.Node, Str) + } + break; + } + var SELF = this; + global.TX_PROCESS.RunRPC("TXWriteAccHash", {}, function(Err, Params) { + if (!Params) + return; + if (global.CompareArr(Context.TxProof.AccHash, Params.AccHash) === 0 && global.CompareArr(Context.TxProof.SmartHash, Params.SmartHash) === 0) { + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + } + else { + global.ToLog("ERROR RESTS LOAD:") + global.ToLog("Must AccHash:" + global.GetHexFromArr(Context.TxProof.AccHash)) + global.ToLog("Must SmartHash:" + global.GetHexFromArr(Context.TxProof.SmartHash)) + global.ToLog("Write AccHash:" + global.GetHexFromArr(Params.AccHash)) + global.ToLog("Write SmartHash:" + global.GetHexFromArr(Params.SmartHash)) + SELF.BlockNumDB = 0 + SELF.BlockNumDBMin = 0 + SELF.UseTruncateBlockDB = undefined + global.TX_PROCESS.RunRPC("TXPrepareLoadRest", 0, function(Err, Params) { + }) + Context.Mode = 100 + } + }) + Context.Mode++ + global.ToLog("Next mode: " + Context.Mode, 2) + break; + case 10: + break; + case 11: + var Context2 = this.LoadHistoryContext; + Context2.BlockNum = this.LoadRestContext.BlockNumRest + Context2.StartTimeHistory = Date.now() + Context.Mode = 200 + break; + case 200: + global.ToLog("Error state!") + break; + } + } + RETBLOCKHEADER_REST(Info, CurTime) { + if (Info.Node.SendRestGetHeader === 2) + return; + Info.Node.SendRestGetHeader = 2 + var Context = this.LoadRestContext; + var BufRead = global.BufLib.GetReadBuffer(Info.Data); + var arr = this.GetBlockArrFromBuffer_Load(BufRead, Info); + global.ToLog("RETBLOCKHEADER_FOWARD SyncRest from " + NodeName(Info.Node) + " arr=" + arr.length, 2) + Context.ReceiveHeaderCount++ + var MinSumPow = 10 * Context.CountProof; + var SumPower = 0; + if (arr.length >= Context.CountProof) + for (var i = 0; i < Context.CountProof; i++) { + SumPower += arr[i].Power + } + if (SumPower <= MinSumPow) + SumPower = 0 + Context.ArrProof.push({ Node: Info.Node, SumPower: SumPower, arr: arr, BufRead: BufRead }) + } + static + GETSMART_F() { + return "{\ + SmartNum:uint,\ + Count:uint,\ + }"; + } + static + RETSMART_F() { + return global.FORMAT_SMART_TRANSFER; + } + static + GETREST_F() { + return "{\ + BlockNum:uint,\ + AccNum:uint,\ + Count:uint,\ + AccHash:hash,\ + }"; + } + static + RETREST_F() { + return global.FORMAT_REST_TRANSFER; + } + SendLoadToBegin() { + return; + if (!this.BlockNumDBMin) + return; + if (!this.ContextSendLoadToBegin) + this.ContextSendLoadToBegin = { Time: 0, MapSend: {} } + var Context = this.ContextSendLoadToBegin; + var CurTime = Date.now(); + var Delta = CurTime - Context.Time; + if (Delta < 2 * 1000) + return; + var BlockDB = this.ReadBlockHeaderDB(this.BlockNumDBMin + 1); + if (!BlockDB) + return; + Context.BlockNum = BlockDB.BlockNum + var Ret = this.GetNextNode(Context, Context.BlockNum, 1); + if (Ret.Result) { + var Node = Ret.Node; + global.ToLog("LOAD_TO_BEGIN - from: " + BlockDB.BlockNum + " to " + NodeName(Node), 2) + Context.Time = CurTime + this.SendF(Node, { + "Method": "GETBLOCKHEADER", "Data": { Foward: 0, BlockNum: Context.BlockNum, Hash: BlockDB.Hash, IsSum: 0, Count: global.COUNT_HISTORY_BLOCKS_FOR_LOAD }, + "Context": { + F: function(Info) { + global.ToLog("GET LOAD_TO_BEGIN from " + NodeName(Info.Node) + " Length=" + Info.Data.length, 2) + } + } + }) + } + } +}; + +function CheckHashSmarts(LastSumHash) { + global.DApps.Smart.Close(); + var MaxNum = global.DApps.Smart.GetMaxNum(); + var Item = global.DApps.Smart.DBSmart.Read(MaxNum); + if (global.CompareArr(Item.SumHash, LastSumHash) !== 0) + return MaxNum; + var WorkStruct = {}; + for (var Num = MaxNum; Num >= 1; Num--) { + var PrevItem = global.DApps.Smart.DBSmart.Read(Num - 1); + if (!PrevItem) + return Num; + var WasSumHash = Item.SumHash; + Item.SumHash = []; + var Buf = global.BufLib.GetBufferFromObject(Item, global.DApps.Smart.FORMAT_ROW, 20000, WorkStruct); + var Hash = global.sha3(Buf); + var SumHash = sha3arr2(PrevItem.SumHash, Hash); + if (global.CompareArr(SumHash, WasSumHash) !== 0) + return Num; + Item = PrevItem; + } + return 0; +}; diff --git a/src/core/rest_tables.ts b/src/core/rest_tables.ts new file mode 100644 index 0000000..7df51d3 --- /dev/null +++ b/src/core/rest_tables.ts @@ -0,0 +1,73 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + + +function DoRest(r,t,e) +{ + var u = r.Arr[0], o = Math.floor(e / REST_BLOCK_SCALE); + if(o !== Math.floor((u.BlockNum - 1) / REST_BLOCK_SCALE)) + { + for(var n = GetRestArr(o), l = [], a = n.length - 2; 0 <= a; a--) + l.push(n[a] * REST_BLOCK_SCALE); + RestPush(r, l, e, 1); + } + r.Arr[0] = {BlockNum:e, Value:t.Value}; +}; + +function RestPush(r,t,e,u) +{ + var o = r.Arr[u - 1], n = r.Arr[u]; + if(1 < u) + { + var l = t[u - 2]; + if(o.BlockNum > l) + return ; + } + if(n.BlockNum && n.BlockNum >= e || o.BlockNum >= e) + return n.BlockNum = 0, void (n.Value = {}); + n.BlockNum && u < r.Arr.length - 1 && RestPush(r, t, e, u + 1), r.Arr[u] = o; +}; + +function GetRestArr(r) +{ + for(var t = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], e = t.length, u = 0; u <= r; u++) + for(var o = 0, n = u, l = e - 1; 0 <= l; l--) + { + var a = t[l]; + if(t[l] = n, n = a, 0 == ((o = o << 4 | 15) & u)) + break; + if(0 != (o & n)) + break; + } + return t; +}; +var RestArrMap = {}; + +function GetCurrentRestArr() +{ + var r = GetCurrentBlockNumByTime(), t = Math.floor(r / REST_BLOCK_SCALE), e = RestArrMap[t]; + if(void 0 === e) + { + RestArrMap = {}, (e = GetRestArr(t)).length = e.length - 1; + for(var u = 0; u < e.length; u++) + e[u] = e[u] * REST_BLOCK_SCALE; + RestArrMap[t] = e; + } + return e; +}; + +function GetCurrentRestNum(r) +{ + for(var t = GetCurrentBlockNumByTime() - r, e = GetCurrentRestArr(), u = e.length - 1; 0 <= u; u--) + if(e[u] <= t) + return e[u]; + return 0; +}; +global.DoRest = DoRest, global.GetRestArr = GetRestArr, global.GetCurrentRestArr = GetCurrentRestArr, global.GetCurrentRestNum = GetCurrentRestNum; diff --git a/src/core/server.ts b/src/core/server.ts new file mode 100644 index 0000000..a631c76 --- /dev/null +++ b/src/core/server.ts @@ -0,0 +1,1061 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const net = require("net"); +const dgram = require("dgram"); +import * as crypto from 'crypto'; +require("./library.js"); +require("./crypto-library"); +const HARD_PACKET_PERIOD = 20; +global.BUF_TYPE = 1; +global.STR_TYPE = 2; +global.MAX_STR_BUF_DATA = 200; +global.MAX_CONNECTION_ACTIVE = 40; +var MAX_CONNECTION_ANOTHER = 40; +const TRAFIC_LIMIT_NODE_1S = MAX_BLOCK_SIZE * 1.25; +const TRAFIC_LIMIT_1S = 8 * TRAFIC_LIMIT_NODE_1S; +global.STAT_PERIOD = CONSENSUS_PERIOD_TIME / 5; +const TRAFIC_LIMIT_SEND = TRAFIC_LIMIT_1S * STAT_PERIOD / 1000; +const TRAFIC_LIMIT_NODE = TRAFIC_LIMIT_NODE_1S * STAT_PERIOD / 1000; +const BUF_PACKET_SIZE = 32 * 1024; +global.FORMAT_POW_TO_CLIENT = "{addrArr:hash,HashRND:hash,MIN_POWER_POW_HANDSHAKE:uint,PubKeyType:byte,Sign:arr64,Reserve:arr33}"; +global.FORMAT_POW_TO_SERVER = "{\ + DEF_NETWORK:str15,\ + DEF_VERSION:str9,\ + DEF_CLIENT:str16, \ + addrArr:addres, \ + ToIP:str26,\ + ToPort:uint16, \ + FromIP:str26,\ + FromPort:uint16, \ + nonce:uint,\ + Reconnect:byte,\ + SendBytes:uint,\ + PubKeyType:byte,\ + Sign:arr64,\ + SecretForReconnect:arr20,\ + GrayConnect:byte,\ + Reserve:arr14\ + }"; +const WorkStructPacketSend = {}; +const FORMAT_PACKET_SEND_TCP = "{\ + PacketSize:uint,\ + NumXORRND:uint,\ + Method:str25,\ + NodeTime:time,\ + Length:uint,\ + ContextID:hash,\ + TypeData:byte,\ + Hash:hash,\ + Data:data,\ + }"; +module.exports = class CTransport extends require("./connect") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.UseRNDHeader = UseRNDHeader + this.BAN_IP = {} + this.ip = RunIP.trim() + this.port = RunPort + this.CanSend = 0 + this.SendFormatMap = {} + this.ActualNodes = new RBTree(function(a, b) { + if (b.Prioritet !== a.Prioritet) + return b.Prioritet - a.Prioritet; + return global.CompareArr(a.addrArr, b.addrArr); + }) + this.SendTrafficFree = 0 + this.LoadedPacketNum = 0 + this.LoadedSocketNum = 0 + setInterval(this.DoLoadBuf.bind(this), 1) + this.LoadBufSocketList = new RBTree(function(a, b) { + if (b.SocketPrioritet !== a.SocketPrioritet) + return b.SocketPrioritet - a.SocketPrioritet; + return a.SocketNum - b.SocketNum; + }) + this.BusyLevel = 0 + this.LastTimeHard = 0 + this.LastTimeHardOK = 0 + setInterval(this.DoHardPacketForSend.bind(this), HARD_PACKET_PERIOD) + this.HardPacketForSend = new RBTree(function(a, b) { + if (b.BlockProcessCount === a.BlockProcessCount) + return a.PacketNum - b.PacketNum; + else + return b.BlockProcessCount - a.BlockProcessCount; + }) + setInterval(this.DoSendPacket.bind(this), 2) + setInterval(this.DoSendBuf.bind(this), 1) + var Map = {}; + this.MethodTiming = Map + MethodTiming: + { + Map["TRANSFER"] = { Period: 700, Hot: 1 } + Map["TRANSFERTX"] = { Period: 700, Hot: 1 } + Map["TIME"] = { Period: 2000, LowVersion: 1, Hard: 1, Immediately: 1 } + Map["PING"] = { Period: 4000, LowVersion: 1, Hard: 1, Immediately: 1 } + Map["PONG"] = { Period: 0, LowVersion: 1, Immediately: 1 } + Map["ADDLEVELCONNECT"] = { Period: 1000, Hard: 1 } + Map["RETADDLEVELCONNECT"] = { Period: 0 } + Map["DISCONNECTHOT"] = { Period: 1000, Hard: 1 } + Map["GETMESSAGE"] = { Period: 1000, Hard: 1 } + Map["MESSAGE"] = { Period: 1000, Hard: 1 } + Map["TRANSACTION"] = { Period: PERIOD_GET_BLOCK, Hard: 1 } + Map["GETBLOCKHEADER"] = { Period: PERIOD_GET_BLOCK, Hard: 2, Process: global.STATIC_PROCESS } + Map["GETBLOCKHEADER100"] = { Period: PERIOD_GET_BLOCK, Hard: 2, Process: global.STATIC_PROCESS } + Map["GETBLOCK"] = { Period: PERIOD_GET_BLOCK, Hard: 2, Process: global.STATIC_PROCESS } + Map["GETNODES"] = { Period: 1000, Hard: 1, LowVersion: 1, IsAddrList: 1 } + Map["RETGETNODES"] = { Period: 0, IsAddrList: 1 } + Map["RETGETNODES2"] = { Period: 0, IsAddrList: 1 } + Map["GETCODE"] = { Period: 10000, Hard: 1, LowVersion: 1, Process: global.STATIC_PROCESS } + Map["RETBLOCKHEADER"] = { Period: 0 } + Map["RETBLOCKHEADER100"] = { Period: 0 } + Map["RETGETBLOCK"] = { Period: 0 } + Map["RETCODE"] = { Period: 0 } + Map["GETREST"] = { Period: 1000, Hard: 2, Process: global.STATIC_PROCESS } + Map["RETREST"] = { Period: 0 } + Map["GETSMART"] = { Period: 1000, Hard: 2, Process: global.STATIC_PROCESS } + Map["RETSMART"] = { Period: 0 } + } + if (!this.VirtualMode) + this.StartServer() + this.CurrentTimeStart = 0 + this.CurrentTimeValues = {} + this.LoadNodesFromFile() + } + GetF(Method, bSend) { + var name = Method + "-" + bSend; + var format = this.SendFormatMap[name]; + if (!format) { + var F = this.constructor[Method + "_F"]; + if (typeof F === "function") { + format = { struct: F(bSend), length: 8096, wrk: {} } + } + else { + format = "{}" + } + this.SendFormatMap[name] = format + } + return format; + } + SendF(Node, Info, Length) { + var format = this.GetF(Info.Method, true); + if (!Length) + Length = format.length + Info.Data = global.BufLib.GetBufferFromObject(Info.Data, format.struct, Length, format.wrk) + this.Send(Node, Info, 1) + } + DataFromF(Info, bSendFormat) { + var format = this.GetF(Info.Method, bSendFormat); + try { + var Data = global.BufLib.GetObjectFromBuffer(Info.Data, format.struct, format.wrk); + return Data; + } + catch (e) { + global.ToLog(e) + return {}; + } + } + ADD_CURRENT_STAT_TIME(Key, Value) { + var TimeNum = Math.floor(Date.now() / STAT_PERIOD); + if (this.CurrentTimeStart !== TimeNum) + this.CurrentTimeValues = {} + this.CurrentTimeStart = TimeNum + if (!this.CurrentTimeValues[Key]) + this.CurrentTimeValues[Key] = 0 + this.CurrentTimeValues[Key] += Value + } + GET_CURRENT_STAT_TIME(Key) { + var TimeNum = Math.floor(Date.now() / STAT_PERIOD); + if (this.CurrentTimeStart === TimeNum) { + var Value = this.CurrentTimeValues[Key]; + if (Value === undefined) + return 0; + else + return Value; + } + else { + return 0; + } + } + RecalcSendStatictic() { + var TimeNum = Math.floor(Date.now() / STAT_PERIOD); + if (this.SendStatNum === TimeNum) + return; + this.SendStatNum = TimeNum + var Period = CONSENSUS_PERIOD_TIME / STAT_PERIOD; + this.SendTrafficFree = TRAFIC_LIMIT_SEND + var it = this.ActualNodes.iterator(), Node; + while ((Node = it.next()) !== null) { + { + var arr = Node.TrafficArr; + arr.push(Node.BufWriteLength) + Node.BufWriteLength = 0 + if (arr.length > 5 * Period) { + arr.shift() + } + else { + if (arr.length < 3 * Period) + continue; + } + var arrAvg = [], arrK = []; + var valNext = CalcStatArr(arr, arrAvg, arrK, Period); + valNext = Math.min(valNext, TRAFIC_LIMIT_NODE) + Node.SendTrafficLimit = Math.min(this.SendTrafficFree, valNext * 1.1) + this.SendTrafficFree -= Node.SendTrafficLimit + } + Node.SendTrafficCurrent = 0 + global.ADD_TO_STAT("MAX:NODE_TRAFFIC_LIMIT:" + NodeName(Node), 1000 / STAT_PERIOD * Node.SendTrafficLimit / 1024, 1) + } + this.SendTrafficFree += TRAFIC_LIMIT_NODE + global.ADD_TO_STAT("SEND_TRAFFIC_FREE", this.SendTrafficFree / 1024) + } + OnGetMethod(Info, CurTime) { + if (DEBUG_MODE) { + var Str = ""; + if (Info.Data && Info.Data.Length) + Str = " LENGTH=" + Info.Data.Length + TO_DEBUG_LOG("GET:" + Info.Method + Str + " from: Node=" + NodeInfo(Info.Node)) + } + if (global.ADDRLIST_MODE) { + var StrOK = ",HAND,GETNODES,"; + if (StrOK.indexOf("," + Info.Method + ",") === - 1) + return; + } + Info.Node.LastTime = CurTime - 0 + if (Info.Context && typeof Info.Context.F === "function") { + Info.Context.F(Info, CurTime) + } + else { + var F = this[Info.Method.toUpperCase()]; + if (typeof F === "function") { + F.bind(this)(Info, CurTime) + } + else { + TO_ERROR_LOG("TRANSPORT", 20, "Method '" + Info.Method + "' not found Socket=*" + Info.Socket.ConnectID, "node", Info.Node) + this.AddCheckErrCount(Info.Node, 1, "Method not found") + } + } + } + GetActualNodes() { + var Arr = []; + var it = this.ActualNodes.iterator(), Item; + while ((Item = it.next()) !== null) { + if (GetSocketStatus(Item.Socket) >= 100) + Arr.push(Item) + else { + this.DeleteNodeFromActive(Item) + } + } + return Arr; + } + NodeIp(Node) { + if (Node.ip_arrival) { + return { ip: Node.ip_arrival, port: Node.port_arrival }; + } + else { + return { ip: Node.ip, port: Node.port }; + } + } + SetXORHeader(buf, bForce) { + if (this.UseRNDHeader || bForce) { + var HashHashSign = global.shaarr(buf.slice(buf.length - 32, buf.length)); + for (var i = 0; i < 32; i++) + buf[i] = HashHashSign[i] ^ buf[i] + } + } + WasBanIP(rinfo) { + if (!rinfo || !rinfo.address) + return false; + var Key = "" + rinfo.address.trim(); + var Stat = this.BAN_IP[Key]; + if (Stat) { + if (Stat.TimeTo > (GetCurrentTime(0) - 0)) + return true; + } + return false; + } + NodeInBan(Node) { + return this.WasBanIP({ address: Node.ip }); + } + DeleteNodeFromActiveByIP(ip) { + var Arr = this.GetActualNodes(); + for (var i = 0; i < Arr.length; i++) { + var Node = Arr[i]; + if (Node.ip === ip) { + this.DeleteNodeFromActive(Node) + } + } + } + AddToBan(Node, Str) { + if (global.NeedRestart) + return; + this.DeleteNodeFromActive(Node) + if (!Node.ip) + return; + var Key = "" + Node.ip.trim(); + if (!Node.DeltaBan) + Node.DeltaBan = 300 + if (Node.DeltaBan > 1000000) + Node.DeltaBan = 1000000 + Node.DeltaBan = Node.DeltaBan * 2 + var TimeTo = (GetCurrentTime(0) - 0) + Node.DeltaBan * 1000; + this.BAN_IP[Key] = { TimeTo: TimeTo } + Node.BlockProcessCount = 0 + this.DeleteNodeFromActiveByIP(Node.ip) + global.ADD_TO_STAT("AddToBan") + } + AddToBanIP(ip, Str, Period) { + if (!Period) + Period = 600 * 1000 + var Key = "" + ip.trim(); + this.BAN_IP[Key] = { TimeTo: (GetCurrentTime(0) - 0) + Period } + this.DeleteNodeFromActiveByIP(ip) + global.ToLog("ADD TO BAN:: " + Key + " " + Str) + global.ADD_TO_STAT("AddToBanIP") + } + OnPacketTCP(Meta) { + var startTime = process.hrtime(); + global.ADD_TO_STAT("USEPACKET") + var CurTime = global.GetCurrentTime(); + Meta.Node.LastTime = CurTime - 0 + if (Meta.MethodTiming.Process && Meta.MethodTiming.Process.Worker) { + var Data = this.DataFromF(Meta); + Meta.MethodTiming.Process.Worker.send({ cmd: Meta.Method, Data: Data, addrStr: Meta.Node.addrStr, Context: Meta.Context }) + } + else { + this.OnGetMethod(Meta, CurTime) + } + ADD_TO_STAT_TIME("MAX:TIME_USE_PACKET", startTime) + ADD_TO_STAT_TIME("TIME_USE_PACKET", startTime) + ADD_TO_STAT_TIME("MAX:TIME_USE_PACKET:" + Meta.Method, startTime) + } + GetBufFromData(Method, Data, TypeData, ContextID) { + var BufData; + if (TypeData === BUF_TYPE) { + BufData = Data + } + else + if (TypeData === STR_TYPE) { + BufData = Buffer.from(Data.substr(0, MAX_STR_BUF_DATA)) + } + else { + if (Data === undefined) { + TypeData = BUF_TYPE + BufData = Buffer.alloc(0) + } + else { + throw "ERROR TYPE DATA"; + } + } + var BUF = {}; + BUF.PacketSize = 0 + BUF.NumXORRND = 0 + BUF.Method = Method + BUF.NodeTime = global.GetCurrentTime() + BUF.TypeData = TypeData + BUF.Length = BufData.length + BUF.Data = BufData + BUF.ContextID = ContextID + BUF.Hash = this.GetHashFromData(BUF) + var BufWrite = global.BufLib.GetBufferFromObject(BUF, FORMAT_PACKET_SEND_TCP, BufData.length + 300, WorkStructPacketSend); + BufWrite.len = 0 + global.BufLib.Write(BufWrite, BufWrite.length, "uint") + return BufWrite; + } + GetDataFromBuf(buf) { + try { + var Meta = global.BufLib.GetObjectFromBuffer(buf, FORMAT_PACKET_SEND_TCP, WorkStructPacketSend); + } + catch (e) { + TO_ERROR_LOG("TRANSPORT", 640, "Error parsing Buffer") + return undefined; + } + var Hash = this.GetHashFromData(Meta); + if (global.CompareArr(Hash, Meta.Hash) !== 0) { + if (global.WATCHDOG_DEV) + global.ToLog("TRANSPORT", 645, "Error hash Buffer", 2) + return undefined; + } + if (Meta.TypeData === STR_TYPE) { + Meta.Data = Meta.Data.slice(0, MAX_STR_BUF_DATA).toString() + } + return Meta; + } + GetHashFromData(Info) { + return global.shaarr(Info.Method + Info.Length + "-" + (Info.NodeTime - 0)); + } + OnGetFromTCP(Node, Socket, Buf) { + if (!Node) + return; + if (!Node.Socket) + Node.Socket = Socket + if (!Socket.Buf || Socket.Buf.length === 0) { + Socket.Buf = Buf + } + else { + Socket.Buf = Buffer.concat([Socket.Buf, Buf]) + } + if (!Socket.SocketNum) { + this.LoadedSocketNum++ + Socket.SocketNum = this.LoadedSocketNum + Socket.SocketPrioritet = Node.BlockProcessCount + } + this.LoadBufSocketList.insert(Socket) + } + DoLoadBuf() { + var Socket = this.LoadBufSocketList.min(); + if (!Socket) + return; + this.LoadBufSocketList.remove(Socket) + if (Socket.WasClose) + return; + while (true) { + if (Socket.Buf && Socket.Buf.length > 6) { + global.ADD_TO_STAT("MAX:BUFFE_LOAD_SIZE", Socket.Buf.length / 1024) + Socket.Buf.len = 0 + var PacketSize = global.BufLib.Read(Socket.Buf, "uint"); + if (PacketSize > MAX_PACKET_LENGTH) { + this.SendCloseSocket(Socket, "MAX_PACKET_LENGTH") + break; + } + else + if (Socket.Buf.length >= PacketSize) { + var data = Socket.Buf.slice(0, PacketSize); + Socket.Buf = Socket.Buf.slice(PacketSize, Socket.Buf.length) + var Res = this.DoDataFromTCP(Socket, data); + if (Res) { + continue; + } + } + } + break; + } + } + DoDataFromTCP(Socket, buf) { + this.LoadedPacketNum++ + var Node = Socket.Node; + if (!Node) + return 0; + var startTime = process.hrtime(); + global.ADD_TO_STAT("GETDATA(KB)", buf.length / 1024) + global.ADD_TO_STAT("GETDATA(KB):" + NodeName(Node), buf.length / 1024, 1) + if (!Node.TransferSize) + Node.TransferSize = 0 + Node.TransferSize += buf.length / 1024 + Node.TransferBlockNumFix = this.CurrentBlockNum + var Buf = this.GetDataFromBuf(buf); + if (!Buf) { + this.AddCheckErrCount(Node, 1, "Err GetDataFromBuf") + this.SendCloseSocket(Socket, "FORMAT_PACKET_SEND_TCP") + return 0; + } + global.ADD_TO_STAT("GET:" + Buf.Method) + global.ADD_TO_STAT("GET:(KB)" + Buf.Method, buf.length / 1024) + global.ADD_TO_STAT("GET:" + Buf.Method + ":" + NodeName(Node), 1, 1) + var Param = this.MethodTiming[Buf.Method]; + if (this.StopDoSendPacket(Param, Node, Buf.Method)) { + return 1; + } + if (!IsZeroArr(Buf.ContextID)) { + Buf.Context = global.ContextPackets.LoadValue(Buf.ContextID) + } + if (!Buf.Context) { + if (Param && Param.Period === 0 && Buf.Method !== "RETBLOCKHEADER") { + this.AddCheckErrCount(Node, 1) + return; + } + Buf.Context = {} + } + Buf.Context.ContextID = Buf.ContextID + Buf.Node = Node + Buf.Socket = Socket + Buf.MethodTiming = Param + if (!global.ADDRLIST_MODE || Param.IsAddrList) { + if (Param.Hard) { + if (Param.Immediately && this.HardPacketForSend.size <= 3) { + this.OnPacketTCP(Buf) + } + else { + Buf.PacketNum = this.LoadedPacketNum + Buf.BlockProcessCount = Node.BlockProcessCount + Buf.TimeLoad = Date.now() + this.HardPacketForSend.insert(Buf) + } + } + else { + this.OnPacketTCP(Buf) + } + } + ADD_TO_STAT_TIME("MAX:TIMEDOGETDATA", startTime) + return 1; + } + StopDoSendPacket(Param, Node, Name) { + var CurTime = GetCurrentTime(0) - 0; + if (!Param) { + global.ADD_TO_STAT("STOP_METHOD") + global.ADD_TO_STAT("STOP_METHOD:NO") + this.AddCheckErrCount(Node, 1) + return 1; + } + if (Param.Hot && !Node.Hot) { + this.AddCheckErrCount(Node, 1) + return 0; + } + if (Param.Period && !Node.VersionOK && !Param.LowVersion) { + global.ADD_TO_STAT("STOP_METHOD") + global.ADD_TO_STAT("STOP_METHOD:LOWVERSION:" + Name) + return 1; + } + if (global.STOPGETBLOCK && Param.Hard === 2 && Node.BlockProcessCount < 1000000) { + Node.NextPing = 1 * 1000 + global.ADD_TO_STAT("STOP_METHOD") + global.ADD_TO_STAT("STOP_METHOD:STOPGETBLOCK:" + Name) + this.AddCheckErrCount(Node, 0.5) + return 1; + } + var ArrTime = Node.TimeMap[Name]; + if (!ArrTime) { + ArrTime = [0, 0, 0] + Node.TimeMap[Name] = ArrTime + } + ArrTime.sort(function(a, b) { + return a - b; + }) + var Delta = CurTime - ArrTime[0]; + if (Delta < Param.Period) { + global.ADD_TO_STAT("STOP_METHOD") + global.ADD_TO_STAT("STOP_METHOD:" + Name) + this.AddCheckErrCount(Node, 1) + return 1; + } + ArrTime[0] = CurTime + return 0; + } + DoHardPacketForSend() { + global.ADD_TO_STAT("MAX:BUSY_LEVEL", this.BusyLevel) + global.ADD_TO_STAT("MAX:HARD_PACKET_SIZE", this.HardPacketForSend.size) + var Delta = Date.now() - this.LastTimeHard; + this.LastTimeHard = Date.now() + if (Delta > global.HARD_PACKET_PERIOD120 * HARD_PACKET_PERIOD / 100) { + global.ADD_TO_STAT("HARD_PACKET_PERIOD120") + var Delta2 = Date.now() - this.LastTimeHardOK; + if (Delta2 > 100) { + var Info = this.HardPacketForSend.min(); + this.RiseBusyLevelByInfo(Info) + } + return; + } + if (this.BusyLevel) + this.BusyLevel = this.BusyLevel / 1.1 + this.LastTimeHardOK = Date.now() + global.ADD_TO_STAT("HARD_PACKET_PERIOD") + this.DoHardPacketForSendNext() + } + RiseBusyLevelByInfo(Info) { + if (!Info) + return; + if (!this.BusyLevel) + this.BusyLevel = 1 + if (Info.BlockProcessCount > this.BusyLevel) + this.BusyLevel = Info.BlockProcessCount + 1 + if (this.BusyLevel <= 0) + this.BusyLevel = 1 + } + DropBusyLevelByInfo(Info) { + if (!Info) + return; + if (this.BusyLevel > Info.BlockProcessCount) + this.BusyLevel = Info.BlockProcessCount - 1 + if (this.BusyLevel < 0) + this.BusyLevel = 0 + } + DoHardPacketForSendNext() { + var Info = this.HardPacketForSend.min(); + if (!Info) { + this.BusyLevel = 0 + return; + } + this.DropBusyLevelByInfo(Info) + this.HardPacketForSend.remove(Info) + this.OnPacketTCP(Info) + global.ADD_TO_STAT("DO_HARD_PACKET") + global.ADD_TO_STAT("DO_HARD_PACKET:" + Info.Method) + var DeltaTime = Date.now() - Info.TimeLoad; + if (this.HardPacketForSend.size && DeltaTime > PACKET_ALIVE_PERIOD / 2) { + global.ADD_TO_STAT("DELETE_HARD_PACKET_OLD", this.HardPacketForSend.size) + this.HardPacketForSend.clear() + return; + } + var MaxCount = 20; + while (Info = this.HardPacketForSend.max()) { + var DeltaTime = Date.now() - Info.TimeLoad; + if (DeltaTime > PACKET_ALIVE_PERIOD / 2 || !Info.Node.Socket || Info.Node.Socket.WasClose) { + this.HardPacketForSend.remove(Info) + if (DeltaTime > PACKET_ALIVE_PERIOD / 2) { + this.RiseBusyLevelByInfo(Info) + Info.Node.NextPing = 1 * 1000 + this.AddCheckErrCount(Info.Node, 0.2) + global.ADD_TO_STAT("DELETE_HARD_PACKET_OLD") + global.ADD_TO_STAT("DELETE_HARD_PACKET_OLD:" + Info.Method) + } + else { + global.ADD_TO_STAT("DELETE_HARD_PACKET_NO_ALIVE") + } + } + MaxCount-- + if (MaxCount <= 0) + break; + } + } + Send(Node, Info, TypeData) { + if (!Node.Socket) { + this.DeleteNodeFromActive(Node) + return; + } + if (Info.Context) { + Info.ContextID = Info.Context.ContextID + if (!Info.ContextID) { + Info.ContextID = crypto.randomBytes(32) + Info.Context.ContextID = Info.ContextID + } + global.ContextPackets.SaveValue(Info.ContextID, Info.Context) + } + else { + Info.ContextID = [] + } + Node.SendPacketNum++ + Info.Node = Node + Info.TypeData = TypeData + Info.Prioritet = Node.Prioritet + Info.PacketNum = Node.SendPacketNum + Info.TimeNum = Date.now() + Node.SendPacket.insert(Info) + } + DoSendPacketNodeAll(Node) { + while (this.DoSendPacketNode(Node) === 1); + } + DoSendPacketNode(Node) { + var TimeNum = Date.now(); + var Info = Node.SendPacket.max(); + if (Info && TimeNum - Info.TimeNum > PACKET_ALIVE_PERIOD) + while (Info = Node.SendPacket.max()) { + var DeltaTime = TimeNum - Info.TimeNum; + if (DeltaTime > PACKET_ALIVE_PERIOD / 2) { + Node.SendPacket.remove(Info) + global.ADD_TO_STAT("DELETE_OLD_PACKET") + } + else + break; + } + Info = Node.SendPacket.min() + if (!Info) + return 0; + global.ADD_TO_STAT("MAX:NODE_BUF_WRITE:" + NodeName(Node), Node.BufWrite.length / 1024, 1) + global.ADD_TO_STAT("MAX:NODE_SEND_BUF_PACKET_COUNT:" + NodeName(Node), Node.SendPacket.size, 1) + if (Node.BufWrite.length > 2 * TRAFIC_LIMIT_1S) { + return 2; + } + Node.SendPacket.remove(Info) + if (Info.Context) { + if (!Info.Context.SendCount) + Info.Context.SendCount = 0 + Info.Context.SendCount++ + } + var BufWrite = this.GetBufFromData(Info.Method, Info.Data, Info.TypeData, Info.ContextID); + Node.BufWriteLength += BufWrite.length + if (Node.BufWrite.length === 0) + Node.BufWrite = BufWrite + else + Node.BufWrite = Buffer.concat([Node.BufWrite, BufWrite]) + global.ADD_TO_STAT("SEND:" + Info.Method) + global.ADD_TO_STAT("SEND:(KB)" + Info.Method, BufWrite.length / 1024) + global.ADD_TO_STAT("SEND:" + Info.Method + ":" + NodeName(Node), 1, 1) + TO_DEBUG_LOG("SEND " + Info.Method + " to " + NodeInfo(Node) + " LENGTH=" + BufWrite.length) + return 1; + } + DoSendPacket() { + var it = this.ActualNodes.iterator(), Node; + while ((Node = it.next()) !== null) + if (Node.ConnectStatus() === 100) { + this.DoSendPacketNode(Node) + } + else { + global.ADD_TO_STAT("SEND_ERROR") + this.AddCheckErrCount(Node, 0.005, "NODE STATUS=" + Node.ConnectStatus()) + } + } + DoSendBuf() { + this.RecalcSendStatictic() + var CountNodeSend = 0; + var it = this.ActualNodes.iterator(), Node; + NEXT_NODE: + while ((Node = it.next()) !== null) + if (Node.Socket && Node.ConnectStatus() === 100) + if (Node.BufWrite.length > 0) { + CountNodeSend++ + var CountSend = Math.min(BUF_PACKET_SIZE, Node.BufWrite.length); + var Value = CountSend / 1024; + if (global.LIMIT_SEND_TRAFIC) { + var CanCountSend = Node.SendTrafficLimit - Node.SendTrafficCurrent; + if (CanCountSend < CountSend) { + if (this.SendTrafficFree < CountSend) { + global.ADD_TO_STAT("LIMIT_SENDDATA:" + NodeName(Node), Value, 1) + continue NEXT_NODE; + } + this.SendTrafficFree -= CountSend + } + } + Node.write(Node.BufWrite.slice(0, CountSend)) + Node.SendTrafficCurrent += CountSend + Node.BufWrite = Node.BufWrite.slice(CountSend) + this.ADD_CURRENT_STAT_TIME("SEND_DATA", Value) + global.ADD_TO_STAT("SENDDATA(KB)", Value) + global.ADD_TO_STAT("SENDDATA(KB):" + NodeName(Node), Value, 1) + } + } + CheckPOWTicketConnect(Socket, data) { + try { + var Info = global.BufLib.GetObjectFromBuffer(data, FORMAT_POW_TO_SERVER, {}); + } + catch (e) { + this.SendCloseSocket(Socket, "FORMAT_POW_TO_SERVER") + return; + } + if (Info.DEF_NETWORK !== GetNetworkName()) { + this.SendCloseSocket(Socket, "DEF_NETWORK=" + Info.DEF_NETWORK + " MUST:" + GetNetworkName()) + return; + } + var Node = this.FindRunNodeContext(Info.addrArr, Info.FromIP, Info.FromPort, true); + if (global.CompareArr(Info.addrArr, this.addrArr) === 0) { + AddNodeInfo(Node, "SERV: GET SELF") + this.SendCloseSocket(Socket, "SELF") + return; + } + var Hash = shaarr2(this.addrArr, Socket.HashRND); + var hashInfo = GetHashWithValues(Hash, Info.nonce, 0); + var power = GetPowPower(hashInfo); + if (Info.Reconnect) { + if ((Node.SecretForReconnect && Node.WaitConnectFromServer && global.CompareArr(Node.SecretForReconnect, Info.SecretForReconnect) === 0) || Info.Reconnect === 255) { + var Result = 1; + if (Info.Reconnect === 255) { + Result = CheckDevelopSign(Hash, Info.Sign) + } + if (Result) { + Node.NextConnectDelta = 1000 + Node.WaitConnectFromServer = 0 + Node.GrayConnect = 0 + AddNodeInfo(Node, "3. SERVER OK CONNECT for client node " + SocketInfo(Socket)) + this.AddNodeToActive(Node) + Node.Socket = Socket + SetSocketStatus(Socket, 3) + SetSocketStatus(Socket, 100) + Socket.Node = Node + Socket.write(this.GetBufFromData("POW_CONNECT0", "OK", 2)) + return; + } + else { + Node.NextConnectDelta = 60 * 1000 + global.ToLog("Error Sign Node from " + NodeInfo(Node)) + this.AddCheckErrCount(Node, 10, "Error Sign Node") + } + } + AddNodeInfo(Node, "SERV: ERROR_RECONNECT") + Socket.end(this.GetBufFromData("POW_CONNEC11", "ERROR_RECONNECT", 2)) + CloseSocket(Socket, "ERROR_RECONNECT") + return; + } + else { + if (power < MIN_POWER_POW_HANDSHAKE) { + global.ToLog("END: MIN_POWER_POW_HANDSHAKE") + AddNodeInfo(Node, "SERV: ERR MIN_POWER_POW_HANDSHAKE") + Socket.end(this.GetBufFromData("POW_CONNECT2", "MIN_POWER_POW_HANDSHAKE", 2)) + CloseSocket(Socket, "MIN_POWER_POW_HANDSHAKE") + return; + } + else { + if (!Node.BlockProcessCount) + Node.BlockProcessCount = 0 + if (this.ActualNodes.size >= MAX_CONNECTIONS_COUNT && Node.BlockProcessCount < global.TRUST_PROCESS_COUNT) { + AddNodeInfo(Node, "SERV: ERROR_MAX_CLIENTS") + Socket.end(this.GetBufFromData("POW_CONNECT8", "ERROR_MAX_CLIENTS", 2)) + CloseSocket(Socket, "ERROR_MAX_CLIENTS") + return; + } + var Result = false; + if (Info.PubKeyType === 2 || Info.PubKeyType === 3) + Result = secp256k1.verify(Buffer.from(Hash), Buffer.from(Info.Sign), Buffer.from([Info.PubKeyType].concat(Info.addrArr))) + if (!Result) { + AddNodeInfo(Node, "SERV: ERROR_SIGN_CLIENT") + Socket.end(this.GetBufFromData("POW_CONNECT8", "ERROR_SIGN_CLIENT", 2)) + CloseSocket(Socket, "ERROR_SIGN_CLIENT") + this.AddToBanIP(Socket.remoteAddress, "ERROR_SIGN_CLIENT") + return; + } + AddNodeInfo(Node, "1. SERVER OK POW for client node " + SocketInfo(Socket)) + Node.FromIP = Info.FromIP + Node.FromPort = Info.FromPort + Node.SecretForReconnect = crypto.randomBytes(20) + Node.PubKey = Buffer.from([Info.PubKeyType].concat(Info.addrArr)) + if (Info.GrayConnect) { + Node.NextConnectDelta = 1000 + Node.WaitConnectFromServer = 0 + Node.GrayConnect = 1 + AddNodeInfo(Node, "5. CLIENT OK GRAY CONNECT " + SocketInfo(Socket)) + this.AddNodeToActive(Node) + Node.Socket = Socket + SetSocketStatus(Socket, 3) + SetSocketStatus(Socket, 100) + Socket.Node = Node + Socket.write(this.GetBufFromData("POW_CONNECT0", "OK", 2)) + return; + } + if (!Node.WasAddToReconnect) { + Node.WasAddToReconnect = 1 + Node.ReconnectFromServer = 1 + global.ArrReconnect.push(Node) + } + Socket.write(this.GetBufFromData("POW_CONNECT4", "WAIT_CONNECT_FROM_SERVER:" + global.GetHexFromArr(Node.SecretForReconnect), 2)) + } + } + } + StopServer() { + if (this.Server) + this.Server.close() + } + StartServer() { + if (GrayConnect()) { + this.CanSend++ + return; + } + let SELF = this; + this.Server = net.createServer(function(sock) { + if (SELF.WasBanIP({ address: sock.remoteAddress })) { + sock.ConnectID = "new" + CloseSocket(sock, "WAS BAN", true) + return; + } + let SOCKET = sock; + socketInit(SOCKET, "c") + SetSocketStatus(SOCKET, 0) + AddNodeInfo(SOCKET, "Client *" + SOCKET.ConnectID + " connected from " + SOCKET.remoteAddress + ":" + SOCKET.remotePort, 1) + global.ADD_TO_STAT("ClientConnected") + SOCKET.HashRND = crypto.randomBytes(32) + var Data = { + addrArr: SELF.addrArr, HashRND: SOCKET.HashRND, MIN_POWER_POW_HANDSHAKE: MIN_POWER_POW_HANDSHAKE, PubKeyType: SELF.PubKeyType, + Sign: SELF.ServerSign, Reserve: [] + }; + var BufData = global.BufLib.GetBufferFromObject(Data, FORMAT_POW_TO_CLIENT, 300, {}); + var BufWrite = SELF.GetBufFromData("POW_CONNECT5", BufData, 1); + try { + SOCKET.write(BufWrite) + } + catch (e) { + global.ToError(e) + SOCKET = undefined + return; + } + SOCKET.on('data', function(data) { + if (SOCKET.WasClose) { + return; + } + if (!SOCKET.Node) { + var Buf = SELF.GetDataFromBuf(data); + if (Buf) { + SELF.CheckPOWTicketConnect(SOCKET, Buf.Data) + SOCKET.ConnectToServer = 0 + return; + } + CloseSocket(SOCKET, "=SERVER ON DATA=") + } + else { + socketRead(SOCKET, data) + SELF.OnGetFromTCP(SOCKET.Node, SOCKET, data) + } + }) + SOCKET.on('end', function() { + global.ADD_TO_STAT("ClientEnd") + var Node = SOCKET.Node; + var Status = GetSocketStatus(SOCKET); + if (Status) + AddNodeInfo(Node, "Get socket end *" + SOCKET.ConnectID + " from client Stat: " + SocketStatistic(SOCKET)) + if (Node && Status === 200) { + Node.SwapSockets() + SOCKET.WasClose = 1 + } + }) + SOCKET.on('close', function(err) { + global.ADD_TO_STAT("ClientClose") + if (SOCKET.ConnectID && GetSocketStatus(SOCKET)) + AddNodeInfo(SOCKET.Node, "Get socket close *" + SOCKET.ConnectID + " from client Stat: " + SocketStatistic(SOCKET)) + if (!SOCKET.WasClose && SOCKET.Node) { + CloseSocket(SOCKET, "GET CLOSE") + } + SetSocketStatus(SOCKET, 0) + }) + SOCKET.on('error', function(err) { + global.ADD_TO_STAT("ERRORS") + CloseSocket(SOCKET, "ERRORS") + if (SOCKET.Node) + SELF.AddCheckErrCount(SOCKET.Node, 1, "ERR##2 : socket") + }) + }) + this.Server.on('close', function() { + }) + this.Server.on('error', function(err) { + if (err.code === 'EADDRINUSE') { + ToLogClient('Port ' + SELF.port + ' in use, retrying...') + if (SELF.Server) + SELF.Server.close() + setTimeout(function() { + SELF.RunListenServer() + }, 5000) + return; + } + global.ADD_TO_STAT("ERRORS") + global.ToError("ERR##3") + }) + if (!SELF.ip) { + this.FindInternetIP() + } + else { + this.CanSend++ + this.RunListenServer() + } + } + RunListenServer() { + if (!START_PORT_NUMBER || START_PORT_NUMBER === "undefined") + START_PORT_NUMBER = 30000 + let SELF = this; + SELF.port = START_PORT_NUMBER + ToLogClient("Prepare to run TCP server on " + LISTEN_IP + ":" + SELF.port) + this.Server.listen(SELF.port, LISTEN_IP, function() { + if (SELF.CanSend < 2) + ToLogClient("Run TCP server on " + SELF.ip + ":" + SELF.port) + SELF.CanSend++ + var Hash; + Hash = global.sha3(SELF.addrStr) + SELF.ServerSign = secp256k1.sign(Buffer.from(Hash), SELF.KeyPair.getPrivateKey('')).signature + }) + } + FindInternetIP() { + let SELF = this; + let server = Stun.createServer(); + const request = Stun.createMessage(Stun.constants.STUN_BINDING_REQUEST); + server.on('error', function(err) { + SELF.CanSend++ + }) + server.once('bindingResponse', function(stunMsg) { + var value = stunMsg.getAttribute(Stun.constants.STUN_ATTR_XOR_MAPPED_ADDRESS).value; + global.ToLog("INTERNET IP:" + value.address) + SELF.CanSend++ + global.INTERNET_IP_FROM_STUN = value.address + if (!SELF.ip) + SELF.ip = INTERNET_IP_FROM_STUN + if (server) + server.close() + SELF.RunListenServer() + }) + var StrStunAddr = 'stun.l.google.com'; + const dns = require('dns'); + dns.lookup(StrStunAddr, function(err, address, family) { + if (!err) + server.send(request, 19302, StrStunAddr) + else + SELF.CanSend++ + }) + } + CLOSE_SOCKET(Context, CurTime) { + AddNodeInfo(Context.Socket.Node, "GET CLOSE_SOCKET *" + Context.Socket.ConnectID + ": " + Context.Data.toString()) + CloseSocket(Context.Socket, "CLOSE_SOCKET") + } + SendCloseSocket(Socket, Str) { + AddNodeInfo(Socket.Node, "CLOSE_SOCKET " + SocketInfo(Socket) + " - " + Str) + if (Socket.WasClose) { + return; + } + this.AddCheckErrCount(Socket.Node, 1, "SendCloseSocket") + if (Socket.Node && Socket.Node.BufWrite && Socket.Node.BufWrite.length > 0) { + } + else { + AddNodeInfo(Socket.Node, "END *" + Socket.ConnectID + ": " + Str) + Socket.end(this.GetBufFromData("CLOSE_SOCKET", Str, 2)) + } + CloseSocket(Socket, Str) + } + AddCheckErrCount(Node, Count, StrErr) { + if (!Node) + return; + if (!Count) + Count = 1 + var Delta = Date.now() - Node.LastTimeError; + if (Delta > 10 * 1000) { + Node.ErrCount = 0 + } + Node.LastTimeError = Date.now() + Node.ErrCountAll += Count + Node.ErrCount += Count + if (Node.ErrCount >= 5) { + Node.ErrCount = 0 + global.ADD_TO_STAT("ERRORS") + Node.BlockProcessCount-- + if (Node.BlockProcessCount < - 30) { + if (!StrErr) + StrErr = "" + this.AddToBan(Node, StrErr + " BlockProcess:" + Node.BlockProcessCount) + } + else { + } + } + } +}; +global.ContextPackets = new STreeBuffer(10 * 1000, CompareItemHash32, "object"); + +function CalcStatArr(arr, arrAvg, arrNext, Period) { + var arrSum = [arr[0]]; + for (var i = 1; i < arr.length; i++) { + arrSum[i] = arrSum[i - 1] + arr[i]; + } + for (var i = 0; i < arrSum.length; i++) { + if (i < Period) + arrAvg[i] = Math.floor(arrSum[i] / (i + 1)); + else { + arrAvg[i] = Math.floor((arrSum[i] - arrSum[i - Period]) / Period); + } + } + arrNext[0] = 0; + for (var i = 1; i < arrAvg.length; i++) { + var Avg = arrSum[i] / (i + 1); + var minValue = Avg / 20; + var Value1 = arrAvg[i - 1]; + var Value2 = arrAvg[i]; + if (Value1 < minValue) + Value1 = minValue; + if (Value2 < minValue) + Value2 = minValue; + var KLast = Math.floor(100 * (Value2 - Value1) / Value1) / 100; + var AvgLast = arrAvg[i]; + if (Avg > AvgLast) + AvgLast = Avg; + if (KLast > 2.0) + KLast = 2.0; + if (KLast < - 0.0) + KLast = - 0.0; + arrNext[i] = AvgLast * (1 + KLast); + var AvgMax = 0; + if (0) + if (i > 1 * Period) { + for (var j = i - Period / 2; j <= i; j++) + if (arrAvg[j] > AvgMax) + AvgMax = arrAvg[j]; + } + } + return arrNext[arrNext.length - 1]; +}; diff --git a/src/core/startlib.ts b/src/core/startlib.ts new file mode 100644 index 0000000..377412d --- /dev/null +++ b/src/core/startlib.ts @@ -0,0 +1,46 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +import * as fs from 'fs' + +function CopyFiles(l, o, t) { + if (fs.existsSync(l)) + for (var e = fs.readdirSync(l), n = 0; n < e.length; n++) { + var a = l + "/" + e[n], s = o + "/" + e[n]; + if (fs.statSync(a).isDirectory()) + t && (fs.existsSync(s) || fs.mkdirSync(s), CopyFiles(a, s, t)); + else { + var r = fs.readFileSync(a), i = fs.openSync(s, "w"); + fs.writeSync(i, r, 0, r.length), fs.closeSync(i); + } + } +}; +global.GetDataPath = function(l) { + return "/" !== global.DATA_PATH.substr(global.DATA_PATH.length - 1, 1) && (global.DATA_PATH = global.DATA_PATH + "/"), global.GetNormalPathString(global.DATA_PATH + l); +} +global.GetCodePath = function(l) { + return "/" !== global.CODE_PATH.substr(global.CODE_PATH.length - 1, 1) && (global.CODE_PATH = global.CODE_PATH + "/"), global.GetNormalPathString(global.CODE_PATH + l); +} +global.GetNormalPathString = function(l: string) { + return l.split("\\").join("/"); +} +global.CheckCreateDir = function(l, o, t) { + if (l = global.GetNormalPathString(l), !fs.existsSync(l)) { + o || console.log("Create: " + l); + var e = l.split("/"), n = e[0]; + t && e.length--; + for (var a = 1; a < e.length; a++) + n += "/" + e[a], fs.existsSync(n) || fs.mkdirSync(n); + } +} +global.CopyFiles = CopyFiles +global.ToLog || (global.ToLog = function(l) { + console.log(l); +}); diff --git a/src/core/terahashmining.ts b/src/core/terahashmining.ts new file mode 100644 index 0000000..7af8d6e --- /dev/null +++ b/src/core/terahashmining.ts @@ -0,0 +1,202 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +var START_NONCE = 0; +const COUNT_FIND_HASH1 = 64; +const DELTA_LONG_MINING = 5000; +var BLOCKNUM_ALGO2 = 6560000; +if (global.LOCAL_RUN || global.TEST_NETWORK) { + BLOCKNUM_ALGO2 = 0; +} +require('./library.js'); +require('./crypto-library.js'); +require('../HTML/JS/terahashlib.js'); +var DELTA_NONCE = Math.pow(2, 40) * global.MINING_VERSION_NUM; +global.CreateHashMinimal = CreateHashMinimal; +global.CreatePOWVersionX = CreatePOWVersion3; + +function CreateHashMinimal(Block, MinerID) { + if (Block.BlockNum < BLOCKNUM_ALGO2) { + throw "BlockNum < BLOCKNUM_ALGO2"; + return false; + } + var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28); + var Ret = GetHash(Block.SeqHash, PrevHashNum, Block.BlockNum, MinerID, 0, 0, 0, 0, 0); + Block.Hash = Ret.Hash; + Block.PowHash = Ret.PowHash; + Block.Power = GetPowPower(Block.PowHash); + Block.AddrHash = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + WriteUintToArrOnPos(Block.AddrHash, MinerID, 0); + WriteUint32ToArrOnPos(Block.AddrHash, PrevHashNum, 28); + return true; +}; +var MAX_MEMORY3 = 0, SHIFT_MASKA3; +var BufferNonce3, BufferBlockNum3; +var bWasInitVer3, bWasInitVerOK3; + +function InitVer3(Block) { + bWasInitVer3 = 1; + if (Block.ProcessMemorySize > 0) { + var MAXARRAYSIZE = (1 << 30) * 2 - 1; + var MaxArrCount = Math.min(Math.trunc(Block.ProcessMemorySize / 8), MAXARRAYSIZE); + var BitCount = 0; + MAX_MEMORY3 = 1; + for (var b = 0; b < 32; b++) { + if (MAX_MEMORY3 > MaxArrCount) { + BitCount--; + MAX_MEMORY3 = MAX_MEMORY3 / 2; + break; + } + BitCount++; + MAX_MEMORY3 = MAX_MEMORY3 * 2; + } + SHIFT_MASKA3 = 32 - BitCount; + try { + BufferNonce3 = new Uint32Array(MAX_MEMORY3); + BufferBlockNum3 = new Uint32Array(MAX_MEMORY3); + } + catch (e) { + SHIFT_MASKA3 = SHIFT_MASKA3 + 1; + MAX_MEMORY3 = MAX_MEMORY3 / 2; + global.ToLog("WAS ALLOC MEMORY ERROR. NEW TRY: " + MAX_MEMORY3); + BufferNonce3 = new Uint32Array(MAX_MEMORY3); + BufferBlockNum3 = new Uint32Array(MAX_MEMORY3); + } + bWasInitVerOK3 = 1; + global.ToLog("MAX HASH ITEMS=" + Math.trunc(MAX_MEMORY3 / 1024 / 1024) + " M"); + } +}; + +function CreatePOWVersion3(Block, bHashPump) { + if (!bWasInitVer3) + InitVer3(Block); + if (!bWasInitVerOK3) + return 0; + if (!Block.LastNonce) + Block.LastNonce = 0; + if (!Block.HashCount) + Block.HashCount = 0; + if (!Block.LastNonce0) + Block.LastNonce0 = 0; + if (!Block.MaxLider) { + Block.HashCount = 0; + Block.MaxLider = { + Nonce0: 0, Nonce1: 0, Nonce2: 0, DeltaNum1: 0, DeltaNum2: 0, Hash1: [255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255], Hash2: [255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255], + }; + } + var MaxLider = Block.MaxLider; + var RunCount = Block.RunCount; + var BlockNum = Block.BlockNum; + var Miner = Block.MinerID; + var StartNonceRnd = DELTA_NONCE + Block.LastNonce + Math.trunc(3000000000 * Math.random()); + var List = GetNonceHashArr(BlockNum, Miner, StartNonceRnd, RunCount); + for (var n = 0; n < RunCount; n++) { + var Nonce = List.ArrNonce[n]; + var HashNum = List.ArrHash[n] >>> SHIFT_MASKA3; + BufferNonce3[HashNum] = Nonce; + BufferBlockNum3[HashNum] = BlockNum; + } + Block.LastNonce += RunCount; + if (bHashPump) + return; + var Ret = 0; + var PrevHashNum = ReadUint32FromArr(Block.PrevHash, 28); + var HashBase = GetHashFromNum2(BlockNum, PrevHashNum); + var Value1 = FindHashBuffer3(HashBase, BlockNum, Miner, 1); + if (Value1) { + var Hash1 = XORArr(HashBase, Value1.Hash); + if (global.CompareArr(MaxLider.Hash1, Hash1) > 0) { + MaxLider.Hash1 = Hash1; + MaxLider.Nonce1 = Value1.Nonce; + MaxLider.DeltaNum1 = Value1.DeltaNum; + Ret = 1; + } + } + START_NONCE = Block.LastNonce0; + var CountEnd = START_NONCE + 50000; + var Nonce0; + for (Nonce0 = START_NONCE; Nonce0 < CountEnd; Nonce0++) { + var HashCurrent = GetHashFromArrNum2(Block.SeqHash, Miner, Nonce0); + var Value2 = FindHashBuffer3(HashCurrent, BlockNum, Miner, 1); + if (Value2) { + var Hash2 = XORArr(HashCurrent, Value2.Hash); + if (global.CompareArr(MaxLider.Hash2, Hash2) > 0) { + MaxLider.Nonce0 = Nonce0; + MaxLider.Hash2 = Hash2; + MaxLider.Nonce2 = Value2.Nonce; + MaxLider.DeltaNum2 = Value2.DeltaNum; + Ret = 1; + if (global.CompareArr(MaxLider.Hash1, Hash2) > 0) { + break; + } + } + } + } + Block.LastNonce0 = Nonce0; + if (Ret) { + Block.AddrHash = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + WriteUintToArrOnPos(Block.AddrHash, Miner, 0); + WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce0, 6); + WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce1, 12); + WriteUintToArrOnPos(Block.AddrHash, MaxLider.Nonce2, 18); + WriteUint16ToArrOnPos(Block.AddrHash, MaxLider.DeltaNum1, 24); + WriteUint16ToArrOnPos(Block.AddrHash, MaxLider.DeltaNum2, 26); + WriteUint32ToArrOnPos(Block.AddrHash, PrevHashNum, 28); + Block.Hash = MaxLider.Hash2; + if (global.CompareArr(MaxLider.Hash1, MaxLider.Hash2) > 0) { + Block.PowHash = MaxLider.Hash1; + } + else { + Block.PowHash = MaxLider.Hash2; + } + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) + Block.Hash = sha3arr2(MaxLider.Hash1, MaxLider.Hash2); + else + Block.Hash = shaarr2(MaxLider.Hash1, MaxLider.Hash2); + var Power = GetPowPower(Block.PowHash); + Block.HashCount = (1 << Power) >>> 0; + } + return Ret; +}; + +function FindHashBuffer3(HashFind, BlockNum, Miner, CountFind) { + var HashNum = ReadIndexFromArr(HashFind); + for (var i = 0; i < CountFind; i++) { + var Index = HashNum ^ i; + var BlockNum2 = BufferBlockNum3[Index]; + if (BlockNum2 && BlockNum2 > BlockNum - DELTA_LONG_MINING) { + var Nonce2 = DELTA_NONCE + BufferNonce3[Index]; + var Hash2 = GetHashFromNum3(BlockNum2, Miner, Nonce2); + return { Hash: Hash2, DeltaNum: BlockNum - BlockNum2, Nonce: Nonce2 }; + } + } + return undefined; +}; + +function ReadIndexFromArr(arr) { + var value = (arr[0] << 23) * 2 + (arr[1] << 16) + (arr[2] << 8) + arr[3]; + value = value >>> SHIFT_MASKA3; + return value; +}; +global.GetNonceHashArr = function(BlockNum, Miner, StartNonceRnd, CountNonce) { + var ArrNonce = []; + var ArrHash = []; + for (var n = 0; n < CountNonce; n++) { + var Nonce = StartNonceRnd + n; + var HashNonce = GetHashFromNum3(BlockNum, Miner, Nonce); + var HashNum = (HashNonce[0] << 23) * 2 + (HashNonce[1] << 16) + (HashNonce[2] << 8) + HashNonce[3]; + ArrNonce[n] = Nonce; + ArrHash[n] = HashNum; + } + return { ArrNonce: ArrNonce, ArrHash: ArrHash }; +}; diff --git a/src/core/transaction-validator.ts b/src/core/transaction-validator.ts new file mode 100644 index 0000000..6004d54 --- /dev/null +++ b/src/core/transaction-validator.ts @@ -0,0 +1,220 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +require("../system/dapp"); +require("../system/accounts"); +require("../system/smart"); +require("../system/file"); +require("../system/messager"); +require("../system/names"); +if (global.PROCESS_NAME === "MAIN" || global.PROCESS_NAME === "TX") + require("./wallet"); +module.exports = class CSmartContract extends require("./block-exchange") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.BufHashTree = new RBTree(CompareArr) + this.BufHashTree.LastAddNum = 0 + } + AddBlockToHashTree(Block) { + this.BufHashTree.LastAddNum = Block.BlockNum + var arr = Block.arrContent; + if (arr) { + for (var i = 0; i < arr.length; i++) { + var HASH = global.shaarr(arr[i]); + this.BufHashTree.insert(HASH) + } + } + } + DeleteBlockFromHashTree(Block) { + var arr = Block.arrContent; + if (arr) { + for (var i = 0; i < arr.length; i++) { + var HASH = global.shaarr(arr[i]); + this.BufHashTree.remove(HASH) + } + } + } + OnWriteBlock(Block) { + } + BlockProcessTX(Block) { + if (Block.BlockNum < 1) + return; + var COUNT_MEM_BLOCKS = 0; + var NUM1 = 1240000; + var NUM2 = 1400000; + if (global.LOCAL_RUN) { + NUM1 = 15 + NUM2 = 100 + } + if (Block.BlockNum > global.BLOCKNUM_TICKET_ALGO) { + NUM1 = 1000000000000 + NUM2 = 1000000000000 + } + if (Block.BlockNum > NUM1) { + COUNT_MEM_BLOCKS = 1 + if (Block.BlockNum > NUM2) + COUNT_MEM_BLOCKS = 60 + if (this.BufHashTree.LastAddNum !== Block.BlockNum - 1) { + this.BufHashTree.clear() + for (var num = COUNT_MEM_BLOCKS; num >= 1; num--) { + var Block2 = this.ReadBlockDB(Block.BlockNum - num); + if (Block2) { + this.AddBlockToHashTree(Block2) + } + } + } + } + for (var key in DApps) { + DApps[key].OnWriteBlockStart(Block) + } + var arrContentResult = []; + var BlockNum = Block.BlockNum; + var arr = Block.arrContent; + if (arr) + for (var i = 0; i < arr.length; i++) { + var HASH = global.shaarr(arr[i]); + if (this.BufHashTree.find(HASH)) { + continue; + } + var type = arr[i][0]; + var App = DAppByType[type]; + if (App) { + App.ResultTx = 0 + global.DApps.Accounts.BeginTransaction() + var StrHex = global.GetHexFromArr(sha3(arr[i])); + var item; + global.CurTrItem = undefined + if (global.TreeFindTX) { + item = global.TreeFindTX.LoadValue(StrHex) + if (item) + global.CurTrItem = item.TX + } + var Result = App.OnWriteTransaction(Block, arr[i], BlockNum, i); + var SetResult = Result; + if (Result === true) { + if (App.ResultTx) + SetResult = App.ResultTx + if (!DApps.Accounts.CommitTransaction(BlockNum, i)) + SetResult = 0 + } + else { + global.DApps.Accounts.RollBackTransaction() + SetResult = 0 + } + if (SetResult === true) + SetResult = 1 + arrContentResult[i] = SetResult + if (item) { + var ResultStr = Result; + if (Result === true || typeof Result === "number") { + ResultStr = "Add to blockchain" + if (type === global.TYPE_TRANSACTION_FILE) + ResultStr += ": file/" + BlockNum + "/" + i + } + item.cmd = "RetFindTX" + item.ResultStr = "" + ResultStr + item.bFinal = 1 + item.Result = SetResult + process.send(item) + } + global.CurTrItem = undefined + } + } + if (COUNT_MEM_BLOCKS) { + var Block2 = this.ReadBlockDB(Block.BlockNum - COUNT_MEM_BLOCKS); + if (Block2) + this.DeleteBlockFromHashTree(Block2) + this.AddBlockToHashTree(Block) + } + if (arrContentResult.length) + process.send({ cmd: "WriteBodyResult", BlockNum: Block.BlockNum, arrContentResult: arrContentResult }) + for (var key in DApps) { + DApps[key].OnWriteBlockFinish(Block) + } + } + BlockDeleteTX(Block) { + this.BufHashTree.LastAddNum = 0 + for (var key in DApps) { + DApps[key].OnDeleteBlock(Block) + } + } + OnDelete(Block) { + } + IsValidTicket(Tr, BlockNum) { + this.CheckCreateTicketObject(Tr, BlockNum) + if (Tr.power < MIN_POWER_POW_TR) + return - 2; + if (Tr.num !== BlockNum) + return - 3; + return 1; + } + IsValidTransaction(Tr, BlockNum) { + if (!Tr.body || Tr.body.length < MIN_TRANSACTION_SIZE || Tr.body.length > MAX_TRANSACTION_SIZE) + return - 1; + this.CheckCreateTransactionObject(Tr) + if (Tr.power - Math.log2(Tr.body.length / 128) < MIN_POWER_POW_TR) + return - 2; + if (Tr.num !== BlockNum) + return - 3; + if (Tr.body[0] === TYPE_TRANSACTION_ACC_HASH) + return - 4; + return 1; + } + ReWriteDAppTransactions(Length) { + if (!TX_PROCESS.Worker) + return 0; + if (!Length) + return 0; + var StartNum = this.BlockNumDB - Length + 1; + if (StartNum < 0) + StartNum = 0 + var EndNum = this.BlockNumDB; + var MinBlock = global.DApps.Accounts.GetMinBlockAct(); + if (MinBlock > StartNum) { + global.ToLog("Cant rewrite transactions. Very long length of the rewriting chain. Max length=" + (this.BlockNumDB - MinBlock)) + return 0; + } + if (global.TX_PROCESS && global.TX_PROCESS.RunRPC) + global.TX_PROCESS.RunRPC("ReWriteDAppTransactions", { StartNum: StartNum, EndNum: EndNum }) + return 1; + } + AddDAppTransactions(BlockNum, Arr) { + if (BlockNum % PERIOD_ACCOUNT_HASH !== 0) + return; + var BlockNumHash = BlockNum - DELTA_BLOCK_ACCOUNT_HASH; + if (BlockNumHash < 0) + return; + var Item = global.DApps.Accounts.GetAccountHashItem(BlockNumHash); + if (Item) { + var Body = [TYPE_TRANSACTION_ACC_HASH]; + WriteUintToArr(Body, BlockNumHash) + WriteArrToArr(Body, Item.AccHash, 32) + if (BlockNumHash >= START_BLOCK_ACCOUNT_HASH3) { + WriteUintToArr(Body, Item.AccountMax) + WriteArrToArr(Body, Item.SmartHash, 32) + WriteUintToArr(Body, Item.SmartCount) + WriteUintToArr(Body, BlockNum) + WriteUintToArr(Body, 0) + } + var Tr = { body: Body }; + this.CheckCreateTransactionObject(Tr) + Arr.unshift(Tr) + } + } + AddTransactionOwn(Tr) { + if (!global.TX_PROCESS.Worker) + return - 6; + var StrHex = global.GetHexFromArr(sha3(Tr.body)); + global.TX_PROCESS.Worker.send({ cmd: "FindTX", TX: StrHex }) + return this.AddTransaction(Tr, 1); + } +}; diff --git a/src/core/transfer-msg.ts b/src/core/transfer-msg.ts new file mode 100644 index 0000000..f4f4dc8 --- /dev/null +++ b/src/core/transfer-msg.ts @@ -0,0 +1,220 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const MAX_MESSAGE_COUNT = 1000; +module.exports = class CMessages extends require("./transaction-validator") +{ + constructor(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) { + super(SetKeyPair, RunIP, RunPort, UseRNDHeader, bVirtual) + this.MemPoolMsg = [] + for (var i = 0; i <= MAX_LEVEL_SPECIALIZATION; i++) + this.MemPoolMsg[i] = new RBTree(CompareItemTimePow) + } + AddMsgToQuote(Msg) { + var Tree = this.MemPoolMsg[Msg.Level]; + if (Tree) { + if (Tree.insert(Msg)) { + if (Tree.size > MEM_POOL_MSG_COUNT) { + var maxitem = Tree.max(); + Tree.remove(maxitem) + if (maxitem === Msg) + return 0; + } + return 1; + } + else { + return 3; + } + } + return 0; + } + IsValidMsg(Msg) { + this.CheckCreateMsgHASH(Msg) + if (Msg.power < MIN_POWER_POW_MSG) + return - 1; + if (Msg.time > this.CurrentBlockNum) + return - 1; + return 1; + } + CheckCreateMsgHASH(Msg) { + if (!Msg.HashPow) { + Msg.HASH = global.sha3(Msg.body) + Msg.HashPow = GetHashWithValues(Msg.HASH, Msg.nonce, Msg.time) + Msg.power = GetPowPower(Msg.HashPow) + Msg.TimePow = Msg.time + Msg.power - Math.log2(Msg.body.length / 128) + Msg.Level = AddrLevelArr(this.addrArr, Msg.addrArr) + if (Msg.Level >= MAX_LEVEL_SPECIALIZATION) + Msg.Level = MAX_LEVEL_SPECIALIZATION + } + } + CreateMsgFromBody(Body, ToAddr) { + var HASH = global.sha3(Body); + var Msg = { + HASH: HASH, body: Body, addrArr: ToAddr, nonce: CreateNoncePOWExtern(HASH, this.CurrentBlockNum, 3 * (1 << MIN_POWER_POW_MSG)), + time: this.CurrentBlockNum, + }; + this.CheckCreateMsgHASH(Msg) + return Msg; + } + SendMessage(Body, ToAddr) { + var Msg = this.CreateMsgFromBody(Body, ToAddr); + this.SendMessageNext(Msg) + } + SendMessageNext(Msg) { + var CountNodes = 3; + var LevelStart = Msg.Level; + if (global.CompareArr(this.addrArr, Msg.addrArr) === 0) + return false; + for (var L = LevelStart; L >= 0; L--) + if (this.LevelNodes[L] && this.LevelNodes[L].length) { + var arr = this.LevelNodes[L]; + for (var j = 0; arr && j < arr.length; j++) { + var Node = arr[j]; + this.SendF(Node, { "Method": "MESSAGE", "Data": { Arr: [Msg] } }) + CountNodes-- + if (CountNodes <= 0) + break; + } + } + return true; + } + static + MESSAGE_F() { + return "{Arr:[{addrArr:hash,body:tr,nonce:uint,time:uint}]}"; + } + MESSAGE(Info, CurTime) { + var Data = this.DataFromF(Info); + var arr = Data.Arr; + for (var i = 0; i < arr.length; i++) { + var Msg = arr[i]; + if (this.IsValidMsg(Msg)) { + if (global.CompareArr(this.addrArr, Msg.addrArr) === 0) { + var App = DAppByType[Msg.body[0]]; + if (App) { + App.OnMessage(Msg, BlockNum, i) + } + } + else { + if (this.AddMsgToQuote(Msg) === 1) { + this.SendMessageNext(Msg) + } + } + } + } + } + SendGetMessage(Node) { + var Context = { "SendGetMessage": 1 }; + this.Send(Node, { "Method": "GETMESSAGE", "Context": Context, "Data": undefined }) + } + GETMESSAGE(Info, CurTime) { + var arr = []; + var BufLength = 300; + var Level = AddrLevelArr(this.addrArr, Info.Node.addrArr); + var Tree = this.MemPoolMsg[Level]; + if (Tree) { + var it = Tree.iterator(), Item; + while ((Item = it.next()) !== null) { + if (arr.length >= MAX_MESSAGE_COUNT) + break; + arr.push(Item) + BufLength += Item.body.length + 50 + } + } + this.SendF(Info.Node, { "Method": "MESSAGE", "Context": Info.Context, "Data": { Arr: arr } }, BufLength) + } + AddTransaction(Tr, ToAll) { + Tr.ToAll = ToAll + var Res = this.IsValidTransaction(Tr, this.CurrentBlockNum); + if (Res <= 0 && Res !== - 3) + return Res; + if (Tr.num < this.CurrentBlockNum) + return - 3; + var delta = Tr.num - this.CurrentBlockNum; + if (delta > 3) { + if (delta < 15) { + let TR = Tr; + let SELF = this; + setTimeout(function() { + var Res = SELF.AddTransaction(TR, TR.ToAll); + if (TR.ToAll) + ToLogClient("#3 Added " + TrName(TR) + " for block: " + TR.num + " on timer Res=" + Res) + }, (delta - 3) * 1000) + if (Tr.ToAll) + ToLogClient("#2 Added " + TrName(Tr) + " for block: " + Tr.num + " to timer. Send transaction after " + (delta - 3) + " sec") + return 4; + } + return - 3; + } + var Block = this.GetBlockContext(Tr.num); + if (!Block) + return - 5; + if (Block.Active) { + Res = - 3 + } + else { + Res = this.AddTrToBlockQuote(Block, Tr) + if (Tr.ToAll) + this.SendTransaction(Tr) + } + ToLogContext("#1 Add " + TrName(Tr) + " for Block: " + Tr.num + " Res=" + Res) + return Res; + } + SendTransaction(Tr) { + if (!Tr.ToAll) + return; + var CurTime = GetCurrentTime(0) - 0; + var Count; + if (GrayConnect()) + Count = Math.trunc(MAX_GRAY_CONNECTIONS_TO_SERVER / 2) + else + Count = Math.min(this.ActualNodes.size, 16) + if (Count < 2) + Count = 2 + var ArrNodes = this.GetActualNodes(); + for (var i = 0; i < ArrNodes.length; i++) { + var Node = ArrNodes[i]; + if (!Node) + continue; + if (Node.TaskLastSend) { + var Delta = CurTime - Node.TaskLastSend; + if (Delta < global.PERIOD_GET_BLOCK || Node.StopGetBlock) { + continue; + } + } + Node.TaskLastSend = CurTime + this.SendF(Node, { "Method": "TRANSACTION", "Data": Tr }, Tr.body.length + 1000) + ToLogContext("Send " + TrName(Tr) + " to " + NodeName(Node)) + Count-- + if (Count <= 0) + break; + } + } + static + TRANSACTION_F() { + return "{body:tr}"; + } + TRANSACTION(Info, CurTime) { + var Tr = this.DataFromF(Info); + ToLogContext("Receive " + TrName(Tr) + " from " + NodeName(Info.Node)) + this.AddTransaction(Tr, 0) + } +}; + +function ToLogContext(Str) { +}; + +function TrName(Tr) { + if (!Tr.HASH) + global.SERVER.CheckCreateTransactionObject(Tr); + var Str = global.GetHexFromArr(Tr.HASH); + return "Tx:" + Str.substr(0, 8); +}; +global.TrName = TrName; diff --git a/src/core/update.ts b/src/core/update.ts new file mode 100644 index 0000000..89545c9 --- /dev/null +++ b/src/core/update.ts @@ -0,0 +1,165 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.RunOnUpdate = RunOnUpdate; + +function RunOnUpdate() { + var fname = global.GetDataPath("DB/update.lst"); + var UpdateInfo = LoadParams(fname, { UPDATE_NUM_COMPLETE: 1071 }); + if (!UpdateInfo.UPDATE_NUM_COMPLETE) + UpdateInfo.UPDATE_NUM_COMPLETE = 0; + var CurNum = UpdateInfo.UPDATE_NUM_COMPLETE; + if (CurNum !== UPDATE_CODE_VERSION_NUM) { + UpdateInfo.UPDATE_NUM_COMPLETE = UPDATE_CODE_VERSION_NUM; + global.ToLog("UPDATER Start"); + SaveParams(fname, UpdateInfo); + if (global.TEST_NETWORK || global.LOCAL_RUN) { + } + else { + } + global.ToLog("UPDATER Finish"); + } +}; + +function CreateHeadersHash100() { + global.ToLog("CreateHeadersHash100"); + const DBRow = require("./db/db-row"); + global.UpdateMode = 1; + var DB = global.SERVER.DBHeader100; + var Num = 0; + var PrevHash100 = []; + while (1) { + var Block = global.SERVER.ReadBlockHeaderDB(Num); + if (!Block) + break; + var Hash100; + if (Num === 0) + Hash100 = []; + else + Hash100 = sha3arr2(PrevHash100, Block.Hash); + DB.Write({ Num: Num / 100, Hash100: Hash100, Hash: Block.Hash }); + if (Num % 1000000 === 0) + global.ToLog("Create Hash100:" + Num); + PrevHash100 = Hash100; + Num += 100; + } + global.UpdateMode = 0; +}; + +function CheckRewriteTr(Num, StrHash, StartRewrite) { + if (SERVER.BlockNumDB < StartRewrite) + return "NO"; + var AccountsHash = global.DApps.Accounts.GetHashOrUndefined(Num); + if (!AccountsHash || global.GetHexFromArr(AccountsHash) !== StrHash) { + global.ToLog("START REWRITE ERR ACTS TRANSACTIONS"); + global.SERVER.ReWriteDAppTransactions(SERVER.BlockNumDB - StartRewrite); + return "Rewrite"; + } + else { + return "OK"; + } +}; + +function CheckRewriteAllTr2(Num, StrHash, Num2, StrHash2) { + if (global.LOCAL_RUN || global.TEST_NETWORK) + return "NONE"; + var MaxNum = global.SERVER.GetMaxNumBlockDB(); + if (MaxNum < START_BLOCK_ACCOUNT_HASH) + return "NONE"; + var AccountsHash = global.DApps.Accounts.GetHashOrUndefined(Num); + var AccountsHash2 = global.DApps.Accounts.GetHashOrUndefined(Num2); + if (AccountsHash2 && global.GetHexFromArr(AccountsHash2) === StrHash2) + return "OK"; + if (AccountsHash && global.GetHexFromArr(AccountsHash) !== StrHash) { + global.ToLog("***************** START REWRITE ALL DAPPS"); + global.UpdateMode = 1; + for (var key in DApps) { + DApps[key].ClearDataBase(); + } + global.UpdateMode = 0; + return "Rewrite"; + } + else { + return "OK"; + } +}; + +function CheckRewriteAllTr(Num, StrHash, Num2, StrHash2) { + if (global.LOCAL_RUN || global.TEST_NETWORK) + return "NONE"; + var MaxNum = global.SERVER.GetMaxNumBlockDB(); + if (MaxNum < START_BLOCK_ACCOUNT_HASH) + return "NONE"; + var AccountsHash = global.DApps.Accounts.GetHashOrUndefined(Num); + if (AccountsHash && global.GetHexFromArr(AccountsHash) !== StrHash) { + global.ToLog("***************** START REWRITE ALL DAPPS"); + global.UpdateMode = 1; + for (var key in DApps) { + DApps[key].ClearDataBase(); + } + global.UpdateMode = 0; + return "Rewrite"; + } + else { + return "OK"; + } +}; +global.CheckRewriteTr = CheckRewriteTr; + +function RecreateAccountRest1() { + var name = "accounts-rest"; + var fname = global.GetDataPath("DB/" + name); + if (fs.existsSync(fname)) { + global.ToLog("Delete " + fname); + fs.unlinkSync(fname); + } +}; + +function RecreateAccountHashDB3() { + var name = "accounts-hash2"; + var fname = global.GetDataPath("DB/" + name); + if (fs.existsSync(fname)) { + global.UpdateMode = 1; + global.ToLog("Start updating " + name); + const DBRow = require("../core/db/db-row"); + var DB0 = new DBRow(name, 6 + 32 + 32 + 10, "{BlockNum:uint, Hash:hash, SumHash:hash, Reserve: arr10}"); + var DB3 = global.DApps.Accounts.DBAccountsHash; + for (var num = 0; true; num++) { + var Item = DB0.Read(num); + if (!Item) + break; + Item.AccHash = Item.Hash; + DB3.Write(Item); + } + global.ToLog("Finish updating " + name); + DB0.Close(); + DB3.Close(); + global.UpdateMode = 0; + fs.unlinkSync(fname); + } +}; + +function ReWriteDBSmartWrite() { + global.UpdateMode = 1; + global.ToLog("Start ReWriteDBSmartWrite"); + require("../core/db/db-row"); + for (var num = 0; true; num++) { + var Item = global.DApps.Smart.DBSmart.Read(num); + if (!Item) + break; + var Body = (global.GetArrFromHex(GetBufferFromObject(Item, global.DApps.Smart.FORMAT_ROW, 20000, {}); + if (Body.length > 15000) + global.ToLog("Smart " + Item.Num + ". " + Item.Name + " length=" + Body.length); + global.DApps.Smart.DBSmartWrite(Item); + } + global.ToLog("Finish ReWriteDBSmartWrite"); + global.DApps.Smart.DBSmart.Close(); + global.UpdateMode = 0; +}; diff --git a/src/core/wallet.ts b/src/core/wallet.ts new file mode 100644 index 0000000..e7272dd --- /dev/null +++ b/src/core/wallet.ts @@ -0,0 +1,226 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const fs = require('fs'); +import * as crypto from 'crypto'; +require("./library"); +require("./crypto-library"); +const WalletPath = "WALLET"; +const DBRow = require("./db/db-row"); +const CONFIG_NAME = global.GetDataPath(WalletPath + "/config.lst"); +class CApp { + constructor() { + CheckCreateDir(global.GetDataPath(WalletPath)) + var bReadOnly = (global.PROCESS_NAME !== "TX"); + this.Password = "" + this.WalletOpen = undefined + var Params = LoadParams(CONFIG_NAME, undefined); + if (!Params) { + Params = {} + if (global.TEST_NETWORK) { + Params.Key = global.ARR_PUB_KEY[0] + } + else { + Params.Key = global.GetHexFromArr(crypto.randomBytes(32)) + } + Params.AccountMap = {} + Params.MiningAccount = 0 + } + if (Params.MiningAccount) + global.GENERATE_BLOCK_ACCOUNT = Params.MiningAccount + this.AccountMap = Params.AccountMap + this.KeyPair = crypto.createECDH('secp256k1') + if (Params.Protect) { + ToLogClient("Wallet protect by password") + this.KeyXOR = global.GetArrFromHex(Params.KeyXOR) + this.WalletOpen = false + this.SetPrivateKey(Params.PubKey) + } + else { + this.SetPrivateKey(Params.Key) + } + } + SetMiningAccount(Account) { + global.GENERATE_BLOCK_ACCOUNT = Account + this.SaveWallet() + } + AddTransaction(Tr) { + if (!global.TX_PROCESS.Worker) + return 0; + var StrHex = global.GetHexFromArr(sha3(Tr.body)); + global.TX_PROCESS.Worker.send({ cmd: "FindTX", TX: StrHex }) + return global.SERVER.AddTransaction(Tr, 1); + } + SetPrivateKey(KeyStr, bSetNew) { + var bGo = 1; + if (this.WalletOpen === false) { + bGo = 0 + } + if (KeyStr && KeyStr.length === 64 && bGo) { + this.KeyPair.setPrivateKey(GetArr32FromHex(KeyStr)) + this.KeyPair.PubKeyArr = this.KeyPair.getPublicKey('', 'compressed') + this.KeyPair.PubKeyStr = global.GetHexFromArr(this.KeyPair.PubKeyArr) + this.KeyPair.PrivKeyStr = KeyStr.toUpperCase() + this.KeyPair.addrArr = this.KeyPair.PubKeyArr.slice(1) + this.KeyPair.addrStr = GetHexAddresFromPublicKey(this.KeyPair.addrArr) + this.KeyPair.addr = this.KeyPair.addrArr + this.KeyPair.WasInit = 1 + this.PubKeyArr = this.KeyPair.PubKeyArr + } + else { + this.KeyPair.WasInit = 0 + if (KeyStr) { + this.PubKeyArr = global.GetArrFromHex(KeyStr) + this.KeyPair.PubKeyStr = global.GetHexFromArr(this.PubKeyArr) + } + else { + this.PubKeyArr = [] + this.KeyPair.PubKeyStr = "" + } + this.KeyPair.PrivKeyStr = "" + } + if (bSetNew) { + this.AccountMap = {} + } + this.FindMyAccounts(0) + if (bGo) + this.SaveWallet() + } + CloseWallet() { + this.Password = "" + this.WalletOpen = false + this.KeyPair = crypto.createECDH('secp256k1') + this.SetPrivateKey(GetHexFromArr(this.PubKeyArr), false) + ToLogClient("Wallet close") + return 1; + } + OpenWallet(StrPassword) { + if (this.WalletOpen !== false) { + ToLogClient("Wallet was open") + } + var Hash = this.HashProtect(StrPassword); + var TestPrivKey = this.XORHash(this.KeyXOR, Hash, 32); + if (!IsZeroArr(TestPrivKey)) { + this.KeyPair.setPrivateKey(Buffer.from(TestPrivKey)) + var TestPubKey = this.KeyPair.getPublicKey('', 'compressed'); + if (global.CompareArr(TestPubKey, this.PubKeyArr) !== 0) { + ToLogClient("Wrong password") + return 0; + } + this.Password = StrPassword + this.WalletOpen = true + this.SetPrivateKey(GetHexFromArr(TestPrivKey), false) + } + else { + this.Password = StrPassword + this.WalletOpen = true + this.SetPrivateKey(GetHexFromArr(this.PubKeyArr), false) + } + ToLogClient("Wallet open") + return 1; + } + SetPasswordNew(StrPassword) { + if (this.WalletOpen === false) { + ToLogClient("Wallet is close by password") + return; + } + this.Password = StrPassword + if (StrPassword) + this.WalletOpen = true + else + this.WalletOpen = undefined + this.SaveWallet() + } + HashProtect(Str) { + var arr = global.shaarr(Str); + for (var i = 0; i < 10000; i++) { + arr = global.shaarr(arr) + } + return arr; + } + XORHash(arr1, arr2, length) { + var arr3 = []; + for (var i = 0; i < length; i++) { + arr3[i] = arr1[i] ^ arr2[i] + } + return arr3; + } + SaveWallet() { + if (this.WalletOpen === false) { + return; + } + var Params = {}; + if (this.Password) { + Params.Protect = true + var Hash = this.HashProtect(this.Password); + if (this.KeyPair.WasInit) { + Params.KeyXOR = global.GetHexFromArr(this.XORHash(this.KeyPair.getPrivateKey(), Hash, 32)) + } + else { + var Key2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + Params.KeyXOR = global.GetHexFromArr(this.XORHash(Key2, Hash, 32)) + } + Params.PubKey = global.GetHexFromArr(this.PubKeyArr) + this.KeyXOR = global.GetArrFromHex(Params.KeyXOR) + } + else { + if (this.KeyPair.WasInit) + Params.Key = this.KeyPair.PrivKeyStr + else + Params.Key = global.GetHexFromArr(this.PubKeyArr) + } + Params.AccountMap = this.AccountMap + Params.MiningAccount = global.GENERATE_BLOCK_ACCOUNT + SaveParams(CONFIG_NAME, Params) + } + OnCreateAccount(Data) { + this.AccountMap[Data.Num] = 0 + } + FindMyAccounts(bClean) { + if (IsZeroArr(this.PubKeyArr)) + return; + if (bClean) + this.AccountMap = {} + global.DApps.Accounts.FindAccounts([this.PubKeyArr], this.AccountMap, 0) + } + GetAccountKey(Num) { + if (this.KeyPair.WasInit && global.TestTestWaletMode) { + } + return this.KeyPair; + } + GetPrivateKey(Num) { + if (!this.KeyPair.WasInit) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var KeyPair; + if (Num) { + KeyPair = this.GetAccountKey(Num) + } + else { + KeyPair = this.KeyPair + } + return KeyPair.getPrivateKey(); + } + GetSignFromArr(Arr, Num) { + if (!this.KeyPair.WasInit) + return "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + var PrivKey = this.GetPrivateKey(Num); + var sigObj = secp256k1.sign(SHA3BUF(Arr), Buffer.from(PrivKey)); + returnglobal.GetHexFromArr(sigObj.signature); + } + GetSignTransaction(TR) { + if (!this.KeyPair.WasInit) + return "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"; + var PrivKey = this.GetPrivateKey(this.AccountMap[TR.FromID]); + var Arr = global.DApps.Accounts.GetSignTransferTx(TR, PrivKey); + returnglobal.GetHexFromArr(Arr); + } +}; +global.WALLET = new CApp; diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..af3169d --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,548 @@ +export { }; + +declare global { + var nw: any; + interface TeraError { + code: string; + stack: any; + } + interface Window { + RUN_CLIENT: number; + RUN_SERVER: number; + } + namespace NodeJS { + interface Global { + //#region run-node.ts + DATA_PATH: string; + CODE_PATH: string; + HTTP_PORT_NUMBER: number; + LOCAL_RUN: number; + //#endregion + //#region main-process.ts + PROCESS_NAME: string; + POWPROCESS: number; + DEBUGPROCESS: any; + UPDATE_CODE_VERSION_NUM: number; + MIN_CODE_VERSION_NUM: number; + MINING_VERSION_NUM: number; + InitParamsArg: Function; + CONST_NAME_ARR: string[]; + NODES_DELTA_CALC_HOUR: number; + USE_HARD_API_V2: number; + USE_TICKET: number; + USE_CHECK_SENDING: number; + USE_LEVEL_WAY: number; + TR_TICKET_HASH_LENGTH: number; + BLOCKNUM_TICKET_ALGO: number; + WATCHDOG_BADACCOUNT: number; + WATCHDOG_DEV: number; + RESYNC_CONDITION: any; + REST_BLOCK_SCALE: number; + REST_START_COUNT: number; + LOAD_TO_BEGIN: number; + DEBUG_WALLET: number; + CHECK_GLOBAL_TIME: number; + AUTO_CORRECT_TIME: number; + DELTA_CURRENT_TIME: number; + NODES_NAME: string; + COMMON_KEY: string; + SERVER_PRIVATE_KEY_HEX: string; + USE_NET_FOR_SERVER_ADDRES: number; + NET_WORK_MODE: { + ip: string; + port: number; + UseDirectIP: boolean; + NodeWhiteList: string; + DoRestartNode: number; + } + STAT_MODE: number; + MAX_STAT_PERIOD: number; + UPDATE_NUM_COMPLETE: number; + WALLET_NAME: string; + WALLET_DESCRIPTION: string; + USE_MINING: number; + POW_MAX_PERCENT: number; + POW_RUN_COUNT: number; + POWRunPeriod: number; + CheckPointDelta: number; + ALL_LOG_TO_CLIENT: number; + LOG_LEVEL: number; + LIMIT_SEND_TRAFIC: number; + COUNT_VIEW_ROWS: number; + MIN_VER_STAT: number; + STOPGETBLOCK: number; + RESTART_PERIOD_SEC: number; + HARD_PACKET_PERIOD120: number; + MINING_START_TIME: string; + MINING_PERIOD_TIME: string; + CHECK_RUN_MINING: number; + CHECK_STOP_CHILD_PROCESS: number; + COUNT_MINING_CPU: number; + SIZE_MINING_MEMORY: number; + HTTP_HOSTING_PORT: number; + HTTPS_HOSTING_DOMAIN: string; + HTTP_MAX_COUNT_ROWS: number; + HTTP_ADMIN_PASSORD: string; + MIN_POWER_POW_HANDSHAKE: number; + USE_HINT: number; + ALL_VIEW_ROWS: number; + COUNT_BLOCK_PROOF: number; + COUNT_NODE_PROOF: number; + MIN_POWER_POW_MSG: number; + MEM_POOL_MSG_COUNT: number; + MAX_LEVEL_SPECIALIZATION: number; + MIN_CONNECT_CHILD: number; + MAX_CONNECT_CHILD: number; + MAX_CONNECTIONS_COUNT: number; + TRUST_PROCESS_COUNT: number; + MAX_NODES_RETURN: number; + MAX_WAIT_PERIOD_FOR_STATUS: number; + MAX_GRAY_CONNECTIONS_TO_SERVER: number; + MAX_PACKET_LENGTH: number; + COUNT_BLOCKS_FOR_LOAD: number; + TR_LEN: number; + BLOCK_PROCESSING_LENGTH: number; + BLOCK_PROCESSING_LENGTH2: number; + CONSENSUS_PERIOD_TIME: number; + MAX_BLOCK_SIZE: number; + MAX_TRANSACTION_SIZE: number; + MIN_TRANSACTION_SIZE: number; + MAX_TRANSACTION_COUNT: number; + MAX_TRANSACTION_LIMIT: number; + MIN_POWER_POW_TR: number; + MIN_POWER_POW_BL: number; + GENERATE_BLOCK_ACCOUNT: number; + TOTAL_SUPPLY_TERA: number; + TRANSACTION_PROOF_COUNT: number; + MIN_POWER_POW_ACC_CREATE: number; + START_MINING: number; + REF_PERIOD_MINING: number; + DELTA_BLOCK_ACCOUNT_HASH: number; + PERIOD_ACCOUNT_HASH: number; + START_BLOCK_ACCOUNT_HASH: number; + START_BLOCK_ACCOUNT_HASH3: number; + NEW_ACCOUNT_INCREMENT: number; + NEW_BLOCK_REWARD1: number; + NEW_FORMULA_START: number; + NEW_FORMULA_KTERA: number; + NEW_FORMULA_TARGET1: number; + NEW_FORMULA_TARGET2: number; + BLOCK_COUNT_IN_MEMORY: number; + HISTORY_BLOCK_COUNT: number; + MAX_SIZE_LOG: number; + READ_ONLY_DB: number; + USE_CHECK_SAVE_DB: number; + START_NETWORK_DATE: number; + NETWORK: string; + DEF_MAJOR_VERSION: string; + SMART_BLOCKNUM_START: number; + PRICE_DAO: Function; + NEW_SIGN_TIME: number; + TEST_TRANSACTION_GENERATE: number; + TEST_NETWORK: boolean | number; + START_PORT_NUMBER: number; + GetNetworkName: Function; + DEF_VERSION: string; + DEF_CLIENT: string; + FIRST_TIME_BLOCK: number; + START_BLOCK_RUN: number; + START_IP: string; + LISTEN_IP: string; + HTTP_PORT_PASSWORD: string; + HTTP_IP_CONNECT: string; + USE_AUTO_UPDATE: number; + USE_PARAM_JS: number; + CREATE_ON_START: boolean | number; + DEBUG_MODE: number; + RUN_CLIENT: number; + RUN_SERVER: number; + CHILD_POW: boolean; + ADDRLIST_MODE: boolean; + NWMODE: number; + NOALIVE: number; + DEV_MODE: number; + START_SERVER: number; + SetCalcPOW: Function; + RunStopPOWProcess: Function; + NEW_SERVER_PRIVATE_KEY: number; + //#endregion + + //#region startlib.ts + GetDataPath: (str: string) => string; + GetCodePath: (str: string) => string; + GetNormalPathString: (str: string) => string; + CheckCreateDir: (l, o?, t?) => void; + CopyFiles: (l, o, t) => void; + ToLog: Function; + //#endregion + + TO_ERROR_LOG: Function; + ToLogClient: Function; + + glCurNumFindArr: number; + ArrReconnect: []; + ArrConnect: []; + + //#region main-process.ts:51 + SERVER: any; + NeedRestart: number; + WEB_PROCESS: TeraProcess; + CountAllNode: number; + //#endregion + + //#region main-process.ts:100 + GetCurrentTime: Function; + //#region main-process.ts:100 + + //#region + SpeedSignLib: number; + TestSignLib: Function; + //#endregion + + //#region main-process.ts:118 + TX_PROCESS: TeraProcess + //#endregion + + //#region main-process.ts:141 + AddTransactionFromWeb: Function; + STATIC_PROCESS: TeraProcess; + //#endregion + + //#region main-process.ts:204 + WALLET: any; + //#endregion + + //#region main-process.ts:342 + StopChildProcess: Function; + //#endregion + + //#region main-process.ts:375 + MiningPaused: number; + ArrMiningWrk: any[]; + //#endregion + + //#region library.ts:118 + DelDir: Function; + SliceArr: Function; + random: Function; + AddrLevelArrFromBegin: Function; + AddrLevelArr: Function; + SaveToFile: Function; + LoadParams: Function; + SaveParams: Function; + StartTime: Function; + FinishTime: Function; + CompareItemBufFD: Function; + CompareArr33: Function; + CompareItemHashSimple: Function; + CompareItemHash: Function; + CompareItemHash32: Function; + CompareItemHASH32: Function; + CompareItemHash33: Function; + CompareItemHashPow: Function; + CompareItemTimePow: Function; + LOAD_CONST: Function; + SAVE_CONST: Function; + CheckGlobalTime: Function; + GetDeltaCurrentTime: Function; + GetStrTimeUTC: Function; + GetStrOnlyTimeUTC: Function; + GetSecFromStrTime: Function; + DateFromBlock: Function; + NormalizeName: Function; + CreateEval: Function; + GetCountMiningCPU: Function; + AddTrMap: string[]; + GrayConnect: Function; + //#endregion + + //#region library.ts:118 + RBTree: any; + ntpClient: any; + Stun: any; + ZIP: any; + secp256k1: any; + BufLib: any; + GetCurrentBlockNumByTime: Function; + TimeStart: number; + //#endregion + + //#region run-nw.ts + NWVERSION: string; + HTTP_SERVER_START_OK: boolean; + //#endregion + + //#region crypto-library.ts + MAX_SUPER_VALUE_POW: number; + GetHexFromAddres: Function; + GetArr32FromHex: Function; + GetAddresFromHex: Function; + GetHexAddresFromPublicKey: Function; + GetHexFromArr: Function; + GetArrFromHex: Function; + GetHexFromArrBlock: Function; + GetPublicKeyFromAddres: Function; + CheckDevelopSign: Function; + CheckContextSecret: Function; + GetSignHash: Function; + GetVerifyHash: Function; + GetKeyPair: Function; + GetKeyPairTest: Function; + GetHashWithValues: Function; + CreateNoncePOWExtern: Function; + CreateNoncePOWExternMinPower: Function; + CreateNoncePOWInner: Function; + CreateAddrPOW: Function; + CalcMerkl3FromArray: Function; + CalcMerkl0FromArray: Function; + ClientHex: Function; + CalcHash3FromArray: Function; + CalcHashFromArray: Function; + CalcMerklFromArray: Function; + CalcTreeHashFromArrBody: Function; + UpdateMerklTree: Function; + GetMerkleProof: Function; + CheckMerkleProof: Function; + IsZeroArr: Function; + GetHashWithNonce: Function; + GetPowPower: Function; + GetArrFromValue: Function; + GetPowValue: Function; + Mesh: Function; + Encrypt: Function; + Decrypt: Function; + toUTF8Array: Function; + Utf8ArrayToStr: Function; + GetArrFromStr: Function; + IsDeveloperAccount: Function; + DEVELOP_PUB_KEY_ARR: Buffer[] | string[]; + DEVELOP_PUB_KEY: any; + DEVELOP_PUB_KEY0: Buffer; + ARR_PUB_KEY: any; + //#endregion + + //#region log-strict.ts + CheckSizeLogFile: Function; + //#endregion + + //#region log.ts + ArrLogClient: any[]; + ToLogWeb: Function; + SmallAddr: Function; + ToErrorTrace: Function; + ToLogTrace: Function; + ToInfo: Function; + ToError: Function; + ToLogClient0: Function; + PrepareStatEverySecond: Function; + HASH_RATE: number; + ADD_HASH_RATE: Function; + GET_STAT: Function; + ADD_TO_STAT_TIME: Function; + ADD_TO_STAT: Function; + GET_STATDIAGRAMS: Function; + GET_STATS: Function; + StartCommonStat: Function; + ClearCommonStat: Function; + ResizeArrAvg: Function; + ResizeArrMax: Function; + TO_DEBUG_LOG: Function; + GetStrOnlyTime: Function; + GetStrTime: Function; + //#endregion + + //#region geo.ts + SetGeoLocation: Function; + //#endregion + + //#region geo.ts + WebApi2: any; + HostingCaller: any; + //#endregion + + //#region web-process.ts + LoadBlockFromNetwork: Function; + GlobalRunID: number; + //#endregion + + //#region base.ts + glStopNode: any; + //#endregion + + //#region html-server.ts + HTTPCaller: any; + DappTemplateFile: Function; + DappSmartCodeFile: Function; + DappClientCodeFile + SendBlockFile + + AddDappEventToGlobalMap: Function; + //#endregion + + //#region accounts.ts + HistoryDB: any; + TYPE_TRANSACTION_CREATE: number; + TYPE_TRANSACTION_ACC_HASH: number; + FORMAT_CREATE: string; + FORMAT_MONEY_TRANSFER: string; + FORMAT_MONEY_TRANSFER_BODY: string; + FORMAT_MONEY_TRANSFER2: string; + FORMAT_MONEY_TRANSFER_BODY2: string; + FORMAT_MONEY_TRANSFER3: string; + FORMAT_MONEY_TRANSFER_BODY3: string; + FORMAT_ACCOUNT_HASH: string; + FORMAT_ACCOUNT_HASH3: string; + + //#endregion + + //#region block-db.ts + BlockDB: any; + BLOCK_HEADER_SIZE + BLOCK_HEADER_SIZE2 + DB_VERSION + + //#endregion + + //#region db.ts + CheckStartOneProcess: Function; + //#endregion + + //#region update.ts + UpdateMode: number; + //#endregion + + //#region file.ts + TYPE_TRANSACTION_FILE: number; + FORMAT_FILE_CREATE: string; + //#endregion + + //#region dapp.ts + DApps: any; + DAppByType: any; + //#endregion + + //#region names.ts + NAMES: any; + //#endregion + + //#region smart.ts + TickCounter: number; + TYPE_TRANSACTION_SMART_RUN: number; + FORMAT_SMART_CREATE: string; + FORMAT_SMART_RUN + FORMAT_SMART_CHANGE + RunSmartMethod: Function; + DebugEvent: Function; + //#endregion + + //#region transaction-validator.ts + //#endregion + + //#region connect.ts + PERIOD_FOR_RECONNECT: number; + CHECK_DELTA_TIME: any; + CHECK_POINT: any; + CODE_VERSION: any; + NET_CONSTANT: any; + START_LOAD_CODE: any; + MIN_PERIOD_PING: number; + MAX_PING_FOR_CONNECT: number; + MAX_WAIT_PERIOD_FOR_HOT: number; + //#endregion + + //#region code.ts + + //#endregion + + //#region terahashlib.js + GetHashFromSeqAddr: Function; + CalcHashBlockFromSeqAddr: Function; + GetHashFromNum2: Function; + GetHashFromNum3: Function; + GetHashFromArrNum2: Function; + XORArr: Function; + GetHash: Function; + ReadUint32FromArr: Function; + ReadUintFromArr: Function; + ReadUint16FromArr: Function; + WriteUintToArr: Function; + WriteUint32ToArr: Function; + WriteUint32ToArrOnPos: Function; + WriteUint16ToArrOnPos: Function; + WriteUintToArrOnPos: Function; + WriteArrToArr: Function; + WriteArrToArrOnPos: Function; + WriteArrToArrHOnPos: Function; + ConvertBufferToStr: Function; + CopyObjValue: Function; + CopyArr: Function; + ParseNum: Function; + CompareArr: Function; + CompareArrL: Function; + shaarr2: Function; + sha3arr2: Function; + arr2: Function; + GetBlockArrFromBuffer: Function; + shaarrblock2: Function; + //#endregion + + SendWebFile: Function; + + GlobalRunMap: any; + sha3: any; + SHA3BUF: any; + shaarr: any; + } + interface Process { + RunRPC: Function; + } + } + interface TeraProcess { + Name: string; + idInterval: number | any; + idInterval1: number | any; + idInterval2: number | any; + LastAlive: number; + Worker: Worker; + Path: string; + OnMessage: Function; + PeriodAlive: number; + } + interface Worker { + connected: boolean; + send: Function; + } + interface Number { + //#region library.ts:118 + toStringZ: Function; + //#region + } + interface String { + right: Function; + } + interface HostingCaller { + GetCurrentInfo?: Function; + GetAccountList?: Function; + GetAccount?: Function; + GetBlockList?: Function; + GetTransactionList?: Function; + GetTransactionAll?: Function; + GetDappList?: Function; + GetNodeList?: Function; + GetAccountListByKey?: Function; + GetDappCategory?: Function; + SendTransactionHex?: Function; + DappSmartHTMLFile?: Function; + DappBlockFile?: Function; + DappInfo?: Function; + DappWalletList?: Function; + DappAccountList?: Function; + DappSmartList?: Function; + DappBlockList?: Function; + DappTransactionList?: Function; + DappStaticCall?: Function; + GetHistoryTransactions?: Function; + GetTotalSupply?: Function; + } + +} \ No newline at end of file diff --git a/src/package.json b/src/package.json new file mode 100644 index 0000000..366eb11 --- /dev/null +++ b/src/package.json @@ -0,0 +1,27 @@ +{ + "name": "tera", + "version": "1.0.0", + "description": "Tera wallet", + "main": "run-nw.js", + "main2": "run-electron.js", + "repository": "https://git.yumc.pw/circlecloud/tera.git", + "keywords": [ + "wallet", + "cryptowallet", + "quick", + "messenger", + "cryptocurrency", + "cryptomessenger" + ], + "author": "progr76@gmail.com", + "license": "MIT", + "dependencies": { + "bintrees": "^1.0.2", + "greenlock": "^2.6.7", + "ntp-client": "^0.5.3", + "secp256k1": "^3.6.1", + "stun": "^1.1.0", + "uglify-js": "^3.4.9", + "zip": "^1.2.0" + } +} \ No newline at end of file diff --git a/src/process/api-exchange.ts b/src/process/api-exchange.ts new file mode 100644 index 0000000..1f4010c --- /dev/null +++ b/src/process/api-exchange.ts @@ -0,0 +1,363 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +let WebApi2: any = {}; +import * as crypto from 'crypto'; +WebApi2.GenerateKeys = function(Params) { + var KeyPair = crypto.createECDH('secp256k1'); + var PrivKey = global.sha3(crypto.randomBytes(32)); + KeyPair.setPrivateKey(Buffer.from(PrivKey)); + var PubKey = KeyPair.getPublicKey('' as any, 'compressed'); + return { result: 1, PrivKey: global.GetHexFromArr(PrivKey), PubKey: global.GetHexFromArr(PubKey), Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.CreateAccount = function(Params, response) { + if (typeof Params === "object" && Params.Name && Params.PrivKey) { + var KeyPair = crypto.createECDH('secp256k1'); + KeyPair.setPrivateKey(Buffer.from(global.GetArrFromHex(Params.PrivKey))); + var PubKey = KeyPair.getPublicKey('' as any, 'compressed'); + var TR: any = { Type: global.TYPE_TRANSACTION_CREATE, Currency: Params.Currency, PubKey: PubKey, Name: Params.Name, Smart: Params.Smart, }; + var Body = global.BufLib.GetBufferFromObject(TR, global.FORMAT_CREATE, 1000, {}, 1); + Body = Body.slice(0, Body.len + 12); + SendTransaction(Body, TR as any, Params.Wait, function(result, text) { + var Result = { + result: result, text: text, TxID: global.GetHexFromArr(TR._TxID.slice(0, TR_TICKET_HASH_LENGTH + 6)), BlockNum: TR._BlockNum, + Meta: Params.Meta, + }; + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +var MapSendID = {}; +WebApi2.Send = function(Params, response, A, bJsonRet) { + if (typeof Params !== "object") + return { result: 0 }; + var Coin; + if (typeof Params.Amount === "number") + Coin = COIN_FROM_FLOAT(Params.Amount); + else + Coin = Params.Amount; + var FromNum = ParseNum(Params.FromID); + if (!Coin) + return { result: 0, Meta: Params.Meta, text: "Params.Amount required" }; + if (!FromNum) + return { result: 0, Meta: Params.Meta, text: "Params.FromID required" }; + if (!Params.ToID) + return { result: 0, Meta: Params.Meta, text: "Params.ToID required" }; + var ToPubKeyArr = []; + var ToID = 0; + if (typeof Params.ToID === "string" && Params.ToID.length === 66) + ToPubKeyArr = global.GetArrFromHex(Params.ToID); + else + ToID = ParseNum(Params.ToID); + var DataFrom = global.DApps.Accounts.ReadState(FromNum); + if (!DataFrom) + return { result: 0, Meta: Params.Meta, text: "Error read account: " + FromNum }; + var OperationID; + if (!MapSendID[FromNum]) { + OperationID = DataFrom.Value.OperationID + 10; + MapSendID[FromNum] = {}; + } + else { + OperationID = MapSendID[FromNum].OperationID; + if ((new Date() - MapSendID[FromNum].Date) > 8 * 1000) { + OperationID += 20; + } + } + OperationID++; + MapSendID[FromNum].OperationID = OperationID; + MapSendID[FromNum].Date = Date.now(); + var TR = { + Type: 111, Version: 3, Reserve: 0, FromID: FromNum, OperationID: OperationID, To: [{ + PubKey: ToPubKeyArr, ID: ToID, SumCOIN: Coin.SumCOIN, + SumCENT: Coin.SumCENT + }], Description: Params.Description, Body: [], + }; + if (bJsonRet) + return { result: 1, Tx: TR }; + if (!Params.FromPrivKey) + return { result: 0, Meta: Params.Meta, text: "Params.FromPrivKey required" }; + TR.Sign = global.DApps.Accounts.GetSignTransferTx(TR, global.GetArrFromHex(Params.FromPrivKey)); + var Body = global.BufLib.GetBufferFromObject(TR, FORMAT_MONEY_TRANSFER3, MAX_TRANSACTION_SIZE, {}, 1); + Body = Body.slice(0, Body.len + 12); + SendTransaction(Body, TR, Params.Wait, function(result, text) { + var Result = { + result: result, text: text, TxID: global.GetHexFromArr(TR._TxID.slice(0, TR_TICKET_HASH_LENGTH + 6)), BlockNum: TR._BlockNum, + Meta: Params.Meta, + }; + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; +}; +WebApi2.GetBalance = function(Params, response) { + if (typeof Params === "object") { + var arr = global.DApps.Accounts.GetRowsAccounts(ParseNum(Params.AccountID), 1); + if (arr.length) { + var Account = arr[0]; + var Value = Account.Value; + var Result = { + result: 1, SumCOIN: Value.SumCOIN, SumCENT: Value.SumCENT, Currency: Account.Currency, PubKey: global.GetHexFromArr(Account.PubKey), + Meta: Params.Meta, + }; + return Result; + } + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.GetTransaction = function(Params) { + if (typeof Params === "object" && Params.TxID) { + var Arr = global.GetArrFromHex(Params.TxID); + var BlockNum = ReadUintFromArr(Arr, TR_TICKET_HASH_LENGTH); + var Block = global.SERVER.ReadBlockDB(BlockNum); + if (Block && Block.arrContent) { + for (var i = 0; i < Block.arrContent.length; i++) { + var Body = Block.arrContent[i]; + var Arr2 = GetTxID(BlockNum, Body); + if (global.CompareArr(Arr2, Arr) === 0) { + return GetTransactionFromBody(Params, Block, i, Body); + } + } + } + } + else { + if (typeof Params === "object" && Params.BlockNum && Params.TrNum !== undefined) { + var Block = global.SERVER.ReadBlockDB(Params.BlockNum); + if (Block && Block.arrContent) { + var Body = Block.arrContent[Params.TrNum]; + if (Body) { + return GetTransactionFromBody(Params, Block, Params.TrNum, Body); + } + } + } + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.GetHistoryTransactions = function(Params) { + if (typeof Params === "object" && Params.AccountID) { + if (!Params.Count) + Params.Count = 100; + if (Params.Confirm === undefined) + Params.Confirm = 8; + var arr = global.DApps.Accounts.GetHistory(Params.AccountID, Params.Count, Params.NextPos, Params.Confirm); + if (Params.GetTxID || Params.GetDescription) { + for (var i = 0; i < arr.length; i++) { + var Item = arr[i]; + var Block = global.SERVER.ReadBlockDB(Item.BlockNum); + if (!Block || (!Block.arrContent)) + continue; + var Body = Block.arrContent[Item.TrNum]; + if (!Body) + continue; + if (Params.GetTxID) { + Item.TxID = global.GetHexFromArr(GetTxID(Item.BlockNum, Body)); + } + if (Params.GetDescription) { + var TR = global.DApps.Accounts.GetObjectTransaction(Body); + if (TR) { + Item.Description = TR.Description; + } + } + } + } + var Result = { result: arr.length > 0 ? 1 : 0, History: arr, Tail: global.DApps.Accounts.DBStateHistory.Read(Params.AccountID), Meta: Params ? Params.Meta : undefined }; + return Result; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.CreateRawTransaction = function(Params) { + if (typeof Params === "object") { + var Ret = WebApi2.Send(Params, undefined, undefined, 1); + TxArrToHex(Ret.Tx); + Ret.Meta = Params.Meta; + return Ret; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.SignRawTransaction = function(Params) { + if (typeof Params === "object" && Params.Tx) { + if (!Params.FromPrivKey) + return { result: 0, Meta: Params.Meta, text: "Params.FromPrivKey required" }; + if (typeof Params.Tx !== "object") + return { result: 0, Meta: Params.Meta, text: "Params.Tx required" }; + if (!Params.Tx.To || !Params.Tx.To.length) + return { result: 0, Meta: Params.Meta, text: "Params.Tx.To required" }; + var TR = Params.Tx; + TxHexToArr(TR); + TR.Sign = global.DApps.Accounts.GetSignTransferTx(TR, global.GetArrFromHex(Params.FromPrivKey)); + TxArrToHex(TR); + var Ret = { result: 1, Tx: TR, Meta: Params ? Params.Meta : undefined }; + return Ret; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; +WebApi2.SendRawTransaction = function(Params, response) { + if (typeof Params === "object" && Params.Tx) { + if (typeof Params.Tx !== "object") + return { result: 0, Meta: Params.Meta, text: "Params.Tx required" }; + if (!Params.Tx.To || !Params.Tx.To.length) + return { result: 0, Meta: Params.Meta, text: "Params.Tx.To required" }; + if (!Params.Tx.Sign) + return { result: 0, Meta: Params.Meta, text: "Params.Tx.Sign required" }; + var TR = Params.Tx; + TxHexToArr(TR); + var Body = global.BufLib.GetBufferFromObject(TR, FORMAT_MONEY_TRANSFER3, MAX_TRANSACTION_SIZE, {}, 1); + Body = Body.slice(0, Body.len + 12); + SendTransaction(Body, TR, Params.Wait, function(result, text) { + var Result = { + result: result, text: text, TxID: global.GetHexFromArr(TR._TxID.slice(0, TR_TICKET_HASH_LENGTH + 6)), BlockNum: TR._BlockNum, + Meta: Params.Meta, + }; + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; + +function TxArrToHex(TR) { + if (TR && TR.To && TR.To[0].PubKey) { + if (TR.To[0].PubKey.length) + TR.To[0].PubKey = global.GetHexFromArr(TR.To[0].PubKey); + else + TR.To[0].PubKey = ""; + if (TR.Sign && TR.Sign.length) + TR.Sign = global.GetHexFromArr(TR.Sign); + else + TR.Sign = ""; + TR.Body = undefined; + TR.Reserve = undefined; + } +}; + +function TxHexToArr(TR) { + TR.Body = []; + if (TR.Sign && TR.Sign.length) + TR.Sign = global.GetArrFromHex(TR.Sign); + else + TR.Sign = []; + for (var i = 0; i < TR.To.length; i++) { + TR.To[i].PubKey = global.GetArrFromHex(TR.To[i].PubKey); + } +}; +var DELTA_FOR_TIME_TX = 1; + +function GetTxID(BlockNum, Body) { + var Nonce = ReadUintFromArr(Body, Body.length - 6); + var Arr2 = CreateTxID(Body, BlockNum, Nonce); + return Arr2.slice(0, TR_TICKET_HASH_LENGTH + 6); +}; + +function CreateTxID(body, BlockNum, Nonce) { + body.writeUIntLE(BlockNum, body.length - 12, 6); + body.writeUIntLE(Nonce, body.length - 6, 6); + var HASH = global.sha3(body); + var FullHashTicket = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (var i = 0; i < TR_TICKET_HASH_LENGTH; i++) + FullHashTicket[i] = HASH[i]; + WriteUintToArrOnPos(FullHashTicket, BlockNum, TR_TICKET_HASH_LENGTH); + return FullHashTicket; +}; + +function GetBlockNumTr(arr) { + var BlockNum = DELTA_FOR_TIME_TX + GetCurrentBlockNumByTime(); + if (arr[0] === global.TYPE_TRANSACTION_CREATE) { + var BlockNum2 = Math.floor(BlockNum / 10) * 10; + if (BlockNum2 < BlockNum) + BlockNum2 = BlockNum2 + 10; + BlockNum = BlockNum2; + } + return BlockNum; +}; + +function CreateHashBodyPOWInnerMinPower(TR, arr, MinPow, startnonce) { + var BlockNum = GetBlockNumTr(arr); + if (MinPow === undefined) { + MinPow = MIN_POWER_POW_TR + Math.log2(arr.length / 128); + } + var nonce = startnonce; + while (1) { + var TxID = CreateTxID(arr, BlockNum, nonce); + var power = GetPowPower(sha3(TxID)); + if (power >= MinPow) { + TR._TxID = TxID; + TR._BlockNum = BlockNum; + global.ToLog("Find: " + power + " for block:" + BlockNum); + return nonce; + } + nonce++; + if (nonce % 2000 === 0) { + BlockNum = GetBlockNumTr(arr); + } + } +}; + +function SendTransaction(Body, TR, Wait, F) { + if (Body.length > 16000) { + TR._result = 0; + TR._text = "Error length transaction =" + Body.length + " (max size=16000)"; + F(1, TR, Body); + return; + } + global.GlobalRunID++; + let WebID = global.GlobalRunID; + CreateNonceAndSend(0, 0); + + function CreateNonceAndSend(startnonce, NumNext) { + if (!NumNext) + NumNext = 0; + if (NumNext > 10) { + F(0, TR, Body); + return; + } + var nonce = CreateHashBodyPOWInnerMinPower(TR, Body, undefined, startnonce); + process.RunRPC("AddTransactionFromWeb", { WebID: WebID, HexValue: global.GetHexFromArr(Body) }, function(Err, text) { + TR._result = Err ? 0 : 1; + TR._text = text; + if (text === "Not add" || text === "Bad PoW") { + CreateNonceAndSend(nonce + 1, NumNext + 1); + return; + } + else + if (text === "Bad time") { + if (DELTA_FOR_TIME_TX < 6) { + DELTA_FOR_TIME_TX++; + global.ToLog("New set Delta time: " + DELTA_FOR_TIME_TX); + CreateNonceAndSend(0, NumNext + 1); + return; + } + } + if (Wait && TR._result) { + global.GlobalRunMap[WebID] = F; + } + else { + F(TR._result < 1 ? 0 : 1, text); + } + }); + }; +}; + +function GetTransactionFromBody(Params, Block, TrNum, Body) { + var TR = global.DApps.Accounts.GetObjectTransaction(Body); + if (TR) { + ConvertBufferToStr(TR); + TR.result = 1; + TR.Meta = Params.Meta; + if (Block.VersionBody === 1 && Block.arrContentResult) { + TR.result = Block.arrContentResult[TrNum]; + } + TR.BlockNum = Block.BlockNum; + TR.TrNum = TrNum; + return TR; + } + return { result: 0, Meta: Params ? Params.Meta : undefined }; +}; diff --git a/src/process/dogs.ts b/src/process/dogs.ts new file mode 100644 index 0000000..1e901a5 --- /dev/null +++ b/src/process/dogs.ts @@ -0,0 +1,10 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + diff --git a/src/process/main-process.ts b/src/process/main-process.ts new file mode 100644 index 0000000..152a8e9 --- /dev/null +++ b/src/process/main-process.ts @@ -0,0 +1,732 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +import '../core/constant' +global.PROCESS_NAME = "MAIN"; +const fs = require('fs'); +const os = require('os'); +import * as crypto from 'crypto'; + +let { + GetNormalPathString, + sha3, + AddTrMap, + ADD_HASH_RATE +} = global + +global.START_SERVER = 1; +global.DATA_PATH = GetNormalPathString(global.DATA_PATH); +global.CODE_PATH = GetNormalPathString(global.CODE_PATH); +console.log("DATA DIR: " + global.DATA_PATH); +console.log("PROGRAM DIR: " + global.CODE_PATH); +require("../core/library"); +global.ToLog(os.platform() + " (" + os.arch() + ") " + os.release()); +var VerArr = process.versions.node.split('.'); +global.ToLog("nodejs: " + process.versions.node); +if ((VerArr[0] as any as number) < 8) { + global.global.ToError("Error version of NodeJS=" + VerArr[0] + " Pls, download new version from www.nodejs.org and update it. The minimum version must be 8"); + process.exit(); +} +var CServer = require("../core/server"); +const DEF_PERIOD_SIGN_LIB = 500; +setTimeout(function() { + TestSignLib(DEF_PERIOD_SIGN_LIB); +}, 4000); +global.glCurNumFindArr = 0; +global.ArrReconnect = []; +global.ArrConnect = []; +var FindList = [ + { "ip": "60.12.241.181", "port": 30000 }, + { "ip": "60.12.241.181", "port": 30001 }, + { "ip": "60.12.241.181", "port": 30002 }, + { "ip": "60.12.241.181", "port": 30003 }, + { "ip": "60.12.241.181", "port": 30004 }, + { "ip": "60.12.241.181", "port": 30005 },]; +if (global.LOCAL_RUN) { + FindList = [{ "ip": "127.0.0.1", "port": 50001 }, { "ip": "127.0.0.1", "port": 50002 }]; +} +else + if (global.TEST_NETWORK) { + FindList = [{ "ip": "149.154.70.158", "port": 40000 },]; + } +global.SERVER = undefined; +global.NeedRestart = 0; +process.on('uncaughtException' as any, function(err: TeraError) { + if (global.PROCESS_NAME !== "MAIN") { + process.send({ cmd: "log", message: err }); + } + global.global.ToError(err.stack); + global.ToLog(err.stack); + if (err.code === "ENOTFOUND" || err.code === "ECONNRESET" || err.code === "EPIPE") { + } + else { + global.TO_ERROR_LOG("APP", 666, err); + global.ToLog("-----------------EXIT------------------"); + process.exit(); + } +}); +process.on('error' as any, function(err: TeraError) { + global.global.ToError(err.stack); + global.ToLog(err.stack); +}); +var ArrChildProcess = []; +var WebProcess: TeraProcess = { + Name: "WEB PROCESS", + idInterval: 0, + idInterval1: 0, + idInterval2: 0, + LastAlive: Date.now(), + Worker: undefined, + Path: "./process/web-process.js", + OnMessage: OnMessageWeb, + PeriodAlive: 10 * 1000 +}; +global.WEB_PROCESS = WebProcess; +if (global.HTTP_HOSTING_PORT && !global.NWMODE) { + ArrChildProcess.push(WebProcess); + WebProcess.idInterval1 = setInterval(function() { + if (WebProcess.Worker && WebProcess.Worker.connected) { + try { + WebProcess.Worker.send({ cmd: "Stat", Name: "MAX:ALL_NODES", Value: global.CountAllNode }); + } + catch (e) { + WebProcess.Worker = undefined; + } + } + }, 500); + WebProcess.idInterval2 = setInterval(function() { + if (WebProcess.Worker && WebProcess.Worker.connected) { + var arr = global.SERVER.GetDirectNodesArray(true, true).slice(1, 500); + var arr2 = []; + var CurTime = global.GetCurrentTime() - 0; + for (var i = 0; i < global.SERVER.NodesArr.length; i++) { + var Item = global.SERVER.NodesArr[i]; + if (Item.LastTime && (CurTime - Item.LastTime) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000) + arr2.push({ ip: Item.ip, port: Item.port, webport: Item.webport }); + else + if (Item.LastTimeGetNode && (CurTime - Item.LastTimeGetNode) < global.NODES_DELTA_CALC_HOUR * 3600 * 1000) + arr2.push({ ip: Item.ip, port: Item.port, webport: Item.webport }); + } + WebProcess.Worker.send({ cmd: "NodeList", Value: arr, ValueAll: arr2 }); + } + }, 5000); +} + +function OnMessageWeb(msg) { + switch (msg.cmd) { + case "SetSmartEvent": + { + if (global.TX_PROCESS && global.TX_PROCESS.Worker) { + global.TX_PROCESS.Worker.send(msg); + } + break; + } + } +}; + +function AddTransactionFromWeb(Params) { + var body = global.GetArrFromHex(Params.HexValue); + if (global.TX_PROCESS && global.TX_PROCESS.Worker) { + var StrHex = global.GetHexFromArr(sha3(body)); + global.TX_PROCESS.Worker.send({ cmd: "FindTX", TX: StrHex, Web: 1, WebID: Params.WebID }); + } + var Res = global.SERVER.AddTransaction({ body: body }, 1); + var text = AddTrMap[Res]; + var final = false; + if (Res <= 0 && Res !== - 3) + final = true; + global.ToLogClient("Send: " + text, global.GetHexFromArr(sha3(body)), final); + return text; +}; +global.AddTransactionFromWeb = AddTransactionFromWeb; +global.STATIC_PROCESS = { + Name: "STATIC PROCESS", + idInterval: 0, + idInterval1: 0, + idInterval2: 0, + LastAlive: Date.now(), + Worker: undefined, + Path: "./process/static-process.js", + OnMessage: OnMessageStatic, + PeriodAlive: 50000 +}; +ArrChildProcess.push(global.STATIC_PROCESS); + +function OnMessageStatic(msg) { + switch (msg.cmd) { + case "Send": + { + var Node = global.SERVER.NodesMap[msg.addrStr]; + if (Node) { + msg.Data = msg.Data.data; + global.SERVER.Send(Node, msg, 1); + } + break; + } + } +}; +global.TX_PROCESS = { + Name: "TX PROCESS", + idInterval: 0, + idInterval1: 0, + idInterval2: 0, + LastAlive: Date.now(), + Worker: undefined, + Path: "./process/tx-process.js", + OnMessage: OnMessageTX, + PeriodAlive: 100 * 1000 +}; +ArrChildProcess.push(global.TX_PROCESS); + +function OnMessageTX(msg) { + switch (msg.cmd) { + case "DappEvent": + { + if (WebProcess && WebProcess.Worker) { + WebProcess.Worker.send(msg); + } + global.AddDappEventToGlobalMap(msg.Data); + break; + } + } +}; + +function StartAllProcess(bClose) { + for (var i = 0; i < ArrChildProcess.length; i++) { + var Item = ArrChildProcess[i]; + StartChildProcess(Item); + } + if (bClose) + setInterval(function() { + if (global.DApps && global.DApps.Accounts) { + global.DApps.Accounts.Close(); + global.DApps.Smart.DBSmart.Close(); + } + if (global.WALLET && global.DApps.DBHistory) + global.DApps.DBHistory.Close(); + }, 500); +}; +var GlobalRunID = 0; +var GlobalRunMap = {}; + +function StartChildProcess(Item) { + let ITEM = Item; + ITEM.idInterval = setInterval(function() { + var Delta0 = Date.now() - ITEM.LastAlive; + if (Delta0 >= 0) { + var Delta = Date.now() - ITEM.LastAlive; + if (ITEM.Worker && Delta > ITEM.PeriodAlive) { + if (ITEM.Worker) { + global.ToLog("KILL PROCESS " + ITEM.Name + ": " + ITEM.Worker.pid); + try { + process.kill(ITEM.Worker.pid, 'SIGKILL'); + } + catch (e) { + global.ToLog("ERR KILL"); + } + ITEM.Worker = undefined; + } + } + if (!ITEM.Worker) { + ITEM.LastAlive = (Date.now()) + ITEM.PeriodAlive * 3; + global.ToLog("STARTING " + ITEM.Name); + ITEM.Worker = Fork(ITEM.Path, ["READONLYDB"]); + ITEM.pid = ITEM.Worker.pid; + global.ToLog("STARTED " + ITEM.Name + ":" + ITEM.pid); + ITEM.Worker.on('message', function(msg) { + if (ITEM.LastAlive < Date.now()) + ITEM.LastAlive = Date.now(); + switch (msg.cmd) { + case "call": + var Err = 0; + var Ret; + try { + if (typeof msg.Params === "object" && msg.Params.F) { + global[msg.Name](msg.Params, function(Err, Ret) { + if (msg.id && ITEM.Worker) + ITEM.Worker.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); + }); + break; + } + else { + Ret = global[msg.Name](msg.Params); + } + } + catch (e) { + Err = 1; + Ret = "" + e; + } + if (msg.id && ITEM.Worker) + ITEM.Worker.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); + break; + case "retcall": + var F = GlobalRunMap[msg.id]; + if (F) { + delete GlobalRunMap[msg.id]; + F(msg.Err, msg.Params); + } + break; + case "log": + global.ToLog(msg.message); + break; + case "global.ToLogClient": + if (WebProcess && WebProcess.Worker) { + WebProcess.Worker.send(msg); + } + global.ToLogClient(msg.Str, msg.StrKey, msg.bFinal); + break; + case "RetFindTX": + if (WebProcess && WebProcess.Worker) { + WebProcess.Worker.send(msg); + if (msg.Web) + break; + } + global.ToLogClient(msg.ResultStr, msg.TX, msg.bFinal); + break; + case "online": + if (ITEM.Worker) + global.ToLog("RUNNING " + ITEM.Name + " : " + msg.message + " pid: " + ITEM.Worker.pid); + break; + case "WriteBodyResult": + var Block = global.SERVER.ReadBlockDB(msg.BlockNum); + if (Block) { + Block.arrContentResult = msg.arrContentResult; + global.SERVER.WriteBodyResultDB(Block); + } + break; + default: + if (ITEM.OnMessage) { + ITEM.OnMessage(msg); + } + break; + } + }); + ITEM.Worker.on('error', function(err) { + }); + ITEM.Worker.on('close', function(code) { + global.global.ToError("CLOSE " + ITEM.Name); + }); + } + } + if (ITEM.Worker) { + ITEM.Worker.send({ cmd: "Alive" }); + } + }, 500); + ITEM.RunRPC = function(Name, Params, F) { + if (!ITEM.Worker) + return; + if (F) { + GlobalRunID++; + try { + ITEM.Worker.send({ cmd: "call", id: GlobalRunID, Name: Name, Params: Params }); + GlobalRunMap[GlobalRunID] = F; + } + catch (e) { + } + } + else { + ITEM.Worker.send({ cmd: "call", id: 0, Name: Name, Params: Params }); + } + }; +}; +global.StopChildProcess = function() { + for (var i = 0; i < ArrChildProcess.length; i++) { + var Item = ArrChildProcess[i]; + if (Item.idInterval) + clearInterval(Item.idInterval); + Item.idInterval = 0; + if (Item.idInterval1) + clearInterval(Item.idInterval1); + Item.idInterval1 = 0; + if (Item.idInterval2) + clearInterval(Item.idInterval2); + Item.idInterval2 = 0; + if (Item.Worker && Item.Worker.connected) { + Item.Worker.send({ cmd: "Exit" }); + Item.Worker = undefined; + } + } + RunStopPOWProcess("STOP"); +}; +require("../core/html-server"); +RunServer(); +let { + ArrReconnect, + ArrConnect +} = global +setInterval(function run1() { + DoConnectToNodes(ArrReconnect, "RECONNECT"); +}, 200); +setInterval(function run2() { + DoGetNodes(); + DoConnectToNodes(ArrConnect, "CONNECT"); +}, 500); +var StartCheckMining = 0; +global.MiningPaused = 0; +var ProcessMemorySize = 0; +global.ArrMiningWrk = []; +var BlockMining; +if (global.ADDRLIST_MODE) { + // @ts-ignore + return; +} +let ArrMiningWrk = global.ArrMiningWrk +function AllAlive() { + for (var i = 0; i < ArrMiningWrk.length; i++) { + ArrMiningWrk[i].send({ cmd: "Alive" }); + } +}; + +function ClearArrMining() { + for (var i = 0; i < ArrMiningWrk.length; i++) { + ArrMiningWrk[i].send({ cmd: "Exit" }); + } + ArrMiningWrk = []; +}; + +let { + GetCountMiningCPU, + CHECK_RUN_MINING, + GetSecFromStrTime, + SERVER, + GENERATE_BLOCK_ACCOUNT, + GetCodePath, + GrayConnect +} = global + +function RunStopPOWProcess(Mode) { + if (!GetCountMiningCPU() || GetCountMiningCPU() <= 0) + return; + if (!StartCheckMining) { + StartCheckMining = 1; + setInterval(RunStopPOWProcess, CHECK_RUN_MINING); + setInterval(AllAlive, 1000); + } + if (global.NeedRestart) + return; + if (global.USE_MINING && global.MINING_START_TIME && global.MINING_PERIOD_TIME) { + var Time = global.GetCurrentTime(); + var TimeCur = Time.getUTCHours() * 3600 + Time.getUTCMinutes() * 60 + Time.getUTCSeconds(); + var StartTime = GetSecFromStrTime(global.MINING_START_TIME); + var RunPeriod = GetSecFromStrTime(global.MINING_PERIOD_TIME); + var TimeEnd = StartTime + RunPeriod; + global.MiningPaused = 1; + if (TimeCur >= StartTime && TimeCur <= TimeEnd) { + global.MiningPaused = 0; + } + else { + StartTime -= 24 * 3600; + TimeEnd -= 24 * 3600; + if (TimeCur >= StartTime && TimeCur <= TimeEnd) { + global.MiningPaused = 0; + } + } + if (ArrMiningWrk.length && global.MiningPaused) { + global.ToLog("------------ MINING MUST STOP ON TIME"); + ClearArrMining(); + return; + } + else + if (!ArrMiningWrk.length && !global.MiningPaused) { + global.ToLog("*********** MINING MUST START ON TIME"); + } + else { + return; + } + } + else { + global.MiningPaused = 0; + } + if (!global.USE_MINING || Mode === "STOP") { + ClearArrMining(); + return; + } + if (global.USE_MINING && ArrMiningWrk.length) + return; + if (SERVER.LoadHistoryMode) + return; + if (GENERATE_BLOCK_ACCOUNT < 8) + return; + var PathMiner = GetCodePath("../miner.js"); + if (!fs.existsSync(PathMiner)) + PathMiner = "./process/pow-process.js"; + if (ArrMiningWrk.length >= GetCountMiningCPU()) + return; + if (GrayConnect()) { + global.ToLog("CANNOT START MINER IN NOT DIRECT IP MODE"); + return; + } + var Memory; + if (global.SIZE_MINING_MEMORY) + Memory = global.SIZE_MINING_MEMORY; + else { + Memory = os.freemem() - (512 + GetCountMiningCPU() * 100) * 1024 * 1014; + if (Memory < 0) { + global.ToLog("Not enough memory to start processes."); + return; + } + } + ProcessMemorySize = Math.trunc(Memory / GetCountMiningCPU()); + global.ToLog("START MINER PROCESS COUNT: " + GetCountMiningCPU() + " Memory: " + ProcessMemorySize / 1024 / 1024 + " Mb for each process"); + for (var R = 0; R < GetCountMiningCPU(); R++) { + let Worker = Fork(PathMiner); + ArrMiningWrk.push(Worker); + Worker.Num = ArrMiningWrk.length; + Worker.on('message', function(msg) { + if (msg.cmd === "log") { + global.ToLog(msg.message); + } + else + if (msg.cmd === "online") { + Worker.bOnline = true; + global.ToLog("RUNNING PROCESS:" + Worker.Num + ":" + msg.message); + } + else + if (msg.cmd === "POW") { + global.SERVER.MiningProcess(msg); + } + else + if (msg.cmd === "HASHRATE") { + ADD_HASH_RATE(msg.CountNonce); + } + }); + Worker.on('error', function(err) { + if (!ArrMiningWrk.length) + return; + global.global.ToError('ERROR IN PROCESS: ' + err); + }); + Worker.on('close', function(code) { + global.ToLog("STOP PROCESS: " + Worker.Num + " pid:" + Worker.pid); + for (var i = 0; i < ArrMiningWrk.length; i++) { + if (ArrMiningWrk[i].pid === Worker.pid) { + global.ToLog("Delete wrk from arr - pid:" + Worker.pid); + ArrMiningWrk.splice(i, 1); + } + } + }); + } +}; + +function SetCalcPOW(Block, cmd) { + if (!global.USE_MINING) + return; + if (ArrMiningWrk.length !== GetCountMiningCPU()) + return; + BlockMining = Block; + for (var i = 0; i < ArrMiningWrk.length; i++) { + var CurWorker = ArrMiningWrk[i]; + if (!CurWorker.bOnline) + continue; + CurWorker.send({ + cmd: cmd, BlockNum: Block.BlockNum, Account: GENERATE_BLOCK_ACCOUNT, MinerID: GENERATE_BLOCK_ACCOUNT, SeqHash: Block.SeqHash, + Hash: Block.Hash, PrevHash: Block.PrevHash, Time: Date.now(), Num: CurWorker.Num, RunPeriod: global.POWRunPeriod, RunCount: global.POW_RUN_COUNT, + Percent: global.POW_MAX_PERCENT, CountMiningCPU: GetCountMiningCPU(), ProcessMemorySize: ProcessMemorySize, + }); + } +}; +global.SetCalcPOW = SetCalcPOW; +global.RunStopPOWProcess = RunStopPOWProcess; +let { + glCurNumFindArr +} = global +function DoGetNodes() { + if (!SERVER) + return; + if (!GrayConnect() && global.SERVER.CanSend < 2) + return; + if (!SERVER.NodesArrUnSort || !SERVER.NodesArrUnSort.length) + return; + var Num = glCurNumFindArr % global.SERVER.NodesArrUnSort.length; + var Node = global.SERVER.NodesArrUnSort[Num]; + if (Num === 0) + glCurNumFindArr = 0; + glCurNumFindArr++; + if (Node.Delete) + return; + if (SERVER.NodeInBan(Node)) + return; + if (SERVER.BusyLevel && Node.BlockProcessCount <= global.SERVER.BusyLevel) + return; + if (GetSocketStatus(Node.Socket) === 100) { + global.SERVER.StartGetNodes(Node); + } +}; + +function DoConnectToNodes(Arr, Mode) { + if (!SERVER) + return; + if (!GrayConnect() && global.SERVER.CanSend < 2) { + return; + } + if (GrayConnect() && global.SERVER.ActualNodes.size > GetGrayServerConnections()) + return; + if (Arr.length) { + var MinProcessCount = global.SERVER.BusyLevel - 1; + for (var i = 0; i < Arr.length; i++) { + var Node = Arr[i]; + if (Node.BlockProcessCount > MinProcessCount) { + Arr.splice(i, 1); + if (Mode === "CONNECT") { + Node.WasAddToConnect = undefined; + global.SERVER.StartConnectTry(Node); + } + else + if (Mode === "RECONNECT") { + Node.WasAddToReconnect = undefined; + Node.CreateConnect(); + } + break; + } + } + } +}; +var idRunOnce; + +function RunServer() { + let { + GetNetworkName, + DEF_VERSION, + NET_WORK_MODE, + SAVE_CONST, + ToLog, + START_IP, + START_PORT_NUMBER + } = global + idRunOnce = setInterval(RunOnce, 1000); + global.ToLog("NETWORK: " + GetNetworkName()); + global.ToLog("VERSION: " + DEF_VERSION); + if (global.NET_WORK_MODE) { + global.START_IP = NET_WORK_MODE.ip; + global.START_PORT_NUMBER = NET_WORK_MODE.port; + } + var KeyPair = crypto.createECDH('secp256k1'); + if (!global.SERVER_PRIVATE_KEY_HEX || global.NEW_SERVER_PRIVATE_KEY) { + while (true) { + var Arr = crypto.randomBytes(32); + KeyPair.setPrivateKey(Buffer.from(Arr)); + var Arr2: any = KeyPair.getPublicKey('' as any, 'compressed'); + if (Arr2[0] === 2) + break; + } + global.SERVER_PRIVATE_KEY_HEX = global.GetHexFromArr(Arr); + SAVE_CONST(true); + } + var ServerPrivKey = global.GetArrFromHex(global.SERVER_PRIVATE_KEY_HEX); + if (global.USE_NET_FOR_SERVER_ADDRES) { + const os = require('os'); + var map = os.networkInterfaces(); + main: + for (var key in map) { + var arr = map[key]; + for (var i = 0; i < arr.length; i++) { + var item = arr[i]; + if (!item.internal && item.mac !== "00:00:00:00:00:00") { + ServerPrivKey = global.sha3(global.SERVER_PRIVATE_KEY_HEX + ":" + item.mac + ":" + global.START_PORT_NUMBER); + break main; + } + } + } + } + KeyPair.setPrivateKey(Buffer.from(ServerPrivKey)); + new CServer(KeyPair, START_IP, START_PORT_NUMBER, false, false); + DoStartFindList(); +}; + +function DoStartFindList() { + var keyThisServer = global.SERVER.ip + ":" + global.SERVER.port; + for (var n = 0; n < FindList.length; n++) { + var item = FindList[n]; + if (!item.ip) + continue; + var key = item.ip + ":" + item.port; + if (keyThisServer === key) + continue; + var addrStr = global.GetHexFromAddres(crypto.randomBytes(32)); + var Node = global.SERVER.GetNewNode(addrStr, item.ip, item.port); + Node.addrStrTemp = addrStr; + Node.StartFindList = 1; + } +}; + +function RunOnce() { + if (global.SERVER && global.SERVER.CheckOnStartComplete) { + clearInterval(idRunOnce); + require("../core/update"); + RunOnUpdate(); + StartAllProcess(1); + require("./dogs"); + if (global.RESTART_PERIOD_SEC) { + var Period = (global.random(600) + global.RESTART_PERIOD_SEC); + global.ToLog("SET RESTART NODE AFTER: " + Period + " sec"); + setInterval(function() { + RestartNode(); + }, Period * 1000); + } + setTimeout(function() { + global.RunStopPOWProcess(); + }, 10000); + } +}; +var glPortDebug = 49800; + +function Fork(Path, ArrArgs?) { + const child_process = require('child_process'); + ArrArgs = ArrArgs || []; + if (global.LOCAL_RUN) + ArrArgs.push("LOCALRUN"); + else + if (global.TEST_NETWORK) + ArrArgs.push("TESTRUN"); + ArrArgs.push("PATH:" + global.DATA_PATH); + ArrArgs.push("HOSTING:" + global.HTTP_HOSTING_PORT); + if (!global.USE_PARAM_JS) + ArrArgs.push("NOPARAMJS"); + if (global.NWMODE) + ArrArgs.push("NWMODE"); + if (global.NOALIVE) + ArrArgs.push("NOALIVE"); + if (global.DEV_MODE) + ArrArgs.push("DEV_MODE"); + glPortDebug++; + var execArgv = []; + var Worker = child_process.fork(Path, ArrArgs, { execArgv: execArgv }); + return Worker; +}; +global.SpeedSignLib = 0; +global.TestSignLib = TestSignLib; + +function TestSignLib(MaxTime) { + if (!MaxTime) + MaxTime = DEF_PERIOD_SIGN_LIB; + var hash = Buffer.from(global.GetArrFromHex("A6B0914953F515F4686B2BA921B8FAC66EE6A6D3E317B43E981EBBA52393BFC6")); + var PubKey = Buffer.from(global.GetArrFromHex("026A04AB98D9E4774AD806E302DDDEB63BEA16B5CB5F223EE77478E861BB583EB3")); + var Sign = Buffer.from(global.GetArrFromHex("5D5382C65E4C1E8D412D5F30F87B8F72F371E9E4FC170761BCE583A961CF44966F92B38D402BC1CBCB7567335051A321B93F4E32112129AED4AB602E093A1187")); + var startTime = process.hrtime(); + var deltaTime = 1; + for (var Num = 0; Num < 1000; Num++) { + var Result = global.secp256k1.verify(hash, Sign, PubKey); + if (!Result) { + global.global.ToError("Error test sign"); + process.exit(0); + } + var Time = process.hrtime(startTime); + deltaTime = Time[0] * 1000 + Time[1] / 1e6; + if (deltaTime > MaxTime) { + global.ToLog("*************** WARNING: VERY SLOW LIBRARY: secp256k1 ***************"); + global.ToLog("You can only process: " + Num + " transactions"); + global.ToLog("Install all dependent packages, see detail: https://www.npmjs.com/package/secp256k1"); + global.SpeedSignLib = Num; + return 0; + } + } + global.SpeedSignLib = Math.floor(Num * MaxTime / deltaTime); + global.ToLog("TestSignLib: " + global.SpeedSignLib + " per sec"); + return 1; +}; diff --git a/src/process/pow-process.ts b/src/process/pow-process.ts new file mode 100644 index 0000000..9346ab2 --- /dev/null +++ b/src/process/pow-process.ts @@ -0,0 +1,91 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.PROCESS_NAME = "POW" +global.POWPROCESS = 1 +require("../core/library") +require("../core/crypto-library") +require("../core/terahashmining"); +var PROCESS = process; +process.send && !global.DEBUGPROCESS ? process.send({ cmd: "online", message: "OK" }) : PROCESS = global.DEBUGPROCESS; +var LastAlive = Date.now(); +setInterval(CheckAlive, 1e3); +var idInterval = void 0, Block: any = {}; + +function CheckAlive() { + if (!global.NOALIVE) { + var e = Date.now() - LastAlive; + Math.abs(e) > global.CHECK_STOP_CHILD_PROCESS && PROCESS.exit(0); + } +}; + +function CalcPOWHash() { + if (Block.SeqHash) { + if ((new Date as any) - Block.Time > Block.Period) + return clearInterval(idInterval), void (idInterval = void 0); + try { + global.CreatePOWVersionX(Block) && process.send({ + cmd: "POW", BlockNum: Block.BlockNum, SeqHash: Block.SeqHash, Hash: Block.Hash, PowHash: Block.PowHash, + AddrHash: Block.AddrHash, Num: Block.Num + }); + } + catch (e) { + global.global.ToError(e); + } + } +}; +PROCESS.on("message", function(e) { + if (LastAlive = Date.now(), "FastCalcBlock" === e.cmd) { + var o = e; + StartHashPump(o), o.RunCount = 0; + try { + global.CreatePOWVersionX(o) && process.send({ + cmd: "POW", BlockNum: o.BlockNum, SeqHash: o.SeqHash, Hash: o.Hash, PowHash: o.PowHash, AddrHash: o.AddrHash, + Num: o.Num + }); + } + catch (e) { + global.global.ToError(e); + } + } + else + if ("SetBlock" === e.cmd) { + var a = 1e6 * (1 + e.Num); + Block.HashCount && process.send({ cmd: "HASHRATE", CountNonce: Block.HashCount, Hash: Block.Hash }), Block.HashCount = 0, (Block = e).Time = Date.now(), + Block.LastNonce = a, Block.Period = global.CONSENSUS_PERIOD_TIME * Block.Percent / 100, 0 < Block.Period && 0 < Block.RunPeriod && (CalcPOWHash(), + void 0 !== idInterval && clearInterval(idInterval), idInterval = setInterval(CalcPOWHash, Block.RunPeriod)); + } + else + "Alive" === e.cmd || "Exit" === e.cmd && PROCESS.exit(0); +}); +var idIntervalPump = global.BlockPump = void 0; + +function StartHashPump(e) { + (!global.BlockPump || global.BlockPump.BlockNum < e.BlockNum || global.BlockPump.MinerID !== e.MinerID || global.BlockPump.Percent !== e.Percent) && (global.BlockPump = { + BlockNum: e.BlockNum, + RunCount: e.RunCount, MinerID: e.MinerID, Percent: e.Percent, LastNonce: 0 + }), idIntervalPump || (idIntervalPump = setInterval(PumpHash, + global.POWRunPeriod)); +}; +var StartTime = 1, EndTime = 0; + +function PumpHash() { + if (global.BlockPump) { + var e = Date.now(); + if (EndTime < StartTime) { + if (100 * (e - StartTime) / CONSENSUS_PERIOD_TIME >= BlockPump.Percent) + return void (EndTime = e); + CreatePOWVersionX(BlockPump, 1); + } + else { + 100 * (e - EndTime) / CONSENSUS_PERIOD_TIME > 100 - BlockPump.Percent && (StartTime = e); + } + } +}; diff --git a/src/process/static-process.ts b/src/process/static-process.ts new file mode 100644 index 0000000..6d79420 --- /dev/null +++ b/src/process/static-process.ts @@ -0,0 +1,373 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.PROCESS_NAME = "STATIC"; +import * as crypto from 'crypto'; +const fs = require('fs'); +require("../core/constant"); +require('../core/block-loader-const'); +require('../core/rest_tables.js'); +require('../system/accounts.js'); +require('../system/smart.js'); +global.DATA_PATH = GetNormalPathString(global.DATA_PATH); +global.CODE_PATH = GetNormalPathString(global.CODE_PATH); +require("../core/library"); +global.READ_ONLY_DB = 1; +var LastAlive = Date.now(); +setTimeout(function() { + setInterval(CheckAlive, 1000); +}, 20000); +setInterval(function() { + process.send({ cmd: "Alive" }); +}, 1000); +process.send({ cmd: "online", message: "OK" }); +process.on('message', function(msg) { + LastAlive = Date.now(); + switch (msg.cmd) { + case "ALive": + break; + case "Exit": + process.exit(0); + break; + case "call": + var Err = 0; + var Ret; + try { + Ret = global[msg.Name](msg.Params); + } + catch (e) { + Err = 1; + Ret = "" + e; + } + if (msg.id) + process.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); + break; + case "GETBLOCKHEADER": + GETBLOCKHEADER(msg); + break; + case "GETBLOCKHEADER100": + GETBLOCKHEADER100(msg); + break; + case "GETBLOCK": + GETBLOCK(msg); + break; + case "GETCODE": + GETCODE(msg); + break; + case "GETREST": + GETREST(msg); + break; + case "GETSMART": + GETSMART(msg); + break; + } +}); + +function CheckAlive() { + if (global.NOALIVE) + return; + var Delta = Date.now() - LastAlive; + if (Delta > CHECK_STOP_CHILD_PROCESS) { + global.ToLog("STATIC-DB: ALIVE TIMEOUT Stop and exit: " + Delta + "/" + global.CHECK_STOP_CHILD_PROCESS); + process.exit(0); + return; + } +}; +process.on('uncaughtException', function(err) { + global.ToError(err.stack); + global.ToLog(err.stack); + TO_ERROR_LOG("STATIC-DB", 777, err); + global.ToLog("-----------------STATIC-DB EXIT------------------"); + process.exit(); +}); +process.on('error', function(err) { + global.ToError("STATIC-DB:\n" + err.stack); + global.ToLog(err.stack); +}); +var CServerDB = require("../core/db/block-db"); +var KeyPair = crypto.createECDH('secp256k1'); +KeyPair.setPrivateKey(Buffer.from([77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77])); +global.SERVER = new CServerDB(KeyPair, undefined, undefined, false, true); +global.HTTP_PORT_NUMBER = 0; +setInterval(function() { + if (SERVER) + global.SERVER.Close(); + global.DApps.Accounts.Close(); + global.DApps.Smart.DBSmart.Close(); +}, 1000); + +function GETBLOCKHEADER100(msg) { + return; + var Data = msg.Data; + var BlockNum = Data.BlockNum; + if (BlockNum % 100 !== 0) + return; + var EndNum100 = BlockNum / 100; + var LoadHash100 = Data.Hash; + var Hash100; + var Count = Data.Count; + if (!Count || Count < 0 || !EndNum100) + return; + if (Count > COUNT_BLOCKS_FOR_LOAD) + Count = COUNT_BLOCKS_FOR_LOAD; + var Arr = []; + var Data100 = global.SERVER.DBHeader100.Read(EndNum100); + if (Data100 && global.CompareArr(Data100.Hash100, LoadHash100) === 0) { + var StartNum = EndNum100 - Count + 1; + if (StartNum < 0) + StartNum = 0; + for (var Num = StartNum; Num <= EndNum100; Num++) { + Data100 = global.SERVER.DBHeader100.Read(Num); + if (Num === StartNum) + Arr.push(Data100.Hash100); + Arr.push(Data100.Hash); + } + } + var BufWrite = global.BufLib.GetBufferFromObject(Arr, "[hash]", MAX_PACKET_LENGTH, {}); + global.ToLog("GETBLOCKHEADER100 Send Arr=" + Arr.length + " - " + BlockNum); + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETBLOCKHEADER100", Context: msg.Context, Data: BufWrite }); +}; + +function GETBLOCKHEADER(msg) { + var Data = msg.Data; + var StartNum = undefined; + var BlockNum; + var LoadHash = Data.Hash; + var Foward = Data.Foward; + if (Foward) { + var BlockDB = global.SERVER.ReadBlockHeaderDB(Data.BlockNum); + if (BlockDB && BlockDB.SumHash && (global.CompareArr(BlockDB.SumHash, LoadHash) === 0 || IsZeroArr(LoadHash))) { + StartNum = Data.BlockNum - global.BLOCK_PROCESSING_LENGTH2; + if (StartNum < 0) + StartNum = 0; + BlockNum = StartNum + COUNT_BLOCKS_FOR_LOAD + global.BLOCK_PROCESSING_LENGTH2; + if (BlockNum > global.SERVER.GetMaxNumBlockDB()) + BlockNum = global.SERVER.GetMaxNumBlockDB(); + } + } + else { + BlockNum = Data.BlockNum; + var IsSum = Data.IsSum; + var Count = Data.Count; + if (!Count || Count < 0 || BlockNum < 0) + return; + if (Count > COUNT_BLOCKS_FOR_LOAD) + Count = COUNT_BLOCKS_FOR_LOAD; + Count += global.BLOCK_PROCESSING_LENGTH2; + var BlockDB = global.SERVER.ReadBlockHeaderDB(BlockNum); + if (BlockDB && (BlockDB.Prepared && (!IsSum) && BlockDB.Hash && global.CompareArr(BlockDB.Hash, LoadHash) === 0 || BlockDB.bSave && IsSum && BlockDB.SumHash && global.CompareArr(BlockDB.SumHash, + LoadHash) === 0)) { + StartNum = BlockNum - Count + 1; + if (StartNum < 0) + StartNum = 0; + } + } + var BufWrite = global.SERVER.BlockChainToBuf(StartNum, StartNum, BlockNum); + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETBLOCKHEADER", Context: msg.Context, Data: BufWrite }); +}; + +function GETBLOCK(msg) { + var Data = msg.Data; + var BlockNum = Data.BlockNum; + var TreeHash = Data.TreeHash; + if (msg.Context.SendCount) { + return; + } + var BufWrite; + var BlockDB = global.SERVER.ReadBlockDB(BlockNum); + var StrSend; + if (BlockDB && (global.CompareArr(BlockDB.TreeHash, TreeHash) === 0 || IsZeroArr(TreeHash))) { + var BufWrite = global.BufLib.GetBufferFromObject(BlockDB, FORMAT_BLOCK_TRANSFER, MAX_PACKET_LENGTH, WRK_BLOCK_TRANSFER); + StrSend = "OK"; + } + if (StrSend === "OK") { + global.ADD_TO_STAT("BLOCK_SEND"); + } + else { + BufWrite = global.BufLib.GetNewBuffer(100); + StrSend = "NO"; + } + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETGETBLOCK", Context: msg.Context, Data: BufWrite }); +}; + +function GETCODE(msg) { + var VersionNum = msg.Data; + var fname = global.GetDataPath("Update/wallet-" + VersionNum + ".zip"); + if (fs.existsSync(fname)) { + var data = fs.readFileSync(fname); + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETCODE", Context: msg.Context, Data: data }); + } +}; + +function GETREST(msg) { + var Data = msg.Data; + if (!Data.BlockNum) + return; + if (IsZeroArr(Data.AccHash)) { + return; + } + var BlockNumRest = Data.BlockNum; + var RestIndexArr = GetCurrentRestArr(); + var nResult = 0; + for (var i = 0; i < RestIndexArr.length; i++) { + if (RestIndexArr[i] === BlockNumRest) { + nResult = 1; + break; + } + } + var BufLength = 1000; + var ProofHash = []; + var ProofArrL = []; + var ProofArrR = []; + var ArrRest = []; + if (nResult) { + var WorkStruct = {}; + var WorkFormat = global.DApps.Accounts.FORMAT_ACCOUNT_ROW; + var WorkFormatLength = global.DApps.Accounts.SIZE_ACCOUNT_ROW; + var Max = global.DApps.Accounts.DBState.GetMaxNum(); + var LengthAccount = Data.Count; + if (LengthAccount > MAX_ACCOUNTS_TRANSFER) + LengthAccount = MAX_ACCOUNTS_TRANSFER; + var StartAccount = Data.AccNum; + var EndAccount = StartAccount + LengthAccount - 1; + if (EndAccount > Max) + EndAccount = Max; + var Tree = GetRestMerkleTree(BlockNumRest, RestIndexArr); + if (global.CompareArr(Data.AccHash, Tree.Root) !== 0) { + global.ToLog("Get bad rest acc hash: " + BlockNumRest + " = " + global.GetHexFromArr(Data.AccHash) + "/" + global.GetHexFromArr(Tree.Root), 2); + ArrRest = []; + nResult = 0; + } + else { + ArrRest = GetArrRest(BlockNumRest, StartAccount, EndAccount); + ProofHash = Tree.Root; + var RetProof = GetMerkleProof(Tree.LevelsHash, StartAccount, EndAccount); + ProofArrL = RetProof.ArrL; + ProofArrR = RetProof.ArrR; + BufLength = 1000 + ArrRest.length * WorkFormatLength; + BufLength += ProofArrL.length * 32 + ProofArrR.length * 32 + 32; + } + } + var Data2 = { Result: nResult, Arr: ArrRest, Version: 1, ProofHash: ProofHash, ProofArrL: ProofArrL, ProofArrR: ProofArrR }; + var BufWrite = global.BufLib.GetBufferFromObject(Data2, FORMAT_REST_TRANSFER, BufLength, {}); + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETREST", Context: msg.Context, Data: BufWrite }); +}; + +function GETSMART(msg) { + var Data = msg.Data; + if (!Data.Count) + return; + var BufLength = 1000; + var SizeForSend = 200 * 1024; + var Arr = []; + for (var Num = Data.SmartNum; Num < Data.SmartNum + Data.Count; Num++) { + var BufSmart = global.DApps.Smart.DBSmart.Read(Num, 1); + if (!BufSmart) + break; + SizeForSend = SizeForSend - BufSmart.length; + if (SizeForSend < 0) + break; + BufLength += BufSmart.length; + Arr.push(BufSmart); + } + var Data2 = { Result: Arr.length ? 1 : 0, Arr: Arr }; + var BufWrite = global.BufLib.GetBufferFromObject(Data2, FORMAT_SMART_TRANSFER, BufLength, {}); + process.send({ cmd: "Send", addrStr: msg.addrStr, Method: "RETSMART", Context: msg.Context, Data: BufWrite }); +}; +var glMapForHash = {}; + +function GetArrRest(BlockNumRest, StartAccount, EndAccount, bHashOnly) { + var ArrRest = []; + var WorkStruct = {}; + var WorkFormat = global.DApps.Accounts.FORMAT_ACCOUNT_ROW; + var WorkFormatLength = global.DApps.Accounts.SIZE_ACCOUNT_ROW; + for (var Num = StartAccount; Num <= EndAccount; Num++) { + var FindItem = undefined; + var RestData = global.DApps.Accounts.ReadRest(Num); + var CountZero = 0; + for (var i = RestData.Arr.length - 1; i >= 0; i--) { + var Item = RestData.Arr[i]; + if (!Item.BlockNum) { + CountZero++; + continue; + } + if (Item.BlockNum <= BlockNumRest) { + if (!FindItem || Item.BlockNum > FindItem.BlockNum) { + FindItem = Item; + } + } + } + var BlocNumMap = 0; + var StateDataValue = undefined; + if (FindItem) { + StateDataValue = FindItem.Value; + BlocNumMap = Item.BlockNum; + } + else { + if (CountZero !== RestData.Arr.length) + continue; + } + var StateData = global.DApps.Accounts.DBState.Read(Num); + if (!StateData) + break; + if (StateDataValue) + StateData.Value = StateDataValue; + if (bHashOnly) { + var key = "" + Num + "-" + BlocNumMap; + var Hash = glMapForHash[key]; + if (!Hash) { + var Buf = global.BufLib.GetBufferFromObject(StateData, WorkFormat, WorkFormatLength, WorkStruct); + Hash = global.shaarr(Buf); + glMapForHash[key] = Hash; + } + ArrRest.push(Hash); + } + else { + var Buf = global.BufLib.GetBufferFromObject(StateData, WorkFormat, WorkFormatLength, WorkStruct); + ArrRest.push(Buf); + } + } + return ArrRest; +}; +var glMapRest = {}; + +function GetRestMerkleTree(BlockNumRest, RestIndexArr) { + var MerkleTree = glMapRest[BlockNumRest]; + if (!MerkleTree) { + global.ToLog("Create new glMapRest key: " + BlockNumRest, 2); + var startTime = process.hrtime(); + var EndAccount = global.DApps.Accounts.DBState.GetMaxNum(); + var ArrHash = GetArrRest(BlockNumRest, 0, EndAccount, 1); + var Time1 = process.hrtime(startTime); + var MerkleCalc = {}; + MerkleTree = { LevelsHash: [ArrHash], RecalcCount: 0 }; + for (var Num = 0; Num < ArrHash.length; Num++) { + MerkleCalc[Num] = 1; + } + UpdateMerklTree(MerkleTree, MerkleCalc, 0); + glMapRest[BlockNumRest] = MerkleTree; + var Time2 = process.hrtime(startTime); + var deltaTime1 = (Time1[0] * 1000 + Time1[1] / 1e6) / 1000; + var deltaTime2 = (Time2[0] * 1000 + Time2[1] / 1e6) / 1000; + global.ToLog("Create delta time: " + deltaTime1 + "/" + deltaTime2 + " s Tree.Root=" + global.GetHexFromArr(MerkleTree.Root), 2); + var MapIndex = {}; + for (var i = 0; i < RestIndexArr.length; i++) { + MapIndex[RestIndexArr[i]] = 1; + } + for (var key in glMapRest) { + if (!MapIndex[key]) { + global.ToLog("Delete old glMapRest key: " + key, 2); + delete glMapRest[key]; + } + } + } + return MerkleTree; +}; diff --git a/src/process/tx-process.ts b/src/process/tx-process.ts new file mode 100644 index 0000000..7f70586 --- /dev/null +++ b/src/process/tx-process.ts @@ -0,0 +1,354 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +global.PROCESS_NAME = "TX"; +import * as crypto from 'crypto'; +const fs = require('fs'); +require("../core/constant"); +global.DATA_PATH = GetNormalPathString(global.DATA_PATH); +global.CODE_PATH = GetNormalPathString(global.CODE_PATH); +require("../core/library"); +global.READ_ONLY_DB = 0; +var LastAlive = Date.now(); +setTimeout(function() { + setInterval(CheckAlive, 1000); +}, 20000); +setInterval(PrepareStatEverySecond, 1000); +if (process.send) { + setInterval(function() { + process.send({ cmd: "Alive" }); + }, 1000); + process.send({ cmd: "online", message: "OK" }); + global.ToLogClient = function(Str, StrKey, bFinal) { + process.send({ cmd: "ToLogClient", Str: "" + Str, StrKey: StrKey, bFinal: bFinal }); + }; +} +process.on('message', function(msg) { + LastAlive = Date.now(); + switch (msg.cmd) { + case "ALive": + break; + case "Exit": + process.exit(0); + break; + case "call": + var Err = 0; + var Ret; + try { + Ret = global[msg.Name](msg.Params); + } + catch (e) { + Err = 1; + Ret = "" + e; + } + if (msg.id) + process.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); + break; + case "FindTX": + global.TreeFindTX.SaveValue(msg.TX, msg); + break; + case "SetSmartEvent": + global.TreeFindTX.SaveValue("Smart:" + msg.Smart, 1); + break; + case "Eval": + EvalCode(msg.Code); + break; + default: + break; + } +}); +global.SetStatMode = function(Val) { + global.STAT_MODE = Val; + return global.STAT_MODE; +}; + +function CheckAlive() { + if (global.NOALIVE) + return; + var Delta = Date.now() - LastAlive; + if (Delta > 100 * 1000) { + global.ToLog("TX-PROCESS: ALIVE TIMEOUT Stop and exit: " + Delta); + process.exit(0); + return; + } +}; +process.on('uncaughtException', function(err) { + global.ToError(err.stack); + global.ToLog(err.stack); + TO_ERROR_LOG("TX-PROCESS", 777, err); + global.ToLog("-----------------TX-PROCESS EXIT------------------"); + process.exit(); +}); +process.on('error', function(err) { + global.ToError("TX-PROCESS:\n" + err.stack); + global.ToLog(err.stack); +}); +global.HTTP_PORT_NUMBER = 0; +var CServerDB = require("../core/transaction-validator"); +var KeyPair = crypto.createECDH('secp256k1'); +KeyPair.setPrivateKey(Buffer.from([77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77])); +global.SERVER = new CServerDB(KeyPair, undefined, undefined, false, true); +global.TreeFindTX = new STreeBuffer(30 * 1000, CompareItemHashSimple, "string"); +setInterval(function() { + if (SERVER) { + global.SERVER.Close(); + } + DoTXProcess(); +}, 10); +var BlockTree = new STreeBuffer(30 * 1000, CompareItemHashSimple, "number"); +global.bShowDetail = 0; +var StopTxProcess = 0; +var MinimalValidBlock = 0; +var LastBlockNum = undefined; + +function DoTXProcess() { + if (StopTxProcess) + return; + if (LastBlockNum === undefined) + InitTXProcess(); + var BlockMin = FindMinimal(); + if (!BlockMin) { + if (bShowDetail) + global.ToLog("!BlockMin"); + return; + } + var StartTime = Date.now(); + if (bShowDetail) + global.ToLog("BlockMin: " + BlockMin.BlockNum + " LastBlockNum=" + LastBlockNum); + var CountTX = 0; + for (var Num = BlockMin.BlockNum; Num < BlockMin.BlockNum + 200; Num++) { + var EndTime = Date.now(); + var Delta = EndTime - StartTime; + if (Delta >= 1000) + break; + var Block = global.SERVER.ReadBlockDB(Num); + if (!Block) { + if (bShowDetail) + global.ToLog("!Block"); + break; + } + if (!IsValidSumHash(Block)) { + break; + } + var Item = BlockTree.LoadValue(Block.BlockNum, 1); + if (Item && global.CompareArr(Item.SumHash, Block.SumHash) === 0) { + if (bShowDetail) + global.ToLog("WAS CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12)); + continue; + } + if (Num > 0) { + var Block0 = global.SERVER.ReadBlockDB(Num - 1); + if (Block0) { + var Item0 = BlockTree.LoadValue(Block0.BlockNum, 1); + if (Item0 && global.CompareArr(Item0.SumHash, Block0.SumHash) !== 0) { + break; + } + } + } + global.SERVER.BlockProcessTX(Block); + if (Num % 100000 === 0) + global.ToLog("CALC: " + Num); + CountTX++; + if (bShowDetail) + global.ToLog(" CALC: " + Num + " SumHash: " + global.GetHexFromArr(Block.SumHash).substr(0, 12)); + BlockTree.SaveValue(Block.BlockNum, { BlockNum: Block.BlockNum, SumHash: Block.SumHash }); + LastBlockNum = Block.BlockNum; + } +}; + +function FindMinimal() { + var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB(); + if (MaxNumBlockDB && MaxNumBlockDB < LastBlockNum) { + if (bShowDetail) + global.ToLog("MaxNumBlockDB 0) { + RewriteAllTransactions(); + } + Block = global.SERVER.ReadBlockHeaderDB(MinimalValidBlock); + return Block; +}; + +function IsValidSumHash(Block) { + if (Block.BlockNum <= MinimalValidBlock + global.BLOCK_PROCESSING_LENGTH2) + return 1; + if (Block.BlockNum < 16) + return 1; + if (IsZeroArr(Block.SumHash)) + return 0; + var PrevBlock = global.SERVER.ReadBlockHeaderDB(Block.BlockNum - 1); + if (!PrevBlock) + return 0; + var SumHash2 = shaarr2(PrevBlock.SumHash, Block.Hash); + if (global.CompareArr(SumHash2, Block.SumHash) === 0) + return 1; + return 0; +}; + +function InitTXProcess() { + var StateTX = global.DApps.Accounts.DBStateTX.Read(0); + if (!StateTX) { + LastBlockNum = 0; + var MaxNum = global.DApps.Accounts.DBAccountsHash.GetMaxNum(); + if (MaxNum > 0) { + var Item = global.DApps.Accounts.DBAccountsHash.Read(MaxNum); + if (Item) { + LastBlockNum = Item.BlockNum; + } + } + global.ToLog("DETECT NEW VER on BlockNum=" + LastBlockNum, 2); + global.DApps.Accounts.DBStateTX.Write({ Num: 0, BlockNum: LastBlockNum, BlockNumMin: MinimalValidBlock }); + } + StateTX = global.DApps.Accounts.DBStateTX.Read(0); + LastBlockNum = StateTX.BlockNum; + MinimalValidBlock = StateTX.BlockNumMin; + LastBlockNum = PERIOD_ACCOUNT_HASH * Math.trunc(LastBlockNum / PERIOD_ACCOUNT_HASH); + if (LastBlockNum > 100) { + LastBlockNum = 1 + LastBlockNum - 100; + } + global.DApps.Accounts.CalcMerkleTree(1); + if (LastBlockNum <= 0) + RewriteAllTransactions(); + else + global.ToLog("Start NUM = " + LastBlockNum, 2); +}; +global.ClearDataBase = ClearDataBase; + +function ClearDataBase() { + MinimalValidBlock = 0; + for (var key in DApps) { + DApps[key].ClearDataBase(); + } + LastBlockNum = 0; + BlockTree.Clear(); +}; +global.RewriteAllTransactions = RewriteAllTransactions; + +function RewriteAllTransactions() { + if (MinimalValidBlock > 0) { + global.ToLog("*************Cant run RewriteAllTransactions, MinimalValidBlock:" + MinimalValidBlock, 2); + return; + } + global.ToLog("*************RewriteAllTransactions"); + for (var key in DApps) { + DApps[key].ClearDataBase(); + } + LastBlockNum = 0; + BlockTree.Clear(); + global.ToLog("Start num = " + LastBlockNum, 2); +}; +global.ReWriteDAppTransactions = ReWriteDAppTransactions; + +function ReWriteDAppTransactions(Params) { + var StartNum = Params.StartNum; + var EndNum = Params.EndNum; + global.ToLog("ReWriteDAppTransactions: " + StartNum + " - " + EndNum); + BlockTree.Clear(); + if (StartNum < LastBlockNum) + LastBlockNum = StartNum; + global.ToLog("Start num = " + LastBlockNum, 2); +}; + +function TXPrepareLoadRest(BlockNum) { + StopTxProcess = 1; + MinimalValidBlock = BlockNum; + global.ToLog("*************TXPrepareLoadRest:" + BlockNum, 2); + for (var key in DApps) { + DApps[key].ClearDataBase(); + } + LastBlockNum = BlockNum; + BlockTree.Clear(); + global.DApps.Accounts.DBStateTX.Write({ Num: 0, BlockNum: LastBlockNum, BlockNumMin: LastBlockNum }); +}; +global.TXPrepareLoadRest = TXPrepareLoadRest; + +function TXWriteAccArr(Params) { + var WorkStruct = {}; + var WorkFormat = global.DApps.Accounts.FORMAT_ACCOUNT_ROW; + global.ToLog("Write accounts: " + Params.StartNum + "-" + Params.Arr.length, 2); + for (var i = 0; i < Params.Arr.length; i++) { + var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct); + Data.Num = Params.StartNum + i; + global.DApps.Accounts._DBStateWrite(Data, MinimalValidBlock); + } +}; +global.TXWriteAccArr = TXWriteAccArr; + +function TXWriteSmartArr(Params) { + var WorkStruct = {}; + var WorkFormat = global.DApps.Smart.FORMAT_ROW; + global.ToLog("Write smarts: " + Params.StartNum + "-" + Params.Arr.length, 2); + for (var i = 0; i < Params.Arr.length; i++) { + var Data = global.BufLib.GetObjectFromBuffer(Params.Arr[i], WorkFormat, WorkStruct); + Data.Num = Params.StartNum + i; + global.DApps.Smart.DBSmart.Write(Data); + } +}; +global.TXWriteSmartArr = TXWriteSmartArr; + +function TXWriteAccHash() { + StopTxProcess = 0; + global.ToLog("Start TXWriteAccHash: " + MinimalValidBlock, 2); + for (var num = 0; true; num++) { + var Item = global.DApps.Smart.DBSmart.Read(num); + if (!Item) + break; + var Body = global.BufLib.GetBufferFromObject(Item, global.DApps.Smart.FORMAT_ROW, 20000, {}); + global.DApps.Smart.DBSmartWrite(Item); + } + global.DApps.Accounts.CalcMerkleTree(1); + var Block = { BlockNum: MinimalValidBlock, SumHash: [] }; + var MaxAccount = global.DApps.Accounts.GetMaxAccount(); + var DataHash = global.DApps.Accounts.CalcHash(Block, MaxAccount); + return DataHash; +}; +global.TXWriteAccHash = TXWriteAccHash; +global.EvalCode = function(Code) { + var Result; + try { + var ret = eval(Code); + Result = JSON.stringify(ret, "", 4); + } + catch (e) { + Result = "" + e; + } + return Result; +}; diff --git a/src/process/web-process.ts b/src/process/web-process.ts new file mode 100644 index 0000000..8b496c5 --- /dev/null +++ b/src/process/web-process.ts @@ -0,0 +1,864 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ +import * as crypto from 'crypto' +import * as http from 'http' +import * as net from 'net' +import * as url from 'url' +import * as fs from 'fs' +import * as querystring from 'querystring' + +global.PROCESS_NAME = "WEB"; +import '../core/constant' +global.MAX_STAT_PERIOD = 600; +global.DATA_PATH = global.GetNormalPathString(global.DATA_PATH); +global.CODE_PATH = global.GetNormalPathString(global.CODE_PATH); +import "../core/library" +import "../core/geo" +global.READ_ONLY_DB = 1; +global.MAX_STAT_PERIOD = 600; +var HostNodeList = []; +var AllNodeList = []; +var NodeBlockChain = []; +var LastAlive = Date.now(); +setTimeout(function() { + setInterval(CheckAlive, 1000); +}, 20000); +setInterval(function() { + process.send({ cmd: "Alive" }); +}, 1000); +process.send({ cmd: "online", message: "OK" }); +process.on('message', function(msg) { + let { + GlobalRunMap, + ADD_TO_STAT, + ToLogClient0, + ArrLogClient + } = global + LastAlive = Date.now(); + switch (msg.cmd) { + case "ALive": + break; + case "Exit": + Exit(); + break; + case "call": + var Err = 0; + var Ret; + try { + Ret = global[msg.Name](msg.Params); + } + catch (e) { + Err = 1; + Ret = "" + e; + } + if (msg.id) + process.send({ cmd: "retcall", id: msg.id, Err: Err, Params: Ret }); + break; + case "retcall": + var F = GlobalRunMap[msg.id]; + if (F) { + delete GlobalRunMap[msg.id]; + F(msg.Err, msg.Params); + } + break; + case "Stat": + ADD_TO_STAT(msg.Name, msg.Value); + break; + case "NodeList": + HostNodeList = msg.Value; + AllNodeList = msg.ValueAll; + break; + case "NodeBlockChain": + NodeBlockChain = msg.Value; + break; + case "DappEvent": + { + AddDappEventToGlobalMap(msg.Data); + break; + } + case "ToLogClient": + { + ToLogClient0(msg.Str, msg.StrKey, msg.bFinal); + break; + } + case "RetFindTX": + { + if (msg.WebID) { + var F = global.GlobalRunMap[msg.WebID]; + if (F) { + delete global.GlobalRunMap[msg.WebID]; + F(msg.Result, msg.ResultStr); + break; + } + } + ArrLogClient.push({ text: msg.ResultStr, key: msg.TX, final: msg.bFinal, }); + break; + } + } +}); +var RedirectServer; +var HostingServer; + +let { + ToLogWeb, + CHECK_STOP_CHILD_PROCESS, + ToError, + ToLog, + TO_ERROR_LOG, + PrepareStatEverySecond, + ToLogTrace +} = global + +function Exit() { + ToLogWeb("=Exit1="); + if (RedirectServer) + RedirectServer.close(); + if (HostingServer) + HostingServer.close(); + ToLogWeb("=Exit2="); + process.exit(0); +}; + +function CheckAlive() { + if (global.NOALIVE) + return; + var Delta = Date.now() - LastAlive; + if (Delta > CHECK_STOP_CHILD_PROCESS) { + Exit(); + return; + } +}; +process.on('uncaughtException', function(err) { + global.ToError(err.stack); + global.ToLog(err.stack); + TO_ERROR_LOG("HOSTING", 777, err); + global.ToLog("-----------------HOSTING EXIT------------------", 0); + process.exit(); +}); +process.on('error' as any, function(err: TeraError) { + global.ToError("HOSTING:\n" + err.stack); + global.ToLog(err.stack); +}); +if (!global.HTTP_HOSTING_PORT) { + ToLogTrace("global.HTTP_HOSTING_PORT=" + global.HTTP_HOSTING_PORT); + process.exit(); +} +var CServerDB = require("../core/db/block-db"); +var KeyPair = crypto.createECDH('secp256k1'); +KeyPair.setPrivateKey(Buffer.from([77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77])); +global.SERVER = new CServerDB(KeyPair, undefined, undefined, false, true); +global.HTTP_PORT_NUMBER = 0; +require("../core/html-server"); +require("../core/transaction-validator"); +global.STAT_MODE = 1; +setInterval(PrepareStatEverySecond, 1000); +var IndexName = "index.html"; +let { + GetDataPath, + CheckCreateDir, + LoadParams, + SaveParams, + ADD_TO_STAT +} = global +if (global.HTTPS_HOSTING_DOMAIN) { + var file_sert = global.GetDataPath("sertif.lst"); + CheckCreateDir(global.GetDataPath("tmp")); + var greenlock = require('greenlock').create({ + version: 'draft-12', server: 'https://acme-v02.api.letsencrypt.org/directory', configDir: global.GetDataPath('tmp'), + }); + var redir = require('redirect-https')(); + RedirectServer = require('http').createServer(greenlock.middleware(redir)); + RedirectServer.on('error', function(err) { + global.ToError('RedirectServer: ' + err.code); + }); + RedirectServer.listen(80); + var GetNewSert = 1; + if (fs.existsSync(file_sert)) { + var certs = LoadParams(file_sert, {}); + var Delta = certs.expiresAt - Date.now(); + if (Delta >= 10 * 24 * 3600 * 1000) { + global.ToLog("USE EXIST SERT. ExpiresAt: " + new Date(certs.expiresAt)); + GetNewSert = 0; + var tlsOptions = { key: certs.privkey, cert: certs.cert + '\r\n' + certs.chain }; + HostingServer = require('https').createServer(tlsOptions, MainHTTPFunction); + RunListenServer(); + } + } + if (GetNewSert) { + global.ToLog("Start get new SERT", 0); + var opts = { domains: [global.HTTPS_HOSTING_DOMAIN], email: 'progr76@gmail.com', agreeTos: true, communityMember: true, }; + greenlock.register(opts).then(function(certs) { + SaveParams(file_sert, certs); + var tlsOptions = { key: certs.privkey, cert: certs.cert + '\r\n' + certs.chain }; + HostingServer = require('https').createServer(tlsOptions, MainHTTPFunction); + RunListenServer(); + }, function(err) { + global.ToError(err); + }); + } +} +else { + HostingServer = http.createServer(MainHTTPFunction); + RunListenServer(); +} + +function MainHTTPFunction(request, response) { + if (!request.headers) + return; + if (!request.socket || !request.socket.remoteAddress) + return; + SetSafeResponce(response); + var DataURL = url.parse(request.url); + var Params = querystring.parse(DataURL.query); + var Path = querystring.unescape(DataURL.pathname); + ADD_TO_STAT("HTTP_ALL"); + var Type = request.method; + if (Type === "POST") { + let Response = response; + let postData = ""; + request.addListener("data", function(postDataChunk) { + if (postData.length <= 12000 && postDataChunk.length <= 12000) + postData += postDataChunk; + else { + var Str = "Error postDataChunk.length=" + postDataChunk.length; + global.ToLog(Str, 0); + Response.writeHead(405, { 'Content-Type': 'text/html' }); + Response.end(Str); + } + }); + request.addListener("end", function() { + var Data; + if (postData && postData.length) { + try { + Data = JSON.parse(postData); + } + catch (e) { + Response.writeHead(405, { 'Content-Type': 'text/html' }); + Response.end("Error data parsing"); + } + } + DoCommandNew(response, Type, Path, Data); + }); + } + else { + DoCommandNew(response, Type, Path, Params); + } +}; +var bWasRun = 0; +var TimeToRerun = 3000; + +function RunListenServer() { + let { + ToLogClient, + LISTEN_IP + } = global + HostingServer.on('error', function(err) { + if (err.code === 'EADDRINUSE') { + TimeToRerun = Math.floor(TimeToRerun * 1.1); + if (TimeToRerun > 1000000 * 1000) + return; + ToLogClient('Port ' + global.HTTP_HOSTING_PORT + ' in use, retrying...'); + if (HostingServer.Server) + HostingServer.Server.close(); + if (!bWasRun) + setTimeout(function() { + RunListenServer(); + }, TimeToRerun); + return; + } + global.ToError("H##6"); + global.ToError(err); + }); + ToLogClient("Prepare to run WEB-server on port: " + global.HTTP_HOSTING_PORT); + HostingServer.listen(global.HTTP_HOSTING_PORT, LISTEN_IP, function() { + if (!bWasRun) + ToLogClient("Run WEB-server on " + LISTEN_IP + ":" + global.HTTP_HOSTING_PORT); + bWasRun = 1; + }); +}; +var SiteFolder = global.GetNormalPathString("./SITE"); +if (!fs.existsSync(SiteFolder)) { + IndexName = "web-wallet.html"; +} +var LangPathMap = {}; +LangPathMap["ru"] = 1; +LangPathMap["cn"] = 1; +LangPathMap["de"] = 1; +LangPathMap["blog"] = 1; +LangPathMap["docs"] = 1; +LangPathMap["game"] = 1; +var WalletFileMap = {}; +WalletFileMap["coinlib.js"] = 1; +WalletFileMap["client.js"] = 1; +WalletFileMap["diagram.js"] = 1; +WalletFileMap["sha3.js"] = 1; +WalletFileMap["terahashlib.js"] = 1; +WalletFileMap["wallet-web.js"] = 1; +WalletFileMap["wallet-lib.js"] = 1; +WalletFileMap["crypto-client.js"] = 1; +WalletFileMap["dapp-inner.js"] = 1; +WalletFileMap["marked.js"] = 1; +WalletFileMap["highlight.js"] = 1; +WalletFileMap["highlight-js.js"] = 1; +WalletFileMap["highlight-html.js"] = 1; +WalletFileMap["codes.css"] = 1; +WalletFileMap["sign-lib-min.js"] = 1; +WalletFileMap["buttons.css"] = 1; +WalletFileMap["style.css"] = 1; +WalletFileMap["wallet.css"] = 1; +WalletFileMap["history.html"] = 1; +WalletFileMap["blockviewer.html"] = 1; +WalletFileMap["web-wallet.html"] = 1; +WalletFileMap["address_book.png"] = 1; +WalletFileMap["mobile-wallet.html"] = 1; +WalletFileMap["mobile-wallet.js"] = 1; +WalletFileMap["mobile-wallet.css"] = 1; +WalletFileMap["reload.svg"] = 1; +WalletFileMap["T.svg"] = 1; +WalletFileMap["B.svg"] = 1; +WalletFileMap["blank.svg"] = 1; +WalletFileMap["info.svg"] = 1; +WalletFileMap["info.svg"] = 1; +WalletFileMap["check.svg"] = 1; +WalletFileMap["right-arrow.svg"] = 1; +WalletFileMap["down-arrow.svg"] = 1; +WalletFileMap["glass.svg"] = 1; +WalletFileMap["dapp-edit.html"] = 1; +WalletFileMap["TeraLogo.svg"] = 1; +WalletFileMap["mobile-wallet.html"] = "web-wallet.html"; +global.WebApi2 = {}; +let HostingCaller: HostingCaller = {} +global.HostingCaller = HostingCaller; +function DoCommandNew(response, Type, Path, Params) { + if (Path.substring(0, 1) === "/") + Path = Path.substring(1); + var ArrPath = Path.split('/', 5); + var Caller = global.HostingCaller; + var Method = ArrPath[0]; + if (ArrPath[0] === "api") { + if (ArrPath[1] === "v2") { + if (!global.USE_HARD_API_V2) { + response.writeHead(200, { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': "*" }); + response.end(JSON.stringify({ result: 0, text: "You must set const USE_HARD_API_V2:1" })); + return; + } + Caller = WebApi2; + } + Method = ArrPath[2]; + } + ADD_TO_STAT("HTTP:" + Method); + var F = Caller[Method]; + if (F) { + response.writeHead(200, { 'Content-Type': 'text/plain', 'Access-Control-Allow-Origin': "*" }); + var Ret; + try { + Ret = F(Params, response, ArrPath); + } + catch (e) { + Ret = { result: 0, text: e.message, text2: e.stack }; + } + if (Ret === null) + return; + try { + var Str; + if (typeof Ret === "object") + Str = JSON.stringify(Ret); + else + Str = Ret; + response.end(Str); + } + catch (e) { + global.ToLog("ERR PATH:" + Path); + global.ToLog(e); + response.end(); + } + return; + } + Method = Method.toLowerCase(); + if (Method === "dapp" && ArrPath.length === 2) + Method = "DappTemplateFile"; + switch (Method) { + case "index.html": + response.writeHead(301, { "Location": '/' }); + return response.end(); + case "file": + SendBlockFile(response, ArrPath[1], ArrPath[2]); + break; + case "DappTemplateFile": + DappTemplateFile(response, ArrPath[1]); + break; + case "smart": + DappSmartCodeFile(response, ArrPath[1]); + break; + case "client": + DappClientCodeFile(response, ArrPath[1]); + default: + { + var Name = ArrPath[ArrPath.length - 1]; + if (typeof Name !== "string") + Name = "ErrorPath"; + else + if (Name.indexOf("..") >= 0 || Name.indexOf("\\") >= 0 || Name.indexOf("/") >= 0) + Name = "ErrorFilePath"; + if (Name === "" || LangPathMap[Name]) + Name = IndexName; + if (Name.indexOf(".") < 0) + Name += ".html"; + var PrefixPath; + if (Method === "files") { + PrefixPath = "../FILES"; + Name = ""; + for (var i = 1; i < ArrPath.length; i++) + if (ArrPath[i].indexOf("..") === - 1 && ArrPath[i].indexOf("\\") === - 1) + Name += "/" + ArrPath[i]; + Name = PrefixPath + Name; + global.SendWebFile(response, Name, Path); + return; + } + else + if (LangPathMap[Method]) { + PrefixPath = "./SITE/" + Method; + } + else { + var Name2 = WalletFileMap[Name]; + if (!Name2) + PrefixPath = "./SITE"; + else { + PrefixPath = "./HTML"; + if (typeof Name2 === "string") + Name = Name2; + } + } + var type = Path.substr(Path.length - 3, 3); + switch (type) { + case ".js": + Name = PrefixPath + "/JS/" + Name; + break; + case "css": + Name = PrefixPath + "/CSS/" + Name; + break; + case "wav": + case "mp3": + Name = PrefixPath + "/SOUND/" + Name; + break; + case "svg": + case "png": + case "gif": + case "jpg": + case "ico": + Name = PrefixPath + "/PIC/" + Name; + break; + case "pdf": + case "zip": + case "exe": + case "msi": + Name = PrefixPath + "/FILES/" + Name; + break; + default: + Name = PrefixPath + "/" + Name; + break; + } + SendWebFile(response, Name, "", 1); + break; + } + } +}; +HostingCaller.GetCurrentInfo = function(Params) { + var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB(); + var Ret: any = { + result: 1, VersionNum: global.UPDATE_CODE_VERSION_NUM, NETWORK: global.NETWORK, MaxNumBlockDB: MaxNumBlockDB, CurBlockNum: global.GetCurrentBlockNumByTime(), + MaxAccID: global.DApps.Accounts.GetMaxAccount(), MaxDappsID: global.DApps.Smart.GetMaxNum(), CurTime: Date.now(), DELTA_CURRENT_TIME: global.DELTA_CURRENT_TIME, + MIN_POWER_POW_TR: global.MIN_POWER_POW_TR, FIRST_TIME_BLOCK: global.FIRST_TIME_BLOCK, CONSENSUS_PERIOD_TIME: global.CONSENSUS_PERIOD_TIME, NEW_SIGN_TIME: global.NEW_SIGN_TIME, + PRICE_DAO: global.PRICE_DAO(MaxNumBlockDB), + }; + if (typeof Params === "object" && Params.Diagram == 1) { + var arrNames = ["MAX:ALL_NODES", "MAX:HASH_RATE_B"]; + Ret.arr = global.GET_STATDIAGRAMS(arrNames); + } + if (typeof Params === "object" && Params.BlockChain == 1) { + Ret.BlockChain = NodeBlockChain; + } + if (typeof Params === "object" && Params.ArrLog == 1) { + var ArrLog = []; + for (var i = 0; i < global.ArrLogClient.length; i++) { + var Item = global.ArrLogClient[i]; + if (!Item.final) + continue; + ArrLog.push(Item); + } + Ret.ArrLog = ArrLog; + } + return Ret; +}; +var MaxCountViewRows = global.HTTP_MAX_COUNT_ROWS; +HostingCaller.GetAccountList = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Accounts.GetRowsAccounts(ParseNum(Params.StartNum), ParseNum(Params.CountNum)); + return { result: 1, arr: arr }; +}; +HostingCaller.GetAccount = function(id) { + id = ParseNum(id); + var arr = global.DApps.Accounts.GetRowsAccounts(id, 1); + return { Item: arr[0], result: 1 }; +}; +HostingCaller.GetBlockList = function(Params, response) { + if (typeof Params !== "object") + return { result: 0 }; + Params.StartNum = ParseNum(Params.StartNum); + Params.CountNum = ParseNum(Params.CountNum); + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + return HTTPCaller.GetBlockList(Params, response); +}; +HostingCaller.GetTransactionList = function(Params, response) { + Params.Param3 = Params.BlockNum; + return HostingCaller.GetTransactionAll(Params, response); +}; +HostingCaller.GetTransactionAll = function(Params, response) { + if (typeof Params !== "object") + return { result: 0 }; + Params.Param3 = ParseNum(Params.Param3); + Params.StartNum = ParseNum(Params.StartNum); + Params.CountNum = ParseNum(Params.CountNum); + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + return HTTPCaller.GetTransactionAll(Params, response); +}; +HostingCaller.GetDappList = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Smart.GetRows(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, Params.Filter, 1); + return { result: 1, arr: arr }; +}; +HostingCaller.GetNodeList = function(Params) { + var arr = []; + var List; + if (typeof Params === "object" && Params.All) + List = AllNodeList; + else + List = HostNodeList; + var MaxNodes = 20; + var len = List.length; + var UseRandom = 0; + if (len > MaxNodes) { + UseRandom = 1; + len = MaxNodes; + } + var Geo = 0; + if (typeof Params === "object" && Params.Geo) + Geo = 1; + var mapWasAdd = {}; + for (var i = 0; i < len; i++) { + var Item; + if (UseRandom) { + var num = global.random(List.length); + Item = List[num]; + if (mapWasAdd[Item.ip]) { + continue; + } + mapWasAdd[Item.ip] = 1; + } + else { + Item = List[i]; + } + var Value: any = { ip: Item.ip, port: Item.portweb, }; + if (Geo) { + if (!Item.Geo) + global.SetGeoLocation(Item); + Value.latitude = Item.latitude; + Value.longitude = Item.longitude; + Value.name = Item.name; + Value.port = Item.port; + } + arr.push(Value); + } + var Result = { result: 1, arr: arr, VersionNum: global.UPDATE_CODE_VERSION_NUM, NETWORK: global.NETWORK, }; + return Result; +}; +var AccountKeyMap = {}; +var LastMaxNum = 0; +HostingCaller.GetAccountListByKey = function(Params, ppp, bRet) { + if (typeof Params !== "object" || !Params.Key) + return { result: 0, arr: [] }; + var Accounts = global.DApps.Accounts; + for (var num = LastMaxNum; true; num++) { + if (Accounts.IsHole(num)) + continue; + var Data = Accounts.ReadState(num); + if (!Data) + break; + var StrKey = global.GetHexFromArr(Data.PubKey); + Data.Next = AccountKeyMap[StrKey]; + AccountKeyMap[StrKey] = Data; + } + LastMaxNum = num; + var arr = []; + var Item = AccountKeyMap[Params.Key]; + while (Item) { + var Data = Accounts.ReadState(Item.Num); + if (!Data) + continue; + if (!Data.PubKeyStr) + Data.PubKeyStr = global.GetHexFromArr(Data.PubKey); + if (Data.Currency) + Data.CurrencyObj = global.DApps.Smart.ReadSimple(Data.Currency); + if (Data.Value.Smart) { + Data.SmartObj = global.DApps.Smart.ReadSimple(Data.Value.Smart); + try { + Data.SmartState = global.BufLib.GetObjectFromBuffer(Data.Value.Data, Data.SmartObj.StateFormat, {}); + if (typeof Data.SmartState === "object") + Data.SmartState.Num = Item.Num; + } + catch (e) { + Data.SmartState = {}; + } + } + arr.unshift(Data); + Item = Item.Next; + if (arr.length >= global.HTTP_MAX_COUNT_ROWS) + break; + } + var Ret = { result: 1, arr: arr }; + if (bRet) + return Ret; + var Context = GetUserContext(Params); + var StrInfo = JSON.stringify(Ret); + if (!Params.AllData && Context.PrevAccountList === StrInfo) { + return { result: 0, cache: 1 }; + } + Context.PrevAccountList = StrInfo; + Context.NumAccountList++; + return StrInfo; +}; +var CategoryMap = {}; +var CategoryArr = []; +var CategoryDappMaxNumWas = 0; +HostingCaller.GetDappCategory = function(Params, response) { + CheckDappCategoryMap(); + return { result: 1, arr: CategoryArr }; +}; + +function CheckDappCategoryMap() { + var MaxNumNow = global.DApps.Smart.GetMaxNum(); + if (MaxNumNow !== CategoryDappMaxNumWas) { + for (var Num = CategoryDappMaxNumWas; Num <= MaxNumNow; Num++) { + var Item = global.DApps.Smart.ReadSimple(Num); + for (var n = 1; n <= 3; n++) { + var Name = "Category" + n; + var Value = Item[Name]; + if (Value) { + var DappMap = CategoryMap[Value]; + if (!DappMap) { + DappMap = {}; + CategoryMap[Value] = DappMap; + CategoryArr.push(Value); + } + DappMap[Num] = 1; + } + } + } + CategoryDappMaxNumWas = MaxNumNow; + } +}; +HostingCaller.SendTransactionHex = function(Params, response) { + if (typeof Params !== "object" || !Params.Hex) + return { result: 0, text: "object requre" }; + process.RunRPC("AddTransactionFromWeb", { HexValue: Params.Hex }, function(Err, text) { + var Result = { result: !Err, text: text }; + var Str = JSON.stringify(Result); + response.end(Str); + }); + return null; +}; +HostingCaller.DappSmartHTMLFile = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + return HTTPCaller.DappSmartHTMLFile(Params); +}; +HostingCaller.DappBlockFile = function(Params, responce) { + if (typeof Params !== "object") + return { result: 0 }; + return HTTPCaller.DappBlockFile(Params, responce); +}; +HostingCaller.DappInfo = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + var SmartNum = ParseNum(Params.Smart); + process.send({ cmd: "SetSmartEvent", Smart: SmartNum }); + var Context = GetUserContext(Params); + var Ret = HTTPCaller.DappInfo(Params, undefined, 1); + Ret.PubKey = undefined; + var StrInfo = JSON.stringify(Ret); + if (!Params.AllData && Context.PrevDappInfo === StrInfo) { + return { result: 0, cache: 1 }; + } + Context.PrevDappInfo = StrInfo; + Context.NumDappInfo++; + Context.LastTime = Date.now(); + Ret.NumDappInfo = Context.NumDappInfo; + Ret.CurTime = Date.now(); + Ret.CurBlockNum = global.GetCurrentBlockNumByTime(); + Ret.BlockNumDB = global.SERVER.BlockNumDB; + Ret.MaxAccID = global.DApps.Accounts.GetMaxAccount(); + Ret.MaxDappsID = global.DApps.Smart.GetMaxNum(); + return Ret; +}; +HostingCaller.DappWalletList = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + var Ret = HostingCaller.GetAccountListByKey(Params, undefined, 1); + var Smart = ParseNum(Params.Smart); + var arr = []; + for (var i = 0; i < Ret.arr.length; i++) { + if (Params.AllAccounts || Ret.arr[i].Value.Smart === Smart) { + arr.push(Ret.arr[i]); + } + } + Ret.arr = arr; + return Ret; +}; +HTTPCaller.DappWalletList = HostingCaller.DappWalletList; +HostingCaller.DappAccountList = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Accounts.GetRowsAccounts(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, 1); + return { arr: arr, result: 1 }; +}; +HostingCaller.DappSmartList = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + var arr = global.DApps.Smart.GetRows(ParseNum(Params.StartNum), ParseNum(Params.CountNum), undefined, undefined, Params.GetAllData, + Params.TokenGenerate); + return { arr: arr, result: 1 }; +}; +HostingCaller.DappBlockList = function(Params, response) { + if (typeof Params !== "object") + return { result: 0 }; + Params.StartNum = ParseNum(Params.StartNum); + Params.CountNum = ParseNum(Params.CountNum); + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + return HTTPCaller.DappBlockList(Params, response); +}; +HostingCaller.DappTransactionList = function(Params, response) { + if (typeof Params !== "object") + return { result: 0 }; + Params.BlockNum = ParseNum(Params.BlockNum); + Params.StartNum = ParseNum(Params.StartNum); + Params.CountNum = ParseNum(Params.CountNum); + if (Params.CountNum > MaxCountViewRows) + Params.CountNum = MaxCountViewRows; + if (!Params.CountNum) + Params.CountNum = 1; + return HTTPCaller.DappTransactionList(Params, response); +}; +HostingCaller.DappStaticCall = function(Params, response) { + if (typeof Params !== "object") + return { result: 0 }; + return HTTPCaller.DappStaticCall(Params, response); +}; +HostingCaller.GetHistoryTransactions = function(Params) { + if (typeof Params !== "object") + return { result: 0 }; + return HTTPCaller.GetHistoryTransactions(Params); +}; +HostingCaller.GetSupply = function(Params) { + var Data = global.DApps.Accounts.ReadState(0); + if (!Data) + return ""; + else { + return "" + (global.TOTAL_SUPPLY_TERA - Data.Value.SumCOIN); + } +}; +HostingCaller.GetTotalSupply = function(Params) { + return "" + global.TOTAL_SUPPLY_TERA; +}; +global.GlobalRunID = 0; +global.GlobalRunMap = {}; +process.RunRPC = function(Name, Params, F) { + if (F) { + global.GlobalRunID++; + try { + process.send({ cmd: "call", id: global.GlobalRunID, Name: Name, Params: Params }); + global.GlobalRunMap[global.GlobalRunID] = F; + } + catch (e) { + } + } + else { + process.send({ cmd: "call", id: 0, Name: Name, Params: Params }); + } +}; +setInterval(function() { + if (global.SERVER) + global.SERVER.Close(); + global.DApps.Accounts.Close(); + global.DApps.Smart.DBSmart.Close(); +}, 500); +setInterval(function() { + var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB(); + var HASHARATE_BLOCK_LENGTH = 10; + var arr = global.SERVER.GetStatBlockchain("POWER_BLOCKCHAIN", HASHARATE_BLOCK_LENGTH); + if (arr.length) { + var SumPow = 0; + var Count = 0; + var Value = 0; + for (var i = arr.length - HASHARATE_BLOCK_LENGTH; i < arr.length; i++) + if (arr[i]) { + Value = arr[i]; + SumPow += Value; + Count++; + } + if (!Count) + Count = 1; + var AvgPow = SumPow / Count; + ADD_TO_STAT("MAX:HASH_RATE_B", AvgPow); + } + var Count = COUNT_BLOCK_PROOF + 16 - 1; + if (MaxNumBlockDB > Count) { + var StartNum = MaxNumBlockDB - Count; + NodeBlockChain = global.SERVER.BlockChainToBuf(StartNum, StartNum, MaxNumBlockDB); + } +}, 700); +require("./api-exchange.js"); +try { + require("../SITE/JS/web-addon.js"); +} +catch (e) { +} +global.LoadBlockFromNetwork = function(Params, F) { + global.ToLog("RUN: LoadBlockFromNetwork:" + Params.BlockNum, 2); + process.RunRPC("LoadBlockFromNetwork", { BlockNum: Params.BlockNum, F: 1 }, function(Err, Block) { + global.ToLog("RETURN: LoadBlockFromNetwork: " + Params.BlockNum, 2); + F(Err, Block); + }); +}; diff --git a/src/run-node.bat b/src/run-node.bat new file mode 100644 index 0000000..236f80a --- /dev/null +++ b/src/run-node.bat @@ -0,0 +1,5 @@ + +:loop +node.exe run-node.js +goto :loop + diff --git a/src/run-node.ts b/src/run-node.ts new file mode 100644 index 0000000..5bd1f28 --- /dev/null +++ b/src/run-node.ts @@ -0,0 +1,8 @@ +if (!global.DATA_PATH || global.DATA_PATH === "") + global.DATA_PATH = "../DATA"; +global.CODE_PATH = process.cwd(); +global.HTTP_PORT_NUMBER = 8080; +if (global.LOCAL_RUN === undefined) + global.LOCAL_RUN = 0; + +require('./process/main-process'); diff --git a/src/run-nw.ts b/src/run-nw.ts new file mode 100644 index 0000000..59327b2 --- /dev/null +++ b/src/run-nw.ts @@ -0,0 +1,70 @@ + + +global.HTTP_PORT_NUMBER = Math.trunc(10000 * Math.random()) + 50000; +if (!global.DATA_PATH || global.DATA_PATH === "") + global.DATA_PATH = "../DATA"; +global.CODE_PATH = process.cwd(); + +global.NWMODE = 1; +global.NWVERSION = "0.37.4" + +global.START_IP = ""; +global.START_PORT_NUMBER = 30000; +global.CREATE_ON_START = 0; + +global.LOCAL_RUN = 0; + +require('./core/library.js'); +if (!global.HTTP_PORT_NUMBER)//try 2 + global.HTTP_PORT_NUMBER = Math.trunc(10000 * Math.random()) + 50000; + +require('./process/main-process'); + + +// global.NO_HISTORY_MODE=1;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 +// global.NO_CHECK_BLOCKNUM_ONSTART=1; + +setTimeout(function() { + var Path = ""; + if (global.HTTP_SERVER_START_OK) { + Path = 'http://localhost:' + global.HTTP_PORT_NUMBER; + } + else { + global.ToLog("ERR HTTP-SERVER NOT STARTING"); + } + nw.Window.open(Path + '/HTML/wallet.html', + { + width: 840, + height: 1000, + icon: "../HTML/PIC/wallet.png", + }, function(win) { + //win.showDevTools(); + + + + // Create a tray icon + let Visible: any = 1; + var tray = new nw.Tray({ title: 'TERA', icon: '/HTML/PIC/wallet16.png' }); + tray.on('click', function() { + Visible = !Visible; + if (Visible) + win.show(); + else + win.hide(); + }) + + // Give it a menu + var menu = new nw.Menu(); + menu.append(new nw.MenuItem({ label: 'Hide', click: function() { win.hide(); Visible = 0; } })); + menu.append(new nw.MenuItem({ label: 'Show', click: function() { win.show(); Visible = 1; } })); + menu.append(new nw.MenuItem({ label: 'Exit', click: function() { process.exit(0) } })); + tray.menu = menu; + + + // win.on('navigation',function (frame, url, policy) + // { + // console.log("url:"+url); + // }); + }); +}, 500); + diff --git a/src/run-test.ts b/src/run-test.ts new file mode 100644 index 0000000..1705fd4 --- /dev/null +++ b/src/run-test.ts @@ -0,0 +1,13 @@ +const fs = require('fs'); +const os = require('os'); +if(!global.DATA_PATH || global.DATA_PATH==="") + global.DATA_PATH="../DATA-TEST"; +global.CODE_PATH=process.cwd(); +global.HTTP_PORT_NUMBER = 8080; +global.START_PORT_NUMBER = 40000; +if(global.LOCAL_RUN===undefined) + global.LOCAL_RUN=0; + +global.TEST_NETWORK = 1; + +require('./process/main-process'); diff --git a/src/set-test.ts b/src/set-test.ts new file mode 100644 index 0000000..64b6a3f --- /dev/null +++ b/src/set-test.ts @@ -0,0 +1,14 @@ + +global.TEST_NETWORK = 1; +global.DATA_PATH = "../DATA-TEST"; +global.CODE_PATH = process.cwd(); + +require("./core/constant"); +require("./core/library"); + +global.CheckCreateDir(global.DATA_PATH); + +InitParamsArg(); +global.SAVE_CONST(true); + +process.exit(); diff --git a/src/set.ts b/src/set.ts new file mode 100644 index 0000000..3c27cfe --- /dev/null +++ b/src/set.ts @@ -0,0 +1,13 @@ + +global.DATA_PATH = "../DATA"; +global.CODE_PATH = process.cwd(); + +require("./core/constant"); +require("./core/library"); + +global.CheckCreateDir(global.DATA_PATH); + +InitParamsArg(); +global.SAVE_CONST(true); + +process.exit(); diff --git a/src/system/accounts.ts b/src/system/accounts.ts new file mode 100644 index 0000000..85615b5 --- /dev/null +++ b/src/system/accounts.ts @@ -0,0 +1,1426 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as fs from 'fs' +const DBRow = require("../core/db/db-row"); +require('../core/rest_tables.js'); +const MAX_SUM_TER = 1e9; +const MAX_SUM_CENT = 1e9; +const DBLib = require("../core/db/db"); +global.HistoryDB = new DBLib(); +const FILE_NAME_HISTORY = "history-body"; +var WorkStructHistory = {}; +const BLOCK_CREATE_INTERVAL = 10; +global.TYPE_TRANSACTION_CREATE = 100; +const TYPE_DEPRECATED_TRANSFER1 = 105; +const TYPE_DEPRECATED_TRANSFER2 = 110; +const TYPE_TRANSACTION_TRANSFER = 111; +global.TYPE_TRANSACTION_ACC_HASH = 119; +global.FORMAT_CREATE = "{\ + Type:byte,\ + Currency:uint,\ + PubKey:arr33,\ + Name:str40,\ + Adviser:uint,\ + Smart:uint32,\ + Reserve:arr3,\ + }"; +global.FORMAT_MONEY_TRANSFER = '{\ + Type:byte,\ + Currency:uint,\ + FromID:uint,\ + To:[{ID:uint,SumCOIN:uint,SumCENT:uint32}],\ + Description:str,\ + OperationID:uint,\ + Sign:arr64,\ + }'; +const WorkStructTransfer = {}; +global.FORMAT_MONEY_TRANSFER_BODY = global.FORMAT_MONEY_TRANSFER.replace("Sign:arr64,", ""); +global.FORMAT_MONEY_TRANSFER2 = "{\ + Type:byte,\ + Version:byte,\ + Currency:uint,\ + FromID:uint,\ + To:[{ID:uint,SumCOIN:uint,SumCENT:uint32}],\ + Description:str,\ + OperationID:uint,\ + Sign:arr64,\ + }"; +const WorkStructTransfer2 = {}; +global.FORMAT_MONEY_TRANSFER_BODY2 = global.FORMAT_MONEY_TRANSFER2.replace("Sign:arr64,", ""); +global.FORMAT_MONEY_TRANSFER3 = "{\ + Type:byte,\ + Version:byte,\ + Reserve:uint,\ + FromID:uint,\ + To:[{PubKey:tr,ID:uint,SumCOIN:uint,SumCENT:uint32}],\ + Description:str,\ + OperationID:uint,\ + Body:tr,\ + Sign:arr64,\ + }"; +const WorkStructTransfer3 = {}; +global.FORMAT_MONEY_TRANSFER_BODY3 = global.FORMAT_MONEY_TRANSFER3.replace("Sign:arr64,", ""); +global.FORMAT_ACCOUNT_HASH = "{\ + Type:byte,\ + BlockNum:uint,\ + AccHash:buffer32,\ + }"; +global.FORMAT_ACCOUNT_HASH3 = "{\ + Type:byte,\ + BlockNum:uint,\ + AccHash:buffer32,\ + AccountMax:uint,\ + SmartHash:buffer32,\ + SmartCount:uint,\ + }"; +let { + ToLog, + shaarr, + UpdateMerklTree, + ToError, + SERVER +} = global + +class MerkleDBRow extends DBRow { + private MerkleTree + private MerkleArr + private MerkleCalc + constructor(FileName, DataSize, Format, bReadOnly) { + super(FileName, DataSize, Format, bReadOnly) + this.InitMerkleTree() + } + InitMerkleTree() { + this.MerkleTree = undefined + this.MerkleArr = [] + this.MerkleCalc = {} + } + CalcMerkleTree(bForceUpdate) { + if (!this.MerkleTree || bForceUpdate) { + this.MerkleCalc = {} + this.MerkleTree = { LevelsHash: [this.MerkleArr], RecalcCount: 0 } + var GetMaxNum = this.GetMaxNum(); + for (var num = 0; num <= GetMaxNum; num++) { + var Buf = this.Read(num, 1); + if (!Buf) { + if (global.WATCHDOG_DEV) + global.ToLog("CalcMerkleTree: Break account reading on num: " + num) + break; + } + this.MerkleArr[num] = global.shaarr(Buf) + this.MerkleCalc[num] = 1 + } + } + this.MerkleTree.RecalcCount = 0 + UpdateMerklTree(this.MerkleTree, this.MerkleCalc, 0) + this.MerkleCalc = {} + return this.MerkleTree.Root; + } + Write(Data) { + var RetBuf: any = {}; + var bRes = DBRow.prototype.Write.call(this, Data, RetBuf); + if (bRes) { + var Hash = global.shaarr(RetBuf.Buf); + this.MerkleArr[Data.Num] = Hash + this.MerkleCalc[Data.Num] = 1 + } + return bRes; + } + Truncate(LastNum) { + DBRow.prototype.Truncate.call(this, LastNum) + if (this.MerkleArr.length !== LastNum + 1) { + this.MerkleArr.length = LastNum + 1 + this.MerkleCalc[LastNum] = 1 + } + } +}; +class AccountApp extends require("./dapp") +{ + private CreateTrCount + private FORMAT_ACCOUNT_ROW + private SIZE_ACCOUNT_ROW + private DBState + private FORMAT_ACCOUNT_ROW_REST + private SIZE_ACCOUNT_ROW_REST + private DBRest + private DBAct + private DBActPrev + private FORMAT_STATE_HISTORY + private DBStateHistory + private HistoryFormatArr + private DBStateTX + private DBAccountsHash + private WasCheckRestDB + private ResultTx + constructor() { + super() + var bReadOnly = (global.PROCESS_NAME !== "TX"); + this.CreateTrCount = 0 + this.FORMAT_ACCOUNT_ROW = "{\ + Currency:uint,\ + PubKey:arr33,\ + Name:str40,\ + Value:{SumCOIN:uint,SumCENT:uint32, OperationID:uint,Smart:uint32,Data:arr80},\ + BlockNumCreate:uint,\ + Adviser:uint,\ + Reserve:arr9,\ + }" + this.SIZE_ACCOUNT_ROW = 6 + 33 + 40 + (6 + 4 + 6 + 84) + 6 + 6 + 9 + this.DBState = new MerkleDBRow("accounts-state", this.SIZE_ACCOUNT_ROW, this.FORMAT_ACCOUNT_ROW, bReadOnly) + this.FORMAT_ACCOUNT_ROW_REST = "{\ + Arr:[{\ + BlockNum:uint,\ + Value:{SumCOIN:uint,SumCENT:uint32, OperationID:uint,Smart:uint32,Data:arr80,Reserv:arr96},\ + }],\ + Reserv0:arr10,\ + }" + this.SIZE_ACCOUNT_ROW_REST = 1024 + this.DBRest = new DBRow("accounts-rest", this.SIZE_ACCOUNT_ROW_REST, this.FORMAT_ACCOUNT_ROW_REST, bReadOnly) + this.DBAct = new DBRow("accounts-act", 6 + 6 + (6 + 4 + 6 + 6 + 84) + 1 + 11, "{ID:uint, BlockNum:uint,PrevValue:{SumCOIN:uint,SumCENT:uint32, NextPos:uint, OperationID:uint,Smart:uint32,Data:arr80}, Mode:byte, TrNum:uint16, Reserve: arr9}", + bReadOnly) + this.DBActPrev = new DBRow("accounts-act-prev", this.DBAct.DataSize, this.DBAct.Format, bReadOnly) + this.FORMAT_STATE_HISTORY = "{NextPos:uint,Reserv:arr2}" + this.DBStateHistory = new DBRow("history-state", 8, this.FORMAT_STATE_HISTORY, bReadOnly) + global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, !bReadOnly) + this.HistoryFormatArr = ["{Type:byte, BlockNum:uint32,TrNum:uint16, NextPos:uint}", "{Type:byte, BlockNum:uint32,TrNum:uint16, NextPos:uint, Direct:str1,CorrID:uint, SumCOIN:uint,SumCENT:uint32}"] + this.DBStateTX = new DBRow("accounts-tx", 6 + 6 + 88, "{BlockNum:uint, BlockNumMin:uint, Reserve: arr88}", bReadOnly) + if (global.READ_ONLY_DB) + return; + this.DBAccountsHash = new DBRow("accounts-hash3", 6 + 32 + 32 + 32 + 6 + 6 + 14, "{BlockNum:uint, AccHash:hash, SumHash:hash, SmartHash:hash, AccountMax:uint, SmartCount:uint, Reserve: arr14}", + bReadOnly) + if (global.START_SERVER) + return; + if (!bReadOnly) + this.Start() + setInterval(this.ControlActSize.bind(this), 60 * 1000) + } + Start(bClean?) { + if (global.LOCAL_RUN) + bClean = 1 + if (!bClean && this.DBState.GetMaxNum() + 1 >= global.global.BLOCK_PROCESSING_LENGTH2) + return; + this.DBState.MerkleTree = undefined + this.DBState.Truncate(- 1) + this.DBStateHistory.Truncate(- 1) + this.DBAct.Truncate(- 1) + this.DBActPrev.Truncate(- 1) + this.DBAccountsHash.Truncate(- 1) + this.DBStateTX.Truncate(- 1) + this.DBRest.Truncate(- 1) + this._DBStateWrite({ Num: 0, PubKey: [], Value: { BlockNum: 1, SumCOIN: 0.95 * global.TOTAL_SUPPLY_TERA }, Name: "System account" }, 1) + for (var i = 1; i < 8; i++) + this._DBStateWrite({ Num: i, PubKey: [], Value: { BlockNum: 1 }, Name: "" }) + this._DBStateWrite({ Num: 8, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[0]), Value: { BlockNum: 1, SumCOIN: 0.05 * global.TOTAL_SUPPLY_TERA }, Name: "Founder account" }) + this._DBStateWrite({ Num: 9, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[1]), Value: { BlockNum: 1, SumCOIN: 0 }, Name: "Developer account" }) + for (var i = 10; i < global.BLOCK_PROCESSING_LENGTH2; i++) + this._DBStateWrite({ Num: i, PubKey: global.GetArrFromHex(global.ARR_PUB_KEY[i - 8]), Value: { BlockNum: 1 }, Name: "" }) + this.DBStateTX.Write({ Num: 0, BlockNum: 0 }) + this.CalcMerkleTree(1) + var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 1); + fs.ftruncateSync(FileItem.fd, 0) + global.ToLog("MAX_NUM:" + this.DBState.GetMaxNum()) + } + Close() { + this.DBState.Close() + this.DBActPrev.Close() + this.DBAct.Close() + if (this.DBAccountsHash) + this.DBAccountsHash.Close() + if (this.DBStateTX) + this.DBStateTX.Close() + this.DBRest.Close() + if (this.DBStateHistory) + this.DBStateHistory.Close() + } + ClearDataBase() { + this.Start(1) + } + CheckRestDB() { + if (!global.SERVER) + return; + if (this.WasCheckRestDB) + return; + this.WasCheckRestDB = 1 + var MaxNumBlock = global.SERVER.GetMaxNumBlockDB(); + if (this.DBState.GetMaxNum() >= 0 && this.DBRest.GetMaxNum() < 0 && MaxNumBlock > 0) { + this.FillRestDB(MaxNumBlock) + } + } + FillRestDB(BlockNum) { + global.ToLog("******************************START FillRestDB") + var Max = this.DBState.GetMaxNum(); + for (var Num = 0; Num <= Max; Num++) { + var Data = this.DBState.Read(Num); + var RestData = this.ReadRest(Num); + if (Num % 10000 === 0) + global.ToLog("Fill Rest DB : " + Num) + RestData.Arr[0] = { BlockNum: BlockNum, Value: Data.Value } + this.DBRest.Write(RestData) + } + global.ToLog("******************************FINISH FillRestDB") + } + _DBStateWrite(Data?, BlockNum?) { + this.CheckRestDB() + this.DBState.Write(Data) + if (Data.Num === undefined) + throw "Error undefined Num DBRest !!"; + var RestData = this.ReadRest(Data.Num); + DoRest(RestData, Data, BlockNum) + this.DBRest.Write(RestData) + } + _DBStateTruncate(Num) { + this.DBState.Truncate(Num) + this.DBRest.Truncate(Num) + } + ReadRest(Num) { + var COUNT_STATE = 5; + var RestData = this.DBRest.Read(Num); + if (!RestData || RestData.Arr.length !== COUNT_STATE) { + RestData = { Num: Num, Arr: [] } + for (var i = 0; i < COUNT_STATE; i++) + RestData.Arr[i] = { BlockNum: 0, Value: {} } + } + if (RestData.Arr.length !== COUNT_STATE) + throw "Error RestData.Arr.length = (" + RestData.Arr.length + ")"; + return RestData; + } + ControlActSize() { + var MaxNum = this.DBAct.GetMaxNum(); + if (MaxNum >= global.TRANSACTION_PROOF_COUNT * 2) { + global.ToLog("Rename act files") + this.DBActPrev.CloseDBFile(this.DBActPrev.FileName) + this.DBAct.CloseDBFile(this.DBAct.FileName) + if (fs.existsSync(this.DBActPrev.FileNameFull)) { + var FileNameFull2 = this.DBActPrev.FileNameFull + "_del"; + try { + fs.renameSync(this.DBActPrev.FileNameFull, FileNameFull2) + } + catch (e) { + global.ToLog("Can-t rename for delete act-file: " + FileNameFull2) + return; + } + fs.unlinkSync(FileNameFull2) + } + try { + fs.renameSync(this.DBAct.FileNameFull, this.DBActPrev.FileNameFull) + } + catch (e) { + global.ToLog("Can-t rename act-file!") + return; + } + } + } + GetSenderNum(BlockNum, Body) { + var Type = Body[0]; + if (Type && Body.length > 90) { + switch (Type) { + case global.TYPE_TRANSACTION_CREATE: + { + if (BlockNum % BLOCK_CREATE_INTERVAL !== 0) + return 0; + var Num = BlockNum; + return Num; + } + case TYPE_TRANSACTION_TRANSFER: + var Num = ReadUintFromArr(Body, 1 + 1 + 6); + return Num; + } + } + return 0; + } + OnDeleteBlock(Block) { + if (Block.BlockNum < 1) + return; + this.DeleteAct(Block.BlockNum) + } + OnWriteBlockStart(Block) { + this.CreateTrCount = 0 + if (Block.BlockNum < 1) + return; + this.OnDeleteBlock(Block) + this.BeginBlock() + } + OnWriteBlockFinish(Block) { + try { + this.BeginTransaction() + this.DoCoinBaseTR(Block) + this.CommitTransaction(Block.BlockNum, 0xFFFF) + } + catch (e) { + this.RollBackTransaction() + global.ToError("DoCoinBaseTR: " + e) + } + this.CommitBlock(Block) + } + OnWriteTransaction(Block, Body, BlockNum, TrNum, ContextFrom) { + var Result; + try { + Result = this.OnWriteTransactionTR(Block, Body, BlockNum, TrNum, ContextFrom) + } + catch (e) { + Result = "" + e + } + if (Result !== true) { + this.RollBackTransaction() + } + return Result; + } + OnWriteTransactionTR(Block, Body, BlockNum, TrNum, ContextFrom) { + var Type = Body[0]; + var Result; + switch (Type) { + case global.TYPE_TRANSACTION_CREATE: + { + Result = this.TRCreateAccount(Body, BlockNum, TrNum, ContextFrom) + break; + } + case TYPE_DEPRECATED_TRANSFER1: + { + Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER, WorkStructTransfer) + break; + } + case TYPE_DEPRECATED_TRANSFER2: + { + Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER2, WorkStructTransfer2) + break; + } + case TYPE_TRANSACTION_TRANSFER: + { + Result = this.TRTransferMoney(Block, Body, BlockNum, TrNum, global.FORMAT_MONEY_TRANSFER3, WorkStructTransfer3) + break; + } + case global.TYPE_TRANSACTION_ACC_HASH: + { + Result = 1 + if (global.LOCAL_RUN || global.TEST_NETWORK); + else + if (BlockNum < global.START_BLOCK_ACCOUNT_HASH + 200000) + break; + var BlockNumHash = BlockNum - global.DELTA_BLOCK_ACCOUNT_HASH; + if (!this.TRCheckAccountHash(Body, BlockNum, TrNum)) { + Result = "BAD ACCOUNT HASH" + global.ToLog("2. ****FIND BAD ACCOUNT HASH IN BLOCK: " + BlockNumHash + " DO BLOCK=" + BlockNum) + } + else { + Result = true + } + break; + } + } + return Result; + } + DoCoinBaseTR(Block) { + if (Block.BlockNum < global.START_MINING) + return; + if (!Block.PowHash) + throw "#121 ERROR NO Block.PowHash"; + var SysData = this.ReadStateTR(0); + var SysBalance = SysData.Value.SumCOIN; + const REF_PERIOD_START = global.START_MINING; + const REF_PERIOD_END = 30 * 1000 * 1000; + var AccountID = ReadUintFromArr(Block.AddrHash, 0); + if (AccountID < 8) + return; + var Data = this.ReadStateTR(AccountID); + if (Data && Data.Currency === 0 && Data.BlockNumCreate < Block.BlockNum) { + var Sum; + if (Block.BlockNum >= global.NEW_FORMULA_START) { + Sum = Power * Power * SysBalance / global.TOTAL_SUPPLY_TERA / 100 + if (Block.BlockNum <= global.NEW_FORMULA_TARGET1) { + Sum = SysBalance * 43 * 43 / 100 / global.TOTAL_SUPPLY_TERA + var KMult = (global.NEW_FORMULA_TARGET2 - Block.BlockNum) / (global.NEW_FORMULA_TARGET2 - global.NEW_FORMULA_START); + Sum = KMult * Sum + } + else { + Sum = global.NEW_FORMULA_KTERA * SysBalance / global.TOTAL_SUPPLY_TERA + } + } + else { + var Power = GetPowPower(Block.PowHash); + if (Block.BlockNum >= global.NEW_BLOCK_REWARD1) + Power = 43 + Sum = Power * Power * SysBalance / global.TOTAL_SUPPLY_TERA / 100 + } + var CoinTotal = { SumCOIN: 0, SumCENT: 0 }; + var CoinSum = COIN_FROM_FLOAT(Sum); + if (!ISZERO(CoinSum)) { + if (Data.Adviser >= 8 && Block.BlockNum < REF_PERIOD_END) { + var RefData = this.ReadStateTR(Data.Adviser); + if (RefData && RefData.BlockNumCreate < Block.BlockNum - REF_PERIOD_MINING) { + var K = (REF_PERIOD_END - Block.BlockNum) / (REF_PERIOD_END - REF_PERIOD_START); + var CoinAdv = COIN_FROM_FLOAT(Sum * K); + this.SendMoneyTR(Block, 0, Data.Adviser, CoinAdv, Block.BlockNum, 0xFFFF, "", "Adviser coin base [" + AccountID + "]", 1) + ADD(CoinTotal, CoinAdv) + ADD(CoinSum, CoinAdv) + } + } + this.SendMoneyTR(Block, 0, AccountID, CoinSum, Block.BlockNum, 0xFFFF, "", "Coin base", 1) + ADD(CoinTotal, CoinSum) + var CoinDevelop = CopyObjValue(CoinTotal); + DIV(CoinDevelop, 100) + if (!ISZERO(CoinDevelop)) + this.SendMoneyTR(Block, 0, 9, CoinDevelop, Block.BlockNum, 0xFFFF, "", "Developers support", 1) + } + } + } + GetVerifyTransaction(Block, BlockNum, TrNum, Body) { + if (Block.VersionBody === 1) { + var Result = Block.arrContentResult[TrNum]; + if (!Result) + return - 1; + else + return Result; + } + return 0; + } + GetObjectTransaction(Body) { + var Type = Body[0]; + var format; + switch (Type) { + case global.TYPE_TRANSACTION_CREATE: + { + format = global.FORMAT_CREATE + break; + } + case TYPE_DEPRECATED_TRANSFER1: + { + format = FORMAT_MONEY_TRANSFER + break; + } + case TYPE_DEPRECATED_TRANSFER2: + { + format = FORMAT_MONEY_TRANSFER2 + break; + } + case TYPE_TRANSACTION_TRANSFER: + { + format = FORMAT_MONEY_TRANSFER3 + break; + } + case TYPE_TRANSACTION_ACC_HASH: + { + format = FORMAT_ACCOUNT_HASH3 + break; + } + default: + return ""; + } + var TR; + try { + TR = global.BufLib.GetObjectFromBuffer(Body, format, {}) + } + catch (e) { + } + return TR; + } + GetScriptTransaction(Body) { + var TR = this.GetObjectTransaction(Body); + if (!TR) + return ""; + if (TR.Body && TR.Body.length) { + var App = DAppByType[TR.Body[0]]; + if (App) { + TR.Body = JSON.parse(App.GetScriptTransaction(TR.Body)) + } + } + ConvertBufferToStr(TR) + return JSON.stringify(TR, "", 2); + } + TRCheckAccountHash(Body, BlockNum, TrNum) { + if (BlockNum % PERIOD_ACCOUNT_HASH !== 0) + return 1; + try { + var TR = global.BufLib.GetObjectFromBuffer(Body, FORMAT_ACCOUNT_HASH3, {}); + } + catch (e) { + return 0; + } + if (BlockNum < START_BLOCK_ACCOUNT_HASH + 200000) + return 1; + var Item = this.GetAccountHashItem(TR.BlockNum); + if (Item && Item.BlockNum === TR.BlockNum) { + if (CompareArr(Item.AccHash, TR.AccHash) === 0) { + if (TR.BlockNum >= START_BLOCK_ACCOUNT_HASH3) { + if (CompareArr(Item.SmartHash, TR.SmartHash) === 0 && Item.AccountMax === TR.AccountMax && Item.SmartCount === TR.SmartCount) { + return 1; + } + else + return 0; + } + return 1; + } + else + return 0; + } + else + return 2; + } + TRCreateAccount(Body, BlockNum, TrNum, ContextFrom) { + if (Body.length < 90) + return "Error length transaction"; + var CheckMinPower = 1; + if (BlockNum >= 7000000 || global.LOCAL_RUN || global.TEST_NETWORK) { + if (ContextFrom && ContextFrom.To.length === 1 && ContextFrom.To[0].ID === 0 && ContextFrom.To[0].SumCOIN >= PRICE_DAO(BlockNum).NewAccount) { + CheckMinPower = 0 + } + else { + if (BlockNum % BLOCK_CREATE_INTERVAL !== 0) + return "The create transaction is not possible in this block: " + BlockNum; + if (this.CreateTrCount > 0) + return "The account creation transaction was already in this block: " + BlockNum; + } + } + this.CreateTrCount++ + var power; + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) { + var Tr = { body: Body }; + global.SERVER.CheckCreateTransactionObject(Tr) + power = Tr.power + } + else { + power = GetPowPower(shaarr(Body)) + } + if (global.TEST_NETWORK && BlockNum >= 3290000) { + CheckMinPower = 0 + } + if (CheckMinPower && BlockNum < 19600000) { + var MinPower; + if (BlockNum < 2500000) + MinPower = global.MIN_POWER_POW_ACC_CREATE + else + if (BlockNum < 2800000) + MinPower = global.MIN_POWER_POW_ACC_CREATE + 2 + else + MinPower = global.MIN_POWER_POW_ACC_CREATE + 3 + if (power < MinPower) + return "Error min power POW for create account (update client)"; + } + try { + var TR = global.BufLib.GetObjectFromBuffer(Body, global.global.FORMAT_CREATE, {}); + } + catch (e) { + return "Error transaction format"; + } + if (BlockNum >= 3500000 && !TR.Name) + return "Account name required"; + if (BlockNum >= 5700000 && !TR.Name.trim()) + return "Account name required"; + var Account = this.NewAccountTR(BlockNum, TrNum); + Account.Currency = TR.Currency + Account.PubKey = TR.PubKey + Account.Name = TR.Name + Account.Adviser = TR.Adviser + Account.Value.Smart = TR.Smart + this.WriteStateTR(Account, TrNum) + if (CompareArr(Account.PubKey, global.WALLET.PubKeyArr) === 0) { + global.WALLET.OnCreateAccount(Account) + } + this.ResultTx = Account.Num + return true; + } + TRTransferMoney(Block, Body, BlockNum, TrNum, format_money_transfer, workstructtransfer) { + if (Body.length < 103) + return "Error length transaction"; + try { + var TR = global.BufLib.GetObjectFromBuffer(Body, format_money_transfer, workstructtransfer); + } + catch (e) { + return "Error transaction format"; + } + if (!TR.Version) + TR.Version = 0 + var Data = this.ReadStateTR(TR.FromID); + if (!Data) + return "Error sender's account ID: " + TR.FromID; + if (TR.Version < 3 && TR.Currency !== Data.Currency) + return "Error sender's currency"; + if (TR.Version < 3) { + if (TR.OperationID !== Data.Value.OperationID) + return "Error OperationID (expected: " + Data.Value.OperationID + " for ID: " + TR.FromID + ")"; + } + else { + if (TR.OperationID < Data.Value.OperationID) + return "Error OperationID (expected: " + Data.Value.OperationID + " for ID: " + TR.FromID + ")"; + var MaxCountOperationID = 100; + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) + MaxCountOperationID = 1000000 + if (TR.OperationID > Data.Value.OperationID + MaxCountOperationID) + return "Error too much OperationID (expected max: " + (Data.Value.OperationID + MaxCountOperationID) + " for ID: " + TR.FromID + ")"; + } + if (BlockNum >= global.SMART_BLOCKNUM_START) { + if (TR.To.length > 10) + return "The number of recipients has been exceeded (max=5, current count=" + TR.To.length + ")"; + } + if (TR.Body && TR.Body.length && TR.To.length > 1) { + return "Error - global.DApps transaction can not be used in a multiple transaction"; + } + var TotalSum = { SumCOIN: 0, SumCENT: 0 }; + var MapItem = {}; + var bWas = 0; + for (var i = 0; i < TR.To.length; i++) { + var Item = TR.To[i]; + if (Item.SumCOIN > MAX_SUM_TER) + return "Error MAX_SUM_COIN"; + if (Item.SumCENT >= MAX_SUM_CENT) + return "Error MAX_SUM_CENT"; + if (TR.Version < 3) { + if (Item.ID === TR.FromID || MapItem[Item.ID]) + continue; + MapItem[Item.ID] = 1 + } + bWas = 1 + ADD(TotalSum, Item) + } + if (!bWas && TR.Version < 3) + return "No significant recipients"; + var ZeroSum = 0; + if (TotalSum.SumCOIN === 0 && TotalSum.SumCENT === 0) { + if (TR.Version < 3) + return "No money transaction"; + else + ZeroSum = 1 + } + if (Data.Value.SumCOIN < TotalSum.SumCOIN || (Data.Value.SumCOIN === TotalSum.SumCOIN && Data.Value.SumCENT < TotalSum.SumCENT)) + return "Not enough money on the account"; + if (BlockNum >= global.NEW_ACCOUNT_INCREMENT) + Data.Value.OperationID = TR.OperationID + Data.Value.OperationID++ + TR.Value = TotalSum + var arr = []; + MapItem = {} + var arrpub = []; + for (var i = 0; i < TR.To.length; i++) { + var Item = TR.To[i]; + var DataTo = this.ReadStateTR(Item.ID); + if (!DataTo) + return "Error receiver account ID: " + Item.ID; + if (!ZeroSum && Data.Currency !== DataTo.Currency) + return "Error receiver currency"; + for (var j = 0; j < 33; j++) + arrpub[arrpub.length] = DataTo.PubKey[j] + if (DataTo.Value.Smart) { + if (TR.To.length > 1) + return "Error - smart accounts can not be used in a multiple transaction"; + } + if (TR.Version === 3 && Item.ID === 0 && Item.PubKey && Item.PubKey.length === 33) { + if (Item.SumCOIN < PRICE_DAO(BlockNum).NewAccount) + return "Not enough money for create account with index: " + i; + var name = TR.Description; + var index = name.indexOf("\n"); + if (index !== - 1) + name = name.substr(0, index) + var Account = this.NewAccountTR(BlockNum, TrNum); + Account.PubKey = Item.PubKey + Account.Name = name + this.WriteStateTR(Account, TrNum) + this.ResultTx = Account.Num + Item.ID = Account.Num + this.SendMoneyTR(Block, Data.Num, Account.Num, { SumCOIN: Item.SumCOIN, SumCENT: Item.SumCENT }, BlockNum, TrNum, TR.Description, + TR.Description, 1) + this.SendMoneyTR(Block, Account.Num, 0, { SumCOIN: PRICE_DAO(BlockNum).NewAccount, SumCENT: 0 }, BlockNum, TrNum, "Fee for create account", + "", 1) + } + else { + if (TR.Version < 3) { + if (Item.ID === TR.FromID || MapItem[Item.ID]) + continue; + MapItem[Item.ID] = 1 + } + this.SendMoneyTR(Block, Data.Num, DataTo.Num, { SumCOIN: Item.SumCOIN, SumCENT: Item.SumCENT }, BlockNum, TrNum, TR.Description, + TR.Description, 0) + arr.push(DataTo) + } + } + if (TR.Version < 3 && arr.length === 0) + return "No recipients"; + var hash; + if (TR.Version === 2 || TR.Version === 3) { + for (var j = 0; j < Body.length - 64 - 12; j++) + arrpub[arrpub.length] = Body[j] + hash = global.SHA3BUF(arrpub, BlockNum) + } + else + if (!TR.Version) { + hash = global.SHA3BUF(Body.slice(0, Body.length - 64 - 12), BlockNum) + } + else { + return "Error transaction version"; + } + var Result = 0; + if (Data.PubKey[0] === 2 || Data.PubKey[0] === 3) + try { + Result = global.secp256k1.verify(hash, TR.Sign, Data.PubKey) + } + catch (e) { + } + if (!Result) { + return "Error sign transaction"; + } + if (TR.Body && TR.Body.length) { + var App = DAppByType[TR.Body[0]]; + if (App) { + TR.FromPubKey = Data.PubKey + var Result = App.OnWriteTransaction(Block, TR.Body, BlockNum, TrNum, TR); + if (Result !== true) + return Result; + } + } + return true; + } + ReadState(Num) { + var Data = this.DBState.Read(Num); + if (Data) + Data.WN = "" + return Data; + } + GetMinBlockAct() { + var DBAct; + var MaxNum = this.DBActPrev.GetMaxNum(); + if (MaxNum === - 1) + DBAct = this.DBAct + else + DBAct = this.DBActPrev + var Item = DBAct.Read(0); + if (!Item) + return - 1; + else + return Item.BlockNum; + } + DeleteAct(BlockNumFrom) { + if (global.START_SERVER) + throw "DeleteAct START_SERVER"; + if (BlockNumFrom > 0) { + var StateTX = this.DBStateTX.Read(0); + StateTX.BlockNum = BlockNumFrom - 1 + this.DBStateTX.Write(StateTX) + } + this.DeleteActOneDB(this.DBAct, BlockNumFrom) + this.DeleteActOneDB(this.DBActPrev, BlockNumFrom) + this.DBAccountsHash.Truncate(Math.trunc(BlockNumFrom / PERIOD_ACCOUNT_HASH)) + } + DeleteActOneDB(DBAct, BlockNum) { + var MaxNum = DBAct.GetMaxNum(); + if (MaxNum === - 1) + return; + for (var num = MaxNum; num >= 0; num--) { + var ItemCheck = DBAct.Read(num); + if (!ItemCheck) { + ToLogTrace("!ItemCheck") + throw "ERRR DeleteActOneDB"; + } + if (ItemCheck.BlockNum < BlockNum) { + this.ProcessingDeleteAct(DBAct, num + 1) + return; + } + } + this.ProcessingDeleteAct(DBAct, 0) + } + ProcessingDeleteAct(DBAct, StartNum) { + var Map = {}; + var bWas = 0; + var NumTruncateState; + for (var num = StartNum; true; num++) { + var Item = DBAct.Read(num); + if (!Item) + break; + bWas = 1 + if (Map[Item.ID]) + continue; + Map[Item.ID] = 1 + if (Item.Mode === 1) { + if (!NumTruncateState) + NumTruncateState = Item.ID + } + else { + var Data = this.DBState.Read(Item.ID); + Data.Value = Item.PrevValue + this._DBStateWrite(Data, Item.BlockNum, 1) + var History = this.DBStateHistory.Read(Item.ID); + if (History) { + History.NextPos = Item.PrevValue.NextPos + this.DBStateHistory.Write(History) + } + } + } + if (bWas) { + if (NumTruncateState) { + this._DBStateTruncate(NumTruncateState - 1) + this.DBStateHistory.Truncate(NumTruncateState - 1) + } + DBAct.Truncate(StartNum - 1) + } + } + FindBlockInAct(DBAct, BlockNum) { + return DBAct.FastFindBlockNum(BlockNum); + } + GetHole() { + return [{ s: 8300, f: 186478 }]; + } + IsHole(num) { + if (global.ALL_VIEW_ROWS) + return 0; + var ArrHole = this.GetHole(); + for (var i = 0; i < ArrHole.length; i++) + if (num >= ArrHole[i].s && num <= ArrHole[i].f) + return 1; + return 0; + } + FindAccounts(PubKeyArr, map, nSet) { + var Count = 0; + for (var num = 0; true; num++) { + if (this.IsHole(num)) + continue; + var Data = this.ReadState(num); + if (!Data) + break; + for (var i = 0; i < PubKeyArr.length; i++) + if (CompareArr(Data.PubKey, PubKeyArr[i]) === 0) { + map[Data.Num] = i + Count++ + } + } + return Count; + } + GetWalletAccountsByMap(map) { + var arr = []; + for (var key in map) { + var Num = parseInt(key); + var Data = this.ReadState(Num); + if (Data) { + if (!Data.PubKeyStr) + Data.PubKeyStr = global.GetHexFromArr(Data.PubKey) + arr.push(Data) + Data.WN = map[key] + Data.Name = NormalizeName(Data.Name) + if (Data.Currency) + Data.CurrencyObj = global.DApps.Smart.ReadSimple(Data.Currency) + if (Data.Value.Smart) { + Data.SmartObj = global.DApps.Smart.ReadSimple(Data.Value.Smart) + if (Data.SmartObj) + Data.SmartState = this.GetSmartState(Data, Data.SmartObj.StateFormat) + else + Data.SmartState = {} + } + } + } + return arr; + } + GetMaxAccount() { + return this.DBState.GetMaxNum(); + } + GetRowsAccounts(start, count, Filter, bGetState) { + if (Filter) { + Filter = Filter.trim() + } + var F; + if (Filter) { + if (Filter.substring(0, 1) === "=") { + Filter = Filter.substring(1) + try { + F = CreateEval(Filter, "Cur,Currency,ID,Operation,Amount,Adviser,Name,PubKey,Smart,BlockNum") + } + catch (e) { + F = undefined + global.ToLog("" + e) + } + } + else { + Filter = Filter.toUpperCase() + } + } + var WasError = 0; + var arr = []; + for (var num = start; true; num++) { + if (this.IsHole(num)) + continue; + var Data = this.ReadState(num); + if (!Data) + break; + if (!Data.PubKeyStr) + Data.PubKeyStr = global.GetHexFromArr(Data.PubKey) + Data.Name = NormalizeName(Data.Name) + if (F) { + var Cur = Data.Currency; + var Currency = Data.Currency; + var ID = Data.Num; + var Operation = Data.Value.OperationID; + var Amount = FLOAT_FROM_COIN(Data.Value); + var Adviser = Data.Adviser; + var Name = Data.Name; + var PubKey = global.GetHexFromArr(Data.PubKey); + var Smart = Data.Value.Smart; + try { + if (!F(Cur, Currency, ID, Operation, Amount, Adviser, Name, PubKey, Smart, Data.BlockNumCreate)) + continue; + } + catch (e) { + if (!WasError) + global.ToLog("" + e) + WasError = 1 + } + } + else + if (Filter) { + var Amount = FLOAT_FROM_COIN(Data.Value); + var PubKey = global.GetHexFromArr(Data.PubKey); + var Str = "" + Data.Num + " " + Data.Value.OperationID + " " + Data.Name.toUpperCase() + " " + Data.Adviser + " " + Amount + " " + PubKey + " " + Smart + " " + Data.BlockNumCreate; + if (Str.indexOf(Filter) < 0) + continue; + } + if (bGetState) { + if (Data.Currency) + Data.CurrencyObj = global.DApps.Smart.ReadSimple(Data.Currency) + if (Data.Value.Smart) { + Data.SmartObj = global.DApps.Smart.ReadSimple(Data.Value.Smart) + if (Data.SmartObj) + Data.SmartState = this.GetSmartState(Data, Data.SmartObj.StateFormat) + else + Data.SmartState = {} + } + } + arr.push(Data) + count-- + if (count < 1) + break; + } + return arr; + } + GetSmartState(StateData, StateFormat) { + var SmartState; + try { + SmartState = global.BufLib.GetObjectFromBuffer(StateData.Value.Data, StateFormat, {}) + if (typeof SmartState === "object") + SmartState.Num = StateData.Num + } + catch (e) { + SmartState = {} + } + return SmartState; + } + GetActsMaxNum() { + return this.DBActPrev.GetMaxNum() + this.DBAct.GetMaxNum(); + } + GetActList(start, count) { + var arr = []; + var num; + for (num = start; num < start + count; num++) { + var Item = this.DBActPrev.Read(num); + if (!Item) + break; + Item.Num = "Prev." + Item.Num + if (Item.TrNum === 0xFFFF) + Item.TrNum = "" + arr.push(Item) + if (arr.length > count) + return arr; + } + start = num - this.DBActPrev.GetMaxNum() - 1 + for (num = start; num < start + count; num++) { + var Item = this.DBAct.Read(num); + if (!Item) + break; + Item.Num = Item.Num + if (Item.TrNum === 0xFFFF) + Item.TrNum = "" + arr.push(Item) + if (arr.length > count) + return arr; + } + return arr; + } + GetHashOrUndefined(BlockNum) { + if (BlockNum % PERIOD_ACCOUNT_HASH !== 0) + return undefined; + var Item = this.GetAccountHashItem(BlockNum); + if (Item) + return Item.AccHash; + else + return undefined; + } + GetAccountHashItem(BlockNum) { + var Item = this.DBAccountsHash.Read(Math.trunc(BlockNum / PERIOD_ACCOUNT_HASH)); + return Item; + } + GetHashedMaxBlockNum() { + var Num = this.DBAccountsHash.GetMaxNum(); + if (Num >= 0) { + var Data = this.DBAccountsHash.Read(Num); + return Data.BlockNum; + } + else + return 0; + } + CalcHash(Block, BlockMaxAccount) { + if (Block.BlockNum % PERIOD_ACCOUNT_HASH !== 0) + return; + if (this.DBState.WasUpdate) { + this.CalcMerkleTree() + } + var Hash = this.DBState.MerkleHash; + var SmartHash; + var SmartCount = global.DApps.Smart.GetMaxNum() + 1; + if (SmartCount > 0) { + var MaxSmart = global.DApps.Smart.DBSmart.Read(SmartCount - 1); + SmartHash = MaxSmart.SumHash + } + else { + SmartHash = [] + } + var Data = { + Num: Block.BlockNum / PERIOD_ACCOUNT_HASH, BlockNum: Block.BlockNum, AccHash: Hash, SumHash: Block.SumHash, AccountMax: BlockMaxAccount, + SmartHash: SmartHash, SmartCount: SmartCount + }; + this.DBAccountsHash.Write(Data) + this.DBAccountsHash.Truncate(Block.BlockNum / PERIOD_ACCOUNT_HASH) + return Data; + } + CalcMerkleTree(bForce) { + this.DBState.MerkleHash = this.DBState.CalcMerkleTree(bForce) + this.DBState.WasUpdate = 0 + } + GetAdviserByMiner(Map, Id) { + var Adviser = Map[Id]; + if (Adviser === undefined) { + var Item = this.ReadState(Id); + if (Item) + Adviser = Item.Adviser + else + Adviser = 0 + Map[Id] = Adviser + } + return Adviser; + } + BeginBlock() { + this.DBChanges = { BlockMap: {}, BlockMaxAccount: this.GetMaxAccount(), BlockHistory: [], BlockEvent: [], } + } + BeginTransaction() { + global.TickCounter = 35000 + this.DBChanges.TRMap = {} + this.DBChanges.TRMaxAccount = this.DBChanges.BlockMaxAccount + this.DBChanges.RollBackTransaction = 0 + this.DBChanges.TRHistory = [] + this.DBChanges.TREvent = [] + } + RollBackTransaction() { + this.DBChanges.RollBackTransaction = 1 + } + CommitBlock(Block) { + var BlockNum = Block.BlockNum; + var DBChanges = this.DBChanges; + for (var i = 0; i < DBChanges.BlockHistory.length; i++) { + var Data = DBChanges.BlockHistory[i]; + var Account = DBChanges.BlockMap[Data.CurID]; + Data.Type = 1 + Data.NextPos = Account.Value.NextPos + Account.Value.NextPos = this.SaveHistory(Data) + } + var arr = []; + for (var key in DBChanges.BlockMap) { + key = ParseNum(key) + var Data = DBChanges.BlockMap[key]; + if (Data.Changed) { + arr.push(Data) + } + } + arr.sort(function(a, b) { + return a.Num - b.Num; + }) + for (var i = 0; i < arr.length; i++) { + var Account = arr[i]; + var BackLog = { + Num: undefined, ID: Account.Num, BlockNum: BlockNum, PrevValue: Account.BackupValue, TrNum: Account.ChangeTrNum, + Mode: Account.New + }; + this.DBAct.Write(BackLog) + } + for (var i = 0; i < arr.length; i++) { + var Account = arr[i]; + this._DBStateWrite(Account, BlockNum, 0) + } + for (var i = 0; i < arr.length; i++) { + var Account = arr[i]; + var History = { Num: Account.Num, NextPos: Account.Value.NextPos }; + this.DBStateHistory.Write(History) + } + for (var i = 0; i < DBChanges.BlockEvent.length; i++) { + var Data = DBChanges.BlockEvent[i]; + var Has = global.TreeFindTX.LoadValue("Smart:" + Data.Smart, 1); + if (Has) { + process.send({ cmd: "DappEvent", Data: Data }) + } + } + global.TickCounter = 0 + this.DBChanges = undefined + this.CalcHash(Block, DBChanges.BlockMaxAccount) + var StateTX = this.DBStateTX.Read(0); + StateTX.BlockNum = BlockNum + this.DBStateTX.Write(StateTX) + } + CommitTransaction(BlockNum, TrNum) { + var DBChanges = this.DBChanges; + if (DBChanges.RollBackTransaction) + return false; + DBChanges.BlockMaxAccount = DBChanges.TRMaxAccount + for (var key in DBChanges.TRMap) { + key = ParseNum(key) + var Data = DBChanges.TRMap[key]; + if (Data.Changed) { + DBChanges.BlockMap[key] = Data + if (Data.New) + this.OnWriteNewAccountTR(Data, BlockNum, TrNum) + } + } + for (var i = 0; i < DBChanges.TRHistory.length; i++) + DBChanges.BlockHistory.push(DBChanges.TRHistory[i]) + for (var i = 0; i < DBChanges.TREvent.length; i++) { + DBChanges.BlockEvent.push(DBChanges.TREvent[i]) + } + global.TickCounter = 0 + return true; + } + OnWriteNewAccountTR(Data, BlockNum, TrNum) { + if (BlockNum < global.SMART_BLOCKNUM_START) + Data.Value.Smart = 0 + Data.BlockNumCreate = BlockNum + if (Data.Adviser > this.GetMaxAccount()) + Data.Adviser = 0 + if (Data.Value.Smart > global.DApps.Smart.GetMaxNum()) + Data.Value.Smart = 0 + if (Data.Currency > global.DApps.Smart.GetMaxNum()) + Data.Currency = 0 + if (Data.Currency) { + var Smart = global.DApps.Smart.ReadSmart(Data.Currency); + if (!Smart || !Smart.TokenGenerate) + Data.Currency = 0 + } + } + NewAccountTR(BlockNum, TrNum) { + var DBChanges = this.DBChanges; + DBChanges.TRMaxAccount++ + var Data: any = { + Num: DBChanges.TRMaxAccount, New: 1, Changed: 1, ChangeTrNum: TrNum, BackupValue: {}, PubKey: [], Currency: 0, Adviser: 0, + Value: { SumCOIN: 0, SumCENT: 0, OperationID: 0, Smart: 0, Data: [] } + }; + this.DBChanges.TRMap[Data.Num] = Data + return Data; + } + ReadStateTR(Num) { + Num = ParseNum(Num) + var TRMap = this.DBChanges.TRMap; + var Data = TRMap[Num]; + if (!Data) { + var Value; + var BlockMap = this.DBChanges.BlockMap; + var BData = BlockMap[Num]; + if (!BData) { + BData = this.DBState.Read(Num) + if (!BData) + return undefined; + BData.Num = Num + Value = BData.Value + var BHistory = this.DBStateHistory.Read(Num); + if (BHistory) + Value.NextPos = BHistory.NextPos + BData.BackupValue = { + SumCOIN: Value.SumCOIN, SumCENT: Value.SumCENT, OperationID: Value.OperationID, Smart: Value.Smart, Data: Value.Data, + NextPos: Value.NextPos + } + BlockMap[Num] = BData + } + Value = BData.Value + Data = { + Num: Num, Currency: BData.Currency, PubKey: BData.PubKey, Name: BData.Name, BlockNumCreate: BData.BlockNumCreate, Adviser: BData.Adviser, + Value: { + SumCOIN: Value.SumCOIN, SumCENT: Value.SumCENT, OperationID: Value.OperationID, Smart: Value.Smart, Data: CopyArr(Value.Data), + NextPos: Value.NextPos + }, BackupValue: BData.BackupValue + } + TRMap[Num] = Data + } + return Data; + } + WriteStateTR(Data, TrNum) { + Data.Changed = 1 + Data.ChangeTrNum = TrNum + } + SendMoneyTR(Block, FromID, ToID, CoinSum, BlockNum, TrNum, DescriptionFrom, DescriptionTo, OperationCount) { + FromID = ParseNum(FromID) + ToID = ParseNum(ToID) + if (CoinSum.SumCENT >= 1e9) { + throw "ERROR SumCENT>=1e9"; + } + var FromData = this.ReadStateTR(FromID); + if (!FromData) { + throw "Send: Error account FromNum: " + FromID; + } + if (!SUB(FromData.Value, CoinSum)) { + throw "Not enough money on the account ID:" + FromID; + } + this.WriteStateTR(FromData, TrNum) + if (FromID > 15) { + this.DBChanges.TRHistory.push({ + Direct: "-", Receive: 0, CurID: FromID, CorrID: ToID, BlockNum: BlockNum, TrNum: TrNum, FromID: FromID, + ToID: ToID, SumCOIN: CoinSum.SumCOIN, SumCENT: CoinSum.SumCENT, Description: DescriptionFrom, FromOperationID: FromData.Value.OperationID, + Currency: FromData.Currency + }) + } + var ToData = this.ReadStateTR(ToID); + if (!ToData) { + throw "Send: Error account ToNum: " + ToID; + } + ADD(ToData.Value, CoinSum) + this.WriteStateTR(ToData, TrNum) + if (ToID > 15) { + this.DBChanges.TRHistory.push({ + Direct: "+", Receive: 1, CurID: ToID, CorrID: FromID, BlockNum: BlockNum, TrNum: TrNum, FromID: FromID, + ToID: ToID, SumCOIN: CoinSum.SumCOIN, SumCENT: CoinSum.SumCENT, Description: DescriptionTo, FromOperationID: FromData.Value.OperationID, + Currency: ToData.Currency + }) + } + FromData.Value.OperationID += OperationCount + if (FromData.Value.Smart) { + var Context = { FromID: FromID, ToID: ToID, Description: DescriptionFrom, Value: CoinSum }; + RunSmartMethod(Block, FromData.Value.Smart, FromData, BlockNum, TrNum, Context, "OnSend") + } + if (ToData.Value.Smart) { + var Context = { FromID: FromID, ToID: ToID, Description: DescriptionTo, Value: CoinSum }; + RunSmartMethod(Block, ToData.Value.Smart, ToData, BlockNum, TrNum, Context, "OnGet") + } + } + GetSignTransferTx(TR, PrivKey) { + var Arr; + if (TR.Version === 2 || TR.Version === 3) { + var format; + if (TR.Version === 2) + format = FORMAT_MONEY_TRANSFER_BODY2 + else + format = FORMAT_MONEY_TRANSFER_BODY3 + Arr = [] + for (var i = 0; i < TR.To.length; i++) { + var Item = TR.To[i]; + var DataTo = global.DApps.Accounts.ReadState(Item.ID); + if (!DataTo) + return [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (var j = 0; j < 33; j++) + Arr[Arr.length] = DataTo.PubKey[j] + } + var Body = global.BufLib.GetBufferFromObject(TR, format, MAX_TRANSACTION_SIZE, {}); + for (var j = 0; j < Body.length; j++) + Arr[Arr.length] = Body[j] + } + else { + Arr = global.BufLib.GetBufferFromObject(TR, FORMAT_MONEY_TRANSFER_BODY, MAX_TRANSACTION_SIZE, {}) + } + var sigObj = global.secp256k1.sign(SHA3BUF(Arr), Buffer.from(PrivKey)); + return sigObj.signature; + } + SaveHistory(Data) { + var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 1); + var FD = FileItem.fd; + var Position = FileItem.size; + if (!Position) + Position = 100 + var BufWrite = global.BufLib.GetBufferFromObject(Data, this.HistoryFormatArr[Data.Type], 100, WorkStructHistory); + var written = fs.writeSync(FD, BufWrite, 0, BufWrite.length, Position); + if (written !== BufWrite.length) { + TO_ERROR_LOG("DB-HISTORY", 10, "Error write to file:" + written + " <> " + BufWrite.length) + throw "Error write to FILE_NAME_HISTORY"; + return false; + } + if (Position >= FileItem.size) { + FileItem.size = Position + written + } + return Position; + } + GetHistory(Num, Count, StartPos, MinConfirm) { + if (!MinConfirm) + MinConfirm = 0 + var MaxNumBlockDB = global.SERVER.GetMaxNumBlockDB(); + var Position = StartPos; + var FileItem = global.HistoryDB.OpenDBFile(FILE_NAME_HISTORY, 0); + var FD = FileItem.fd; + if (Position === undefined) { + var Account = this.DBStateHistory.Read(Num); + if (!Account) { + return []; + } + Position = Account.NextPos + } + var arr = []; + while (Count > 0 && Position) { + Count-- + var BufRead = global.BufLib.GetNewBuffer(100); + var bytesRead = fs.readSync(FD, BufRead, 0, BufRead.length, Position); + if (bytesRead < 13) { + global.ToLog("bytesRead<13 Position=" + Position) + break; + } + var Type = BufRead[0]; + var format = this.HistoryFormatArr[Type]; + if (!format) { + global.ToLog("Error from history, type = " + Type) + break; + } + var Item = global.BufLib.GetObjectFromBuffer(BufRead, format, WorkStructHistory); + Item.Pos = Position + Position = Item.NextPos + if (MinConfirm) { + if (Item.BlockNum + MinConfirm > MaxNumBlockDB) { + continue; + } + } + arr.push(Item) + } + return arr; + } + CalcTotalSum(Currency) { + var SumCoin = { SumCOIN: 0, SumCENT: 0 }; + for (var num = 0; true; num++) { + var Data = this.ReadState(num); + if (!Data) + break; + if (Data.Currency === Currency) { + ADD(SumCoin, Data.Value) + } + } + return FLOAT_FROM_COIN(SumCoin); + } +}; +module.exports = AccountApp; +var App = new AccountApp; +DApps["Accounts"] = App; +DAppByType[TYPE_TRANSACTION_CREATE] = App; +DAppByType[TYPE_DEPRECATED_TRANSFER1] = App; +DAppByType[TYPE_DEPRECATED_TRANSFER2] = App; +DAppByType[TYPE_TRANSACTION_TRANSFER] = App; +DAppByType[TYPE_TRANSACTION_ACC_HASH] = App; + +function TestStateFiles(Size, Format) { + return; + if (global.PROCESS_NAME !== "MAIN") + return; + var DBState1 = new DBRow("state-ok", Size, Format, 0); + var DBState2 = new DBRow("state-no", Size, Format, 0); + for (var Num = 0; 1; Num++) { + var Item1 = DBState1.Read(Num); + var Item2 = DBState2.Read(Num); + if (!Item1 && !Item2) + break; + var Str1 = JSON.stringify(Item1); + var Str2 = JSON.stringify(Item2); + if (Str1 !== Str2) { + global.ToLog("Err item: " + Num); + global.ToLog("1: " + Str1); + global.ToLog("2: " + Str2); + } + } +}; diff --git a/src/system/dapp.ts b/src/system/dapp.ts new file mode 100644 index 0000000..fd37568 --- /dev/null +++ b/src/system/dapp.ts @@ -0,0 +1,61 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +import * as fs from 'fs' +class DApp { + constructor() { + } + Name() { + return ""; + } + SendMessage(Body, ToAddr) { + global.SERVER.SendMessage(Body, ToAddr) + } + AddTransaction(Tr) { + global.SERVER.AddTransaction(Tr) + } + GetScriptTransaction(Body) { + return ""; + } + GetVerifyTransaction(Block, BlockNum, TrNum, Body) { + return 1; + } + ClearDataBase() { + } + GetSenderNum(BlockNum, Body) { + return 0; + } + OnWriteBlockStart(Block) { + } + OnWriteBlockFinish(Block) { + } + OnDeleteBlock(Block) { + } + OnWriteTransaction(Block, Body, BlockNum, TrNum) { + } + OnMessage(Msg) { + } +}; +module.exports = DApp; + +function ReqDir(Path) { + if (fs.existsSync(Path)) { + var arr = fs.readdirSync(Path); + for (var i = 0; i < arr.length; i++) { + var name = arr[i]; + global.ToLog("Reg: " + name); + var name2 = Path + "/" + arr[i]; + require(name2); + } + } +}; +global.DApps = {}; +global.DAppByType = {}; diff --git a/src/system/file.ts b/src/system/file.ts new file mode 100644 index 0000000..60e1a6c --- /dev/null +++ b/src/system/file.ts @@ -0,0 +1,40 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +global.TYPE_TRANSACTION_FILE = 5; +global.FORMAT_FILE_CREATE = "{type:byte,Name:str,ContentType:str,Reserve:arr10,Data:tr}"; +//@ts-ignore +let WorkStructRun = {}; +class FileApp extends require("./dapp") +{ + constructor() { + super() + } + OnWriteTransaction(Block, Body, BlockNum, TrNum, ContextFrom) { + return true; + } + GetObjectTransaction(Body) { + var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_FILE_CREATE, WorkStructRun); + return TR; + } + GetScriptTransaction(Body) { + var TR = this.GetObjectTransaction(Body); + ConvertBufferToStr(TR) + return JSON.stringify(TR, undefined, 2); + } + GetVerifyTransaction(Block, BlockNum, TrNum, Body) { + return 1; + } +}; +module.exports = FileApp; +var App = new FileApp; +global.DApps["File"] = App; +global.DAppByType[global.TYPE_TRANSACTION_FILE] = App; diff --git a/src/system/messager.ts b/src/system/messager.ts new file mode 100644 index 0000000..64f3bbe --- /dev/null +++ b/src/system/messager.ts @@ -0,0 +1,123 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +require('../core/crypto-library'); +const OPEN_TYPE_TRANSACTION = 11; +const MESSAGE_TYPE_TRANSACTION = 12; +const MAX_MSG_SIZE = 1024; +var TempArrayTr = new Uint8Array(MAX_MSG_SIZE); +const MESSAGE_START = 9; +const MESSAGE_END = MAX_MSG_SIZE - 5; +require("./names"); +class CApp extends require("./dapp") +{ + constructor() { + super() + this.Channels = {} + this.NamesMap = NAMES.KeyValueMap + global.MESSAGER = this + } + Decrypt(Body) { + for (var key in this.Channels) { + var Node = this.Channels[key]; + Decrypt(Body, TempArrayTr, Node.Secret) + if (IsZeroArr(TempArrayTr.slice(MESSAGE_END))) { + var Str = Utf8ArrayToStr(TempArrayTr.slice(MESSAGE_START)); + return Str; + } + } + return undefined; + } + Encrypt(StrMessage, StrTo) { + var NameArr; + if (typeof StrTo === "string") { + NameArr = GetArrFromStr(StrTo, 32) + } + else { + NameArr = Str + } + var arrMessage = GetArrFromStr(StrMessage, MESSAGE_END); + var ArrayTr = new Uint8Array(MAX_MSG_SIZE); + ArrayTr[0] = MESSAGE_TYPE_TRANSACTION + for (var i = 5; i < MAX_MSG_SIZE; i++) { + ArrayTr[i] = arrMessage[i - MESSAGE_START] + } + var Body = new Uint8Array(MAX_MSG_SIZE); + var Node = this.OpenChannel(NameArr); + Encrypt(ArrayTr, Body, Node.Secret) + return Body; + } + OpenChannel(FromNameArr) { + var FromArr; + var StrKeyFrom = GetHexFromAddres(FromNameArr); + if (this.NamesMap[StrKeyFrom]) { + FromArr = this.NamesMap[StrKeyFrom] + } + else { + FromArr = FromNameArr + } + var StrKey = GetHexFromAddres(FromArr); + var Node = this.Channels[StrKey]; + if (!Node) { + Node = { addrArr: FromArr } + CheckContextSecret(this.Server, Node) + this.Channels[StrKey] = Node + } + return Node; + } + OnWriteTransaction(Block, Body, BlockNum, TrNum) { + var Type = Body[0]; + if (Type === OPEN_TYPE_TRANSACTION) { + var ToArr = Body.slice(33); + if (global.CompareArr(ToArr, NAMES.CurrentNameArr) === 0 || global.CompareArr(ToArr, this.Server.addrArr) === 0) { + var FromNameArr = Body.slice(1, 33); + this.OpenChannel(FromNameArr) + } + } + else + if (Type === MESSAGE_TYPE_TRANSACTION) { + var Str = this.Decrypt(Body); + if (Str !== undefined) + global.ToLog("GET MESSAGE:" + Str) + } + } + OnMessage(Msg) { + global.ToLog("GET MESSAGE:" + Msg.body) + return; + var Body = Msg.body; + var Type = Body[0]; + if (Type === MESSAGE_TYPE_TRANSACTION) { + var Str = this.Decrypt(Body); + if (Str !== undefined) { + global.ToLog("GET MESSAGE:" + Str) + } + } + } +}; + +function TestEncryptDecrypt() { + const CMessager = module.exports; + var Server = { KeyPair: GetKeyPairTest("Test"), DApp: { Names: { KeyValueMap: {} } }, }; + var Test = new CMessager(Server); + var KeyPair2 = GetKeyPairTest("Test2"); + var StrTest1 = GetArrFromStr("Test2", 32); + var StrKey = GetHexFromAddres(StrTest1); + MESSAGER.NamesMap[StrKey] = KeyPair2.addrArr; + var Body = MESSAGER.Encrypt("This is a test message!", "Test2"); + var Str2 = MESSAGER.Decrypt(Body); + console.log("Decrypt:"); + console.log(Str2); +}; +module.exports = CApp; +var App = new CApp; +DApps["Messager"] = App; +DAppByType[OPEN_TYPE_TRANSACTION] = App; +DAppByType[MESSAGE_TYPE_TRANSACTION] = App; diff --git a/src/system/names.ts b/src/system/names.ts new file mode 100644 index 0000000..02ae542 --- /dev/null +++ b/src/system/names.ts @@ -0,0 +1,38 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const NAMES_TYPE_TRANSACTION = 10; +class NameApp extends require("./dapp") +{ + KeyValueMap; + CurrentNameArr; + constructor() { + super() + this.KeyValueMap = {} + this.CurrentNameArr = "" + global.NAMES = this + } + OnWriteTransaction(Block, Body, BlockNum, TrNum) { + return; + if (Body[0] === NAMES_TYPE_TRANSACTION) { + var StrKey = global.GetHexFromAddres(Body.slice(1, 33)); + if (!this.KeyValueMap[StrKey]) { + this.KeyValueMap[StrKey] = Body.slice(33) + if (CompareArr(Body.slice(33), this.Server.addrArr) === 0) + this.CurrentNameArr = Body.slice(1, 33) + } + } + } +}; +module.exports = NameApp; +var Names = new NameApp; +global.DApps["Names"] = Names; +global.DAppByType[NAMES_TYPE_TRANSACTION] = Names; diff --git a/src/system/smart.ts b/src/system/smart.ts new file mode 100644 index 0000000..72d37a3 --- /dev/null +++ b/src/system/smart.ts @@ -0,0 +1,1220 @@ +/* + * @project: TERA + * @version: Development (beta) + * @license: MIT (not for evil) + * @copyright: Yuriy Ivanov (Vtools) 2017-2019 [progr76@gmail.com] + * Web: https://terafoundation.org + * Twitter: https://twitter.com/terafoundation + * Telegram: https://t.me/terafoundation +*/ + +"use strict"; +const LOC_ADD_NAME = "$"; +require("../HTML/JS/lexer.js"); +global.TickCounter = 0; +//@ts-ignore +const DBRow = require("../core/db/db-row"); +const TYPE_TRANSACTION_SMART_CREATE = 130; +global.TYPE_TRANSACTION_SMART_RUN = 135; +const TYPE_TRANSACTION_SMART_CHANGE = 140; +global.FORMAT_SMART_CREATE = "{\ + Type:byte,\ + TokenGenerate:byte,\ + StartValue:uint,\ + OwnerPubKey:byte,\ + ISIN:str,\ + Zip:byte,\ + AccountLength:byte,\ + StateFormat:str,\ + Category1:byte,\ + Category2:byte,\ + Category3:byte,\ + Reserve:arr20,\ + IconBlockNum:uint,\ + IconTrNum:uint16,\ + ShortName:str5,\ + Name:str,\ + Description:str,\ + Code:str,\ + HTML:str,\ + }"; +const WorkStructCreate = {}; +global.FORMAT_SMART_RUN = "{\ + Type:byte,\ + Account:uint,\ + MethodName:str,\ + Params:str,\ + FromNum:uint,\ + OperationID:uint,\ + Reserve:arr10,\ + Sign:arr64,\ + }"; +//@ts-ignore +const WorkStructRun = {}; +global.FORMAT_SMART_CHANGE = "{\ + Type:byte,\ + Account:uint,\ + Smart:uint32,\ + Reserve:arr10,\ + FromNum:uint,\ + OperationID:uint,\ + Sign:arr64,\ + }"; +const WorkStructChange = {}; +class SmartApp extends require("./dapp") +{ + FORMAT_ROW + ROW_SIZE + DBSmart + constructor() { + super() + var bReadOnly = (global.PROCESS_NAME !== "TX"); + this.FORMAT_ROW = "{\ + Version:byte,\ + TokenGenerate:byte,\ + ISIN:str12,\ + Zip:byte,\ + BlockNum:uint,\ + TrNum:uint16,\ + IconBlockNum:uint,\ + IconTrNum:uint16,\ + ShortName:str5,\ + Name:str40,\ + Account:uint,\ + AccountLength:byte,\ + Category1:byte,\ + Category2:byte,\ + Category3:byte,\ + Owner:uint,\ + Reserve:arr20,\ + StateFormat:str,\ + Description:str,\ + Code:str,\ + HTML:str,\ + SumHash:hash,\ + }" + this.ROW_SIZE = 2 * (1 << 13) + this.DBSmart = new DBRow("smart", this.ROW_SIZE, this.FORMAT_ROW, bReadOnly) + this.InitHole() + if (!bReadOnly) + this.Start() + } + Start() { + if (this.GetMaxNum() + 1 >= 7) + return; + this.DBSmartWrite({ Num: 0, ShortName: "TERA", Name: "TERA", Description: "TERA", BlockNum: 0, TokenGenerate: 1, Account: 0, Category1: 0 }) + for (var i = 1; i < 8; i++) + this.DBSmartWrite({ Num: i, ShortName: "", Name: "", Description: "", BlockNum: 0, TokenGenerate: 1, Account: i, Category1: 0 }) + } + Close() { + this.DBSmart.Close() + } + ClearDataBase() { + this.DBSmart.Truncate(- 1) + this.Start() + } + GetSenderNum(BlockNum, Body) { + var Type = Body[0]; + if (Type && Body.length > 90) { + switch (Type) { + case global.TYPE_TRANSACTION_SMART_RUN: + var len = 1 + 6; + len += 2 + Body[len] + Body[len + 1] * 256 + if (len + 64 > Body.length) + return 0; + len += 2 + Body[len] + Body[len + 1] * 256 + if (len + 64 > Body.length) + return 0; + var Num = ReadUintFromArr(Body, len); + return Num; + case TYPE_TRANSACTION_SMART_CHANGE: + var Num = ReadUintFromArr(Body, 1); + return Num; + } + } + return 0; + } + OnDeleteBlock(Block) { + if (Block.BlockNum < 1) + return; + this.DBSmart.DeleteHistory(Block.BlockNum) + } + OnWriteBlockStart(Block) { + if (Block.BlockNum < 1) + return; + this.OnDeleteBlock(Block) + } + OnWriteBlockFinish(Block) { + } + OnWriteTransaction(Block, Body, BlockNum, TrNum, ContextFrom) { + var Type = Body[0]; + if (!ContextFrom) { + global.DApps.Accounts.BeginTransaction() + } + var Result; + try { + switch (Type) { + case TYPE_TRANSACTION_SMART_CREATE: + Result = this.TRCreateSmart(Block, Body, BlockNum, TrNum, ContextFrom) + break; + case global.TYPE_TRANSACTION_SMART_RUN: + Result = this.TRRunSmart(Block, Body, BlockNum, TrNum, ContextFrom) + break; + case TYPE_TRANSACTION_SMART_CHANGE: + Result = this.TRChangeSmart(Block, Body, BlockNum, TrNum, ContextFrom) + break; + } + } + catch (e) { + Result = "" + e + } + return Result; + } + GetScriptTransaction(Body) { + var Type = Body[0]; + var format; + if (Type === TYPE_TRANSACTION_SMART_CREATE) + format = global.FORMAT_SMART_CREATE + else + if (Type === global.TYPE_TRANSACTION_SMART_RUN) + format = global.FORMAT_SMART_RUN + else + if (Type === TYPE_TRANSACTION_SMART_CHANGE) + format = global.FORMAT_SMART_CHANGE + if (!format) + return ""; + var TR = global.BufLib.GetObjectFromBuffer(Body, format, {}); + ConvertBufferToStr(TR) + return JSON.stringify(TR, undefined, 2); + } + GetVerifyTransaction(Block, BlockNum, TrNum, Body) { + return 1; + } + TRCreateSmart(Block, Body, BlockNum, TrNum, ContextFrom) { + if (!ContextFrom) + return "Pay context required"; + if (Body.length < 31) + return "Error length transaction (min size)"; + if (Body.length > 16000) + return "Error length transaction (max size)"; + if (BlockNum < global.SMART_BLOCKNUM_START) + return "Error block num"; + var TR = global.BufLib.GetObjectFromBuffer(Body, FORMAT_SMART_CREATE, WorkStructCreate); + if (!TR.Name.trim()) + return "Name required"; + if (TR.AccountLength > 50) + return "Error AccountLength=" + TR.AccountLength; + if (TR.AccountLength < 1) + TR.AccountLength = 1 + var AddAccount = TR.AccountLength - 1; + var Price; + if (TR.TokenGenerate) + Price = PRICE_DAO(BlockNum).NewTokenSmart + else + Price = PRICE_DAO(BlockNum).NewSmart + Price += AddAccount * PRICE_DAO(BlockNum).NewAccount + if (!(ContextFrom && ContextFrom.To.length === 1 && ContextFrom.To[0].ID === 0 && ContextFrom.To[0].SumCOIN >= Price)) { + return "Not money in the transaction"; + } + ContextFrom.ToID = ContextFrom.To[0].ID + var Smart = TR; + Smart.Version = 0 + Smart.Zip = 0 + Smart.BlockNum = BlockNum + Smart.TrNum = TrNum + Smart.Reserve = [] + Smart.Num = undefined + Smart.Owner = ContextFrom.FromID + this.DBSmart.CheckNewNum(Smart) + var Account = global.DApps.Accounts.NewAccountTR(BlockNum, TrNum); + Account.Value.Smart = Smart.Num + Account.Name = TR.Name + if (Smart.TokenGenerate) { + Account.Currency = Smart.Num + Account.Value.SumCOIN = TR.StartValue + } + if (TR.OwnerPubKey) + Account.PubKey = ContextFrom.FromPubKey + global.DApps.Accounts.WriteStateTR(Account, TrNum) + for (var i = 0; i < AddAccount; i++) { + var CurAccount = global.DApps.Accounts.NewAccountTR(BlockNum, TrNum); + CurAccount.Value.Smart = Smart.Num + CurAccount.Name = TR.Name + if (Smart.TokenGenerate) + CurAccount.Currency = Smart.Num + if (TR.OwnerPubKey) + CurAccount.PubKey = ContextFrom.FromPubKey + global.DApps.Accounts.WriteStateTR(CurAccount, TrNum) + } + Smart.Account = Account.Num + this.DBSmart.DeleteMap("EVAL" + Smart.Num) + try { + RunSmartMethod(Block, Smart, Account, BlockNum, TrNum, ContextFrom, "OnCreate") + } + catch (e) { + this.DBSmart.DeleteMap("EVAL" + Smart.Num) + return e; + } + this.DBSmartWrite(Smart) + return true; + } + CheckSignFrom(Body, TR, BlockNum, TrNum) { + var ContextFrom = { FromID: TR.FromNum }; + var AccountFrom = global.DApps.Accounts.ReadStateTR(TR.FromNum); + if (!AccountFrom) + return "Error account FromNum: " + TR.FromNum; + if (TR.OperationID < AccountFrom.Value.OperationID) + return "Error OperationID (expected: " + AccountFrom.Value.OperationID + " for ID: " + TR.FromNum + ")"; + var MaxCountOperationID = 100; + if (BlockNum >= global.BLOCKNUM_TICKET_ALGO) + MaxCountOperationID = 1000000 + if (TR.OperationID > AccountFrom.Value.OperationID + MaxCountOperationID) + return "Error too much OperationID (expected max: " + (AccountFrom.Value.OperationID + MaxCountOperationID) + " for ID: " + TR.FromNum + ")"; + var hash = SHA3BUF(Body.slice(0, Body.length - 64 - 12), BlockNum); + var Result = 0; + if (AccountFrom.PubKey[0] === 2 || AccountFrom.PubKey[0] === 3) + try { + Result = secp256k1.verify(hash, TR.Sign, AccountFrom.PubKey) + } + catch (e) { + } + if (!Result) { + return "Error sign transaction"; + } + if (BlockNum >= 13000000) { + AccountFrom.Value.OperationID = TR.OperationID + 1 + global.DApps.Accounts.WriteStateTR(AccountFrom, TrNum) + } + else + if (AccountFrom.Value.OperationID !== TR.OperationID) { + AccountFrom.Value.OperationID = TR.OperationID + global.DApps.Accounts.WriteStateTR(AccountFrom, TrNum) + } + return ContextFrom; + } + TRRunSmart(Block, Body, BlockNum, TrNum, ContextFrom) { + if (Body.length < 100) + return "Error length transaction (min size)"; + if (BlockNum < global.SMART_BLOCKNUM_START) + return "Error block num"; + var TR = global.BufLib.GetObjectFromBuffer(Body, FORMAT_SMART_RUN, WorkStructRun); + var Account = global.DApps.Accounts.ReadStateTR(TR.Account); + if (!Account) + return "RunSmart: Error account Num: " + TR.Account; + if (!ContextFrom && TR.FromNum) { + var ResultCheck = this.CheckSignFrom(Body, TR, BlockNum, TrNum); + if (typeof ResultCheck === "string") + return ResultCheck; + ContextFrom = ResultCheck + } + try { + var Params = JSON.parse(TR.Params); + RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, TR.MethodName, Params, 1) + } + catch (e) { + return e; + } + return true; + } + TRChangeSmart(Block, Body, BlockNum, TrNum, ContextFrom) { + if (Body.length < 21) + return "Error length transaction (min size)"; + if (BlockNum < global.SMART_BLOCKNUM_START) + return "Error block num"; + var TR = global.BufLib.GetObjectFromBuffer(Body, global.FORMAT_SMART_CHANGE, WorkStructChange); + if (!ContextFrom) { + var ResultCheck = this.CheckSignFrom(Body, TR, BlockNum, TrNum); + if (typeof ResultCheck === "string") + return ResultCheck; + ContextFrom = ResultCheck + } + if (TR.Smart > this.GetMaxNum()) + TR.Smart = 0 + if (ContextFrom.FromID !== TR.Account) + return "ChangeSmart: Error account FromNum: " + TR.Account; + var Account = global.DApps.Accounts.ReadStateTR(TR.Account); + if (!Account) + return "Error read account Num: " + TR.Account; + if (BlockNum >= 13000000) { + if (Account.Value.Smart === TR.Smart) + return "The value has not changed"; + } + if (Account.Value.Smart) { + var Smart = this.ReadSmart(Account.Value.Smart); + if (Smart.Account === TR.Account) + return "Can't change base account"; + try { + RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, "OnDeleteSmart") + } + catch (e) { + return e; + } + } + Account.Value.Smart = TR.Smart + Account.Value.Data = [] + global.DApps.Accounts.WriteStateTR(Account, TrNum) + if (Account.Value.Smart) { + try { + RunSmartMethod(Block, Account.Value.Smart, Account, BlockNum, TrNum, ContextFrom, "OnSetSmart") + } + catch (e) { + return e; + } + } + return true; + } + GetRows(start, count, Filter, Category, GetAllData, bTokenGenerate) { + if (Filter) { + Filter = Filter.trim() + Filter = Filter.toUpperCase() + } + if (Category) + Category = ParseNum(Category) + var WasError = 0; + var arr = []; + var Data; + for (var num = start; true; num++) { + if (this.IsHole(num)) + continue; + if (GetAllData) + Data = this.ReadSmart(num) + else + Data = this.ReadSimple(num) + if (!Data) + break; + if (bTokenGenerate && !Data.TokenGenerate) + continue; + if (Category) { + if (Data.Category1 !== Category && Data.Category2 !== Category && Data.Category3 !== Category) + continue; + } + if (Filter) { + var Str = "" + Data.ShortName.toUpperCase() + Data.ISIN.toUpperCase() + Data.Name.toUpperCase() + Data.Description.toUpperCase(); + if (Data.TokenGenerate) + Str += "TOKEN GENERATE" + if (Str.indexOf(Filter) < 0) + continue; + } + var CanAdd = 1; + var DataState = global.DApps.Accounts.ReadState(Data.Account); + if (DataState && !global.ALL_VIEW_ROWS) { + Data.BaseState = global.DApps.Accounts.GetSmartState(DataState, Data.StateFormat) + if (typeof Data.BaseState === "object" && Data.BaseState.HTMLBlock === 404) + CanAdd = 0 + } + if (CanAdd) { + arr.push(Data) + } + count-- + if (count < 1) + break; + } + return arr; + } + GetMaxNum() { + return this.DBSmart.GetMaxNum(); + } + DBSmartWrite(Item) { + var PrevNum; + if (Item.Num === undefined) + PrevNum = this.GetMaxNum() + else + PrevNum = Item.Num - 1 + Item.SumHash = [] + var Buf = global.BufLib.GetBufferFromObject(Item, this.FORMAT_ROW, 20000, {}); + var Hash = global.sha3(Buf); + if (PrevNum < 0) + Item.SumHash = Hash + else { + var PrevItem = this.DBSmart.Read(PrevNum); + if (!PrevItem) { + throw "!PrevItem of Smart num = " + PrevNum; + } + Item.SumHash = sha3arr2(PrevItem.SumHash, Hash) + } + this.DBSmart.Write(Item) + } + ReadSmart(Num) { + Num = ParseNum(Num) + var Smart = this.DBSmart.GetMap("ITEM" + Num); + if (!Smart) { + Smart = this.DBSmart.Read(Num) + if (Smart) { + if (!Smart.WorkStruct) + Smart.WorkStruct = {} + Smart.CodeLength = Smart.Code.length + Smart.HTMLLength = Smart.HTML.length + this.DBSmart.SetMap("ITEM" + Num, Smart) + } + } + return Smart; + } + ReadSimple(Num) { + var Smart = this.DBSmart.GetMap("SIMPLE" + Num); + if (!Smart) { + Smart = this.DBSmart.Read(Num) + if (Smart) { + Smart.CodeLength = Smart.Code.length + Smart.HTMLLength = Smart.HTML.length + Smart.Code = undefined + Smart.HTML = undefined + Smart.Description = undefined + this.DBSmart.SetMap("SIMPLE" + Num, Smart) + } + } + return Smart; + } + InitHole() { + if (global.LOCAL_RUN || global.TEST_NETWORK) + this.RowHole = {} + else + this.RowHole = { "10": 1, "19": 1, "22": 1, "23": 1, "24": 1, "26": 1, "27": 1, "29": 1, "30": 1, "34": 1, "56": 1, "57": 1 } + for (var Num = 0; Num < 8; Num++) + this.RowHole[Num] = 1 + } + IsHole(num) { + if (global.ALL_VIEW_ROWS) + return 0; + return this.RowHole[num]; + } +}; + +function GetParsing(Str) { + LexerJS.ParseCode(Str); + var Code = LexerJS.stream; + for (var key in LexerJS.FunctionMap) { + Code += ";\nfunclist." + key + "=" + LOC_ADD_NAME + key; + } + for (var key in LexerJS.ExternMap) { + Code += ";\npublist." + key + "=" + LOC_ADD_NAME + key; + } + Code += "\n\ + var context;\ + funclist.SetContext=function(cont){context=cont;};\ + "; + return Code; +}; + +function GetSmartEvalContext(Smart) { + var EvalContext = global.DApps.Smart.DBSmart.GetMap("EVAL" + Smart.Num); + if (0) + if (Smart.Num === 26) { + const fs = require("fs"); + var Path = "./dapp-smart/test-test.js"; + Smart.Code = fs.readFileSync(Path, { encoding: "utf8" }); + EvalContext = undefined; + } + if (!EvalContext) { + var CodeLex = GetParsing(Smart.Code); + var publist = {}; + var funclist = {}; + eval(CodeLex); + EvalContext = { publist: publist, funclist: funclist }; + for (var key in funclist) { + Object.freeze(funclist[key]); + } + Object.freeze(funclist); + Object.freeze(publist); + global.DApps.Smart.DBSmart.SetMap("EVAL" + Smart.Num, EvalContext); + } + return EvalContext; +}; +var RunContext = undefined; +global.RunSmartMethod = RunSmartMethod; + +function RunSmartMethod(Block, SmartOrSmartID, Account, BlockNum, TrNum, PayContext, MethodName, Params, bPublic) { + var Smart = SmartOrSmartID; + if (typeof SmartOrSmartID === "number") { + Smart = global.DApps.Smart.ReadSmart(SmartOrSmartID); + if (!Smart) { + if (bPublic) + throw "Smart does not exist. Error id number: " + SmartOrSmartID; + else + return; + } + } + var EvalContext = GetSmartEvalContext(Smart); + if (!EvalContext.funclist[MethodName] || (bPublic && !EvalContext.publist[MethodName])) { + if (bPublic) + throw "Method '" + MethodName + "' not found in smart contract"; + else + return; + } + var context = {}; + if (PayContext) { + context.BlockNum = BlockNum; + context.BlockHash = CopyArr(Block.Hash); + context.BlockAddrHash = CopyArr(Block.AddrHash); + context.TrNum = TrNum; + context.Account = GET_ACCOUNT(Account); + context.Smart = GET_SMART(Smart); + context.FromNum = PayContext.FromID; + context.ToNum = PayContext.ToID; + context.Description = PayContext.Description; + if (PayContext.Value) + context.Value = { SumCOIN: PayContext.Value.SumCOIN, SumCENT: PayContext.Value.SumCENT }; + } + if (BlockNum === 0) { + context.GetBlockHeader = StaticGetBlockHeader; + context.GetBlockNumDB = StaticGetBlockNumDB; + context.GetSmart = StaticGetSmart; + } + var LocalRunContext = { Block: Block, Smart: Smart, Account: Account, BlockNum: BlockNum, TrNum: TrNum, context: context }; + var RetValue; + var _RunContext = RunContext; + RunContext = LocalRunContext; + EvalContext.funclist.SetContext(RunContext.context); + try { + RetValue = EvalContext.funclist[MethodName](Params); + } + catch (e) { + throw e; + } + finally { + RunContext = _RunContext; + } + return RetValue; +}; + +function GET_ACCOUNT(Obj) { + let Data = Obj; + var GET_PROP = { + get Num() { + return Data.Num; + }, get Currency() { + return Data.Currency; + }, get PubKey() { + return CopyArr(Data.PubKey); + }, get Name() { + return Data.Name; + }, get BlockNumCreate() { + return Data.BlockNumCreate; + }, get Adviser() { + return Data.Adviser; + }, get Smart() { + return Data.Smart; + }, get Value() { + return { SumCOIN: Data.Value.SumCOIN, SumCENT: Data.Value.SumCENT, OperationID: Data.Value.OperationID, Smart: Data.Value.Smart }; + }, + }; + return GET_PROP; +}; + +function GET_SMART(Obj) { + let Data = Obj; + var GET_PROP = { + get Num() { + return Data.Num; + }, get Version() { + return Data.Version; + }, get TokenGenerate() { + return Data.TokenGenerate; + }, get ISIN() { + return Data.ISIN; + }, get Zip() { + return Data.Zip; + }, get BlockNum() { + return Data.BlockNum; + }, get TrNum() { + return Data.TrNum; + }, get IconBlockNum() { + return Data.IconBlockNum; + }, get IconTrNum() { + return Data.IconTrNum; + }, get ShortName() { + return Data.ShortName; + }, get Name() { + return Data.Name; + }, get Description() { + return Data.Description; + }, get Account() { + return Data.Account; + }, get AccountLength() { + return Data.AccountLength; + }, get Owner() { + return Data.Owner; + }, get Code() { + return Data.Code; + }, get HTML() { + return Data.HTML; + }, + }; + return GET_PROP; +}; + +function InitEval() { + $Math.abs = function() { + DO(6); + return Math.abs.apply(Math, arguments); + }; + $Math.acos = function() { + DO(16); + return Math.acos.apply(Math, arguments); + }; + $Math.acosh = function() { + DO(9); + return Math.acosh.apply(Math, arguments); + }; + $Math.asin = function() { + DO(19); + return Math.asin.apply(Math, arguments); + }; + $Math.asinh = function() { + DO(32); + return Math.asinh.apply(Math, arguments); + }; + $Math.atan = function() { + DO(13); + return Math.atan.apply(Math, arguments); + }; + $Math.atanh = function() { + DO(30); + return Math.atanh.apply(Math, arguments); + }; + $Math.atan2 = function() { + DO(15); + return Math.atan2.apply(Math, arguments); + }; + $Math.ceil = function() { + DO(6); + return Math.ceil.apply(Math, arguments); + }; + $Math.cbrt = function() { + DO(22); + return Math.cbrt.apply(Math, arguments); + }; + $Math.expm1 = function() { + DO(18); + return Math.expm1.apply(Math, arguments); + }; + $Math.clz32 = function() { + DO(5); + return Math.clz32.apply(Math, arguments); + }; + $Math.cos = function() { + DO(12); + return Math.cos.apply(Math, arguments); + }; + $Math.cosh = function() { + DO(20); + return Math.cosh.apply(Math, arguments); + }; + $Math.exp = function() { + DO(16); + return Math.exp.apply(Math, arguments); + }; + $Math.floor = function() { + DO(7); + return Math.floor.apply(Math, arguments); + }; + $Math.fround = function() { + DO(6); + return Math.fround.apply(Math, arguments); + }; + $Math.hypot = function() { + DO(56); + return Math.hypot.apply(Math, arguments); + }; + $Math.imul = function() { + DO(3); + return Math.imul.apply(Math, arguments); + }; + $Math.log = function() { + DO(10); + return Math.log.apply(Math, arguments); + }; + $Math.log1p = function() { + DO(23); + return Math.log1p.apply(Math, arguments); + }; + $Math.log2 = function() { + DO(19); + return Math.log2.apply(Math, arguments); + }; + $Math.log10 = function() { + DO(16); + return Math.log10.apply(Math, arguments); + }; + $Math.max = function() { + DO(6); + return Math.max.apply(Math, arguments); + }; + $Math.min = function() { + DO(6); + return Math.min.apply(Math, arguments); + }; + $Math.pow = function() { + DO(40); + return Math.pow.apply(Math, arguments); + }; + $Math.round = function() { + DO(7); + return Math.round.apply(Math, arguments); + }; + $Math.sign = function() { + DO(5); + return Math.sign.apply(Math, arguments); + }; + $Math.sin = function() { + DO(10); + return Math.sin.apply(Math, arguments); + }; + $Math.sinh = function() { + DO(24); + return Math.sinh.apply(Math, arguments); + }; + $Math.sqrt = function() { + DO(6); + return Math.sqrt.apply(Math, arguments); + }; + $Math.tan = function() { + DO(13); + return Math.tan.apply(Math, arguments); + }; + $Math.tanh = function() { + DO(24); + return Math.tanh.apply(Math, arguments); + }; + $Math.trunc = function() { + DO(6); + return Math.trunc.apply(Math, arguments); + }; + $Math.random = function() { + DO(1); + return 0; + }; + Object.freeze($SetValue); + Object.freeze($Send); + Object.freeze($Move); + Object.freeze($Event); + Object.freeze($ReadAccount); + Object.freeze($ReadState); + Object.freeze($WriteState); + Object.freeze($GetMaxAccount); + Object.freeze($ADD); + Object.freeze($SUB); + Object.freeze($ISZERO); + Object.freeze($FLOAT_FROM_COIN); + Object.freeze($COIN_FROM_FLOAT); + Object.freeze($COIN_FROM_STRING); + Object.freeze($GetHexFromArr); + Object.freeze($GetArrFromHex); + Object.freeze($sha); + Object.freeze($isFinite); + Object.freeze($isNaN); + Object.freeze($parseFloat); + Object.freeze($parseInt); + Object.freeze($parseUint); + Object.freeze($String); + Object.freeze($Number); + Object.freeze($Boolean); + var arr = Object.getOwnPropertyNames(JSON); + for (var name of arr) { + $JSON[name] = JSON[name]; + } + FreezeObjectChilds($Math); + Object.freeze($Math); + FreezeObjectChilds($JSON); + Object.freeze($JSON); + FreezeObjectChilds(Number.prototype); + FreezeObjectChilds(String.prototype); + FreezeObjectChilds(Boolean.prototype); + FreezeObjectChilds(Array.prototype); + FreezeObjectChilds(Object.prototype); +}; + +function FreezeObjectChilds(Value) { + var arr = Object.getOwnPropertyNames(Value); + for (var name of arr) { + Object.freeze(Value[name]); + } +}; + +function ChangePrototype() { + var Array_prototype_concat = Array.prototype.concat; + var Array_prototype_toString = Array.prototype.toString; + Array.prototype.concat = function() { + if (RunContext) + throw "Error Access denied: concat"; + else + return Array_prototype_concat.apply(this, arguments); + }; + Array.prototype.toString = function() { + if (RunContext) + throw "Error Access denied: toString"; + else + return Array_prototype_toString.apply(this, arguments); + }; + Array.prototype.toLocaleString = Array.prototype.toString; + Number.prototype.toLocaleString = function() { + return this.toString(); + }; + String.prototype.toLocaleLowerCase = String.prototype.toLowerCase; + String.prototype.toLocaleUpperCase = String.prototype.toUpperCase; + var String_prototype_localeCompare = String.prototype.localeCompare; + String.prototype.localeCompare = function() { + if (RunContext) + throw "Error Access denied: localeCompare"; + else + return String_prototype_localeCompare.apply(this, arguments); + }; + var String_prototype_match = String.prototype.match; + String.prototype.match = function() { + if (RunContext) + throw "Error Access denied: match"; + else + return String_prototype_match.apply(this, arguments); + }; + var String_prototype_repeat = String.prototype.repeat; + String.prototype.repeat = function() { + if (RunContext) + throw "Error Access denied: repeat"; + else + return String_prototype_repeat.apply(this, arguments); + }; + var String_prototype_search = String.prototype.search; + String.prototype.search = function() { + if (RunContext) + throw "Error Access denied: search"; + else + return String_prototype_search.apply(this, arguments); + }; + var String_prototype_padStart = String.prototype.padStart; + String.prototype.padStart = function() { + if (RunContext) + throw "Error Access denied: padStart"; + else + return String_prototype_padStart.apply(this, arguments); + }; + var String_prototype_padEnd = String.prototype.padEnd; + String.prototype.padEnd = function() { + if (RunContext) + throw "Error Access denied: padEnd"; + else + return String_prototype_padEnd.apply(this, arguments); + }; + String.prototype.right = function(count) { + if (this.length > count) + return this.substr(this.length - count, count); + else + return this.substr(0, this.length); + }; +}; +const MAX_LENGTH_STRING = 5000; +const $Math: any = {}; +const $JSON: any = {}; + +function DO(Count) { + global.TickCounter -= Count; + if (global.TickCounter < 0) + throw new Error("Stop the execution code. The limit of ticks is over."); +}; + +function $SetValue(ID, CoinSum) { + DO(3000); + ID = ParseNum(ID); + if (!RunContext.Smart.TokenGenerate) { + throw "The smart-contract is not token generate, access to change values is denied"; + } + var ToData = global.DApps.Accounts.ReadStateTR(ID); + if (!ToData) { + throw "Account does not exist.Error id number: " + ID; + } + if (ToData.Currency !== RunContext.Smart.Num) { + throw "The account currency does not belong to the smart-contract, access to change values is denied"; + } + if (typeof CoinSum === "number") { + CoinSum = COIN_FROM_FLOAT(CoinSum); + } + if (CoinSum.SumCENT >= 1e9) { + throw "ERROR SumCENT>=1e9"; + } + if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) { + throw "ERROR Sum<0"; + } + ToData.Value.SumCOIN = Math.trunc(CoinSum.SumCOIN); + ToData.Value.SumCENT = Math.trunc(CoinSum.SumCENT); + global.DApps.Accounts.WriteStateTR(ToData, RunContext.TrNum); + return true; +}; + +function $Send(ToID, CoinSum, Description) { + DO(3000); + ToID = ParseNum(ToID); + if (typeof CoinSum === "number") + CoinSum = COIN_FROM_FLOAT(CoinSum); + if (CoinSum.SumCENT >= 1e9) { + throw "ERROR SumCENT>=1e9"; + } + if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) { + throw "ERROR Sum<0"; + } + var ToData = global.DApps.Accounts.ReadStateTR(ToID); + if (RunContext.Account.Currency !== ToData.Currency) { + throw "Different currencies"; + } + global.DApps.Accounts.SendMoneyTR(RunContext.Block, RunContext.Account.Num, ToID, CoinSum, RunContext.BlockNum, RunContext.TrNum, + Description, Description, 1); +}; + +function $Move(FromID, ToID, CoinSum, Description) { + DO(3000); + FromID = ParseNum(FromID); + ToID = ParseNum(ToID); + var FromData = global.DApps.Accounts.ReadStateTR(FromID); + var ToData = global.DApps.Accounts.ReadStateTR(ToID); + if (FromData.Currency !== ToData.Currency) { + throw "Different currencies"; + } + if (FromData.Value.Smart !== RunContext.Smart.Num) { + throw "The account smart does not belong to the smart-contract, access is denied"; + } + if (typeof CoinSum === "number") { + CoinSum = COIN_FROM_FLOAT(CoinSum); + } + if (CoinSum.SumCENT >= 1e9) { + throw "ERROR SumCENT>=1e9"; + } + if (CoinSum.SumCOIN < 0 || CoinSum.SumCENT < 0) { + throw "ERROR Sum<0"; + } + CoinSum.SumCOIN = Math.trunc(CoinSum.SumCOIN); + CoinSum.SumCENT = Math.trunc(CoinSum.SumCENT); + global.DApps.Accounts.SendMoneyTR(RunContext.Block, FromID, ToID, CoinSum, RunContext.BlockNum, RunContext.TrNum, Description, Description, + 1); +}; + +function $Event(Description) { + DO(50); + global.DApps.Accounts.DBChanges.TREvent.push({ + Description: Description, Smart: RunContext.Smart.Num, Account: RunContext.Account.Num, + BlockNum: RunContext.BlockNum, TrNum: RunContext.TrNum + }); + if (global.DebugEvent) + global.DebugEvent(Description); + if (global.CurTrItem) { + global.ToLogClient(Description, global.CurTrItem, false); + } +}; + +function $ReadAccount(ID) { + DO(900); + ID = ParseNum(ID); + var Account = global.DApps.Accounts.ReadStateTR(ID); + if (!Account) + throw "Error read account Num: " + ID; + return GET_ACCOUNT(Account); +}; + +function $ReadState(ID) { + DO(900); + ID = ParseNum(ID); + var Account = global.DApps.Accounts.ReadStateTR(ID); + if (!Account) + throw "Error read state account Num: " + ID; + var Smart; + if (Account.Value.Smart === RunContext.Smart.Num) { + Smart = RunContext.Smart; + } + else { + DO(100); + var Smart = global.DApps.Smart.ReadSmart(Account.Value.Smart); + if (!Smart) { + throw "Error smart ID: " + Account.Value.Smart; + } + } + var Data; + if (Smart.StateFormat) + Data = global.BufLib.GetObjectFromBuffer(Account.Value.Data, Smart.StateFormat, Smart.WorkStruct, 1); + else + Data = {}; + if (typeof Data === "object") + Data.Num = ID; + return Data; +}; + +function $WriteState(Obj, ID) { + DO(3000); + if (ID === undefined) + ID = Obj.Num; + ID = ParseNum(ID); + var Account = global.DApps.Accounts.ReadStateTR(ID); + if (!Account) + throw "Error write account Num: " + ID; + var Smart = RunContext.Smart; + if (Account.Value.Smart !== Smart.Num) { + throw "The account does not belong to the smart-contract, access to change state is denied"; + } + Account.Value.Data = global.BufLib.GetBufferFromObject(Obj, Smart.StateFormat, 80, Smart.WorkStruct, 1); + global.DApps.Accounts.WriteStateTR(Account, RunContext.TrNum); +}; + +function $GetMaxAccount() { + DO(20); + return global.DApps.Accounts.DBChanges.TRMaxAccount; +}; + +function $ADD(Coin, Value2) { + DO(5); + return ADD(Coin, Value2); +}; + +function $SUB(Coin, Value2) { + DO(5); + return SUB(Coin, Value2); +}; + +function $ISZERO(Coin) { + DO(5); + if (Coin.SumCOIN === 0 && Coin.SumCENT === 0) + return true; + else + return false; +}; + +function $FLOAT_FROM_COIN(Coin) { + DO(5); + return FLOAT_FROM_COIN(Coin); +}; + +function $COIN_FROM_FLOAT(Sum) { + DO(20); + return COIN_FROM_FLOAT(Sum); +}; + +function $COIN_FROM_STRING(Sum) { + DO(20); + return COIN_FROM_STRING(Sum); +}; + +function $require(SmartNum) { + DO(2000); + SmartNum = ParseNum(SmartNum); + var Smart = global.DApps.Smart.ReadSmart(SmartNum); + if (!Smart) { + throw "Smart does not exist. Error id number: " + SmartNum; + } + var EvalContext = GetSmartEvalContext(Smart); + EvalContext.funclist.SetContext(RunContext.context); + return EvalContext.publist; +}; + +function $GetHexFromArr(Arr) { + DO(20); + return global.GetHexFromArr(Arr); +}; + +function $GetArrFromHex(Str) { + DO(20); + return global.GetArrFromHex(Str); +}; + +function $sha(Str) { + DO(1000); + return global.shaarr(Str); +}; + +function $isFinite(a) { + DO(5); + return isFinite(a); +}; + +function $isNaN(a) { + DO(5); + return isNaN(a); +}; + +function $parseFloat(a) { + DO(10); + var Num = parseFloat(a); + if (!Num) + Num = 0; + if (isNaN(Num)) + Num = 0; + return Num; +}; + +function $parseInt(a) { + DO(10); + var Num = parseInt(a); + if (!Num) + Num = 0; + if (isNaN(Num)) + Num = 0; + return Num; +}; + +function $parseUint(a) { + DO(10); + return ParseNum(a); +}; + +function $String(a) { + DO(5); + return String(a); +}; + +function $Number(a) { + DO(5); + return Number(a); +}; + +function $Boolean(a) { + DO(5); + return Boolean(a); +}; + +function CHKL(Str) { + if (typeof Str === "string" && Str.length > MAX_LENGTH_STRING) + throw new Error("Invalid string length:" + Str.length); + return Str; +}; +var BlockRandomInit; +var m_w = 123456789; +var m_z = 987654321; +var mask = 0xffffffff; + +function MathRandom() { + DO(5); + + function seed(i) { + m_w = i; + m_z = 987654321; + }; + + function random() { + m_z = (36969 * (m_z & 65535) + (m_z >> 16)) & mask; + m_w = (18000 * (m_w & 65535) + (m_w >> 16)) & mask; + var result = ((m_z << 16) + m_w) & mask; + result /= 4294967296; + return result + 0.5; + }; + if (BlockRandomInit === RunContext.Block.BlockNum) + return random(); + BlockRandomInit = RunContext.Block.BlockNum; + RunContext.Block.Hash; + return 0; +}; + +function StaticGetBlockHeader(BlockNum) { + DO(100); + return global.SERVER.ReadBlockHeaderDB(BlockNum); +}; + +function StaticGetBlockNumDB() { + return global.SERVER.GetMaxNumBlockDB(); +}; + +function StaticGetSmart(Num) { + DO(100); + var Smart = global.DApps.Smart.ReadSmart(Num); + return GET_SMART(Smart); +}; +ChangePrototype(); +InitEval(); +module.exports = SmartApp; +var smartApp = new SmartApp; +global.DApps["Smart"] = smartApp; +global.DAppByType[TYPE_TRANSACTION_SMART_CREATE] = smartApp; +global.DAppByType[global.TYPE_TRANSACTION_SMART_RUN] = smartApp; +global.DAppByType[TYPE_TRANSACTION_SMART_CHANGE] = smartApp; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..43109ed --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "outDir": "dist", + "target": "es5" + }, + "include": [ + "./src/**/*", + "global.d.ts" + ] +} \ No newline at end of file