diff --git a/.pnp.cjs b/.pnp.cjs index 43971ae62d3..708e5c0c6f7 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -59,10 +59,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "name": "@dashevo/dpp",\ "reference": "workspace:packages/js-dpp"\ },\ - {\ - "name": "@dashevo/drive",\ - "reference": "workspace:packages/js-drive"\ - },\ {\ "name": "@dashevo/grpc-common",\ "reference": "workspace:packages/js-grpc-common"\ @@ -75,10 +71,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "name": "@dashevo/platform-test-suite",\ "reference": "workspace:packages/platform-test-suite"\ },\ - {\ - "name": "@dashevo/rs-drive",\ - "reference": "workspace:packages/rs-drive-nodejs"\ - },\ {\ "name": "@dashevo/wallet-lib",\ "reference": "workspace:packages/wallet-lib"\ @@ -103,13 +95,11 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@dashevo/dashpay-contract", ["workspace:packages/dashpay-contract"]],\ ["@dashevo/dpns-contract", ["workspace:packages/dpns-contract"]],\ ["@dashevo/dpp", ["workspace:packages/js-dpp"]],\ - ["@dashevo/drive", ["workspace:packages/js-drive"]],\ ["@dashevo/feature-flags-contract", ["workspace:packages/feature-flags-contract"]],\ ["@dashevo/grpc-common", ["workspace:packages/js-grpc-common"]],\ ["@dashevo/masternode-reward-shares-contract", ["workspace:packages/masternode-reward-shares-contract"]],\ ["@dashevo/platform", ["workspace:."]],\ ["@dashevo/platform-test-suite", ["workspace:packages/platform-test-suite"]],\ - ["@dashevo/rs-drive", ["workspace:packages/rs-drive-nodejs"]],\ ["@dashevo/wallet-lib", ["workspace:packages/wallet-lib"]],\ ["@dashevo/wasm-dpp", ["workspace:packages/wasm-dpp"]],\ ["@dashevo/withdrawals-contract", ["workspace:packages/withdrawals-contract"]],\ @@ -2278,18 +2268,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@dashevo/abci", [\ - ["https://github.com/dashpay/js-abci.git#commit=09f72120bc2059144f72eb7a246d632ead3fc3c6", {\ - "packageLocation": "./.yarn/cache/@dashevo-abci-https-9fb519f2ca-aaf41ab7fa.zip/node_modules/@dashevo/abci/",\ - "packageDependencies": [\ - ["@dashevo/abci", "https://github.com/dashpay/js-abci.git#commit=09f72120bc2059144f72eb7a246d632ead3fc3c6"],\ - ["@dashevo/protobufjs", "npm:6.10.5"],\ - ["bl", "npm:1.2.3"],\ - ["protocol-buffers-encodings", "npm:1.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@dashevo/bench-suite", [\ ["workspace:packages/bench-suite", {\ "packageLocation": "./packages/bench-suite/",\ @@ -2652,65 +2630,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "SOFT"\ }]\ ]],\ - ["@dashevo/drive", [\ - ["workspace:packages/js-drive", {\ - "packageLocation": "./packages/js-drive/",\ - "packageDependencies": [\ - ["@dashevo/drive", "workspace:packages/js-drive"],\ - ["@dashevo/abci", "https://github.com/dashpay/js-abci.git#commit=09f72120bc2059144f72eb7a246d632ead3fc3c6"],\ - ["@dashevo/dapi-grpc", "workspace:packages/dapi-grpc"],\ - ["@dashevo/dashcore-lib", "npm:0.20.0"],\ - ["@dashevo/dashd-rpc", "npm:18.2.0"],\ - ["@dashevo/dashpay-contract", "workspace:packages/dashpay-contract"],\ - ["@dashevo/dp-services-ctl", "https://github.com/dashevo/js-dp-services-ctl.git#commit=3976076b0018c5b4632ceda4c752fc597f27a640"],\ - ["@dashevo/dpns-contract", "workspace:packages/dpns-contract"],\ - ["@dashevo/dpp", "workspace:packages/js-dpp"],\ - ["@dashevo/feature-flags-contract", "workspace:packages/feature-flags-contract"],\ - ["@dashevo/grpc-common", "workspace:packages/js-grpc-common"],\ - ["@dashevo/masternode-reward-shares-contract", "workspace:packages/masternode-reward-shares-contract"],\ - ["@dashevo/rs-drive", "workspace:packages/rs-drive-nodejs"],\ - ["@dashevo/withdrawals-contract", "workspace:packages/withdrawals-contract"],\ - ["@types/pino", "npm:6.3.12"],\ - ["ajv", "npm:8.8.1"],\ - ["ajv-keywords", "virtual:34fbe5a7dba3086dcbcce8a7faed986b10f7a208f11db70499feb2c1afd76e24089e5b95f9e3b937e89512de1cf4937177cc2000303a1e908baefc73362a7d48#npm:5.0.0"],\ - ["awilix", "npm:4.3.4"],\ - ["babel-eslint", "virtual:27dae49067a60fa65fec6e1c3adad1497d0dda3f71eda711624109131ff3b7d1061a20f55e89b5a0a219da1f7a0a1a0a76bc414d36870315bd60acf5bdcb7f55#npm:10.1.0"],\ - ["blake3", "npm:2.1.7"],\ - ["bs58", "npm:4.0.1"],\ - ["cbor", "npm:8.1.0"],\ - ["chai", "npm:4.3.4"],\ - ["chai-as-promised", "virtual:58fb68f2aed20e5e0f2e48520ab903ae9bb3440369bfd5e912034003cf27c5aae368649fc5620dd2acbed578131f3a0975e75b838d77d12335fb0412e24026c6#npm:7.1.1"],\ - ["chai-string", "virtual:58fb68f2aed20e5e0f2e48520ab903ae9bb3440369bfd5e912034003cf27c5aae368649fc5620dd2acbed578131f3a0975e75b838d77d12335fb0412e24026c6#npm:1.5.0"],\ - ["chalk", "npm:4.1.2"],\ - ["dirty-chai", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:2.0.1"],\ - ["dotenv-expand", "npm:5.1.0"],\ - ["dotenv-safe", "npm:8.2.0"],\ - ["eslint", "npm:7.32.0"],\ - ["eslint-config-airbnb-base", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:14.2.1"],\ - ["eslint-plugin-import", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:2.25.3"],\ - ["find-my-way", "npm:2.2.5"],\ - ["js-merkle", "npm:0.1.5"],\ - ["levelup", "npm:4.4.0"],\ - ["lodash", "npm:4.17.21"],\ - ["long", "npm:5.2.0"],\ - ["memdown", "npm:5.1.0"],\ - ["mocha", "npm:9.2.2"],\ - ["moment", "npm:2.29.4"],\ - ["node-graceful", "npm:3.1.0"],\ - ["nyc", "npm:15.1.0"],\ - ["pino", "npm:6.13.3"],\ - ["pino-multi-stream", "npm:5.3.0"],\ - ["pino-pretty", "npm:4.8.0"],\ - ["rimraf", "npm:3.0.2"],\ - ["setimmediate", "npm:1.0.5"],\ - ["sinon", "npm:11.1.2"],\ - ["sinon-chai", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:3.7.0"],\ - ["through2", "npm:3.0.2"],\ - ["zeromq", "npm:5.2.8"]\ - ],\ - "linkType": "SOFT"\ - }]\ - ]],\ ["@dashevo/feature-flags-contract", [\ ["workspace:packages/feature-flags-contract", {\ "packageLocation": "./packages/feature-flags-contract/",\ @@ -2909,30 +2828,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@dashevo/rs-drive", [\ - ["workspace:packages/rs-drive-nodejs", {\ - "packageLocation": "./packages/rs-drive-nodejs/",\ - "packageDependencies": [\ - ["@dashevo/rs-drive", "workspace:packages/rs-drive-nodejs"],\ - ["@dashevo/dashcore-lib", "npm:0.20.0"],\ - ["@dashevo/dpp", "workspace:packages/js-dpp"],\ - ["@dashevo/withdrawals-contract", "workspace:packages/withdrawals-contract"],\ - ["cargo-cp-artifact", "npm:0.1.6"],\ - ["cbor", "npm:8.1.0"],\ - ["chai", "npm:4.3.4"],\ - ["dirty-chai", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:2.0.1"],\ - ["eslint", "npm:7.32.0"],\ - ["eslint-config-airbnb-base", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:14.2.1"],\ - ["eslint-plugin-import", "virtual:12a596dc9572e25ce715d3736dc74b317c5ca5cfb3b4f67864b1e76b3a401006f84d381aaf975bb5b4da9cafac5125e6869fc78d5202f4c95780c81479112f32#npm:2.25.3"],\ - ["mocha", "npm:9.2.2"],\ - ["neon-cli", "npm:0.10.1"],\ - ["neon-load-or-build", "npm:2.2.2"],\ - ["neon-tag-prebuild", "https://github.com/shumkov/neon-tag-prebuild.git#commit=a429834da27432b129eceb737e4d2b3f03fa5496"],\ - ["ultra-runner", "npm:3.10.5"]\ - ],\ - "linkType": "SOFT"\ - }]\ - ]],\ ["@dashevo/wallet-lib", [\ ["workspace:packages/wallet-lib", {\ "packageLocation": "./packages/wallet-lib/",\ @@ -3185,15 +3080,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@hapi/bourne", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/@hapi-bourne-npm-2.0.0-8eeda7e0a2-2ea0922101.zip/node_modules/@hapi/bourne/",\ - "packageDependencies": [\ - ["@hapi/bourne", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@humanwhocodes/config-array", [\ ["npm:0.5.0", {\ "packageLocation": "./.yarn/cache/@humanwhocodes-config-array-npm-0.5.0-5ded120470-44ee6a9f05.zip/node_modules/@humanwhocodes/config-array/",\ @@ -4390,40 +4276,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["@types/pino", [\ - ["npm:6.3.12", {\ - "packageLocation": "./.yarn/cache/@types-pino-npm-6.3.12-19c7982858-8017351466.zip/node_modules/@types/pino/",\ - "packageDependencies": [\ - ["@types/pino", "npm:6.3.12"],\ - ["@types/node", "npm:17.0.21"],\ - ["@types/pino-pretty", "npm:4.7.3"],\ - ["@types/pino-std-serializers", "npm:2.4.1"],\ - ["sonic-boom", "npm:2.3.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@types/pino-pretty", [\ - ["npm:4.7.3", {\ - "packageLocation": "./.yarn/cache/@types-pino-pretty-npm-4.7.3-5ebf57cfd2-40fe67e73d.zip/node_modules/@types/pino-pretty/",\ - "packageDependencies": [\ - ["@types/pino-pretty", "npm:4.7.3"],\ - ["@types/node", "npm:17.0.21"],\ - ["@types/pino", "npm:6.3.12"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["@types/pino-std-serializers", [\ - ["npm:2.4.1", {\ - "packageLocation": "./.yarn/cache/@types-pino-std-serializers-npm-2.4.1-e7c36178c0-a156e25882.zip/node_modules/@types/pino-std-serializers/",\ - "packageDependencies": [\ - ["@types/pino-std-serializers", "npm:2.4.1"],\ - ["@types/node", "npm:17.0.21"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["@types/qs", [\ ["npm:6.9.7", {\ "packageLocation": "./.yarn/cache/@types-qs-npm-6.9.7-4a3e6ca0d0-7fd6f9c250.zip/node_modules/@types/qs/",\ @@ -5446,27 +5298,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "SOFT"\ }],\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/ajv-keywords-npm-5.0.0-50b946aaa2-239dd46383.zip/node_modules/ajv-keywords/",\ - "packageDependencies": [\ - ["ajv-keywords", "npm:5.0.0"]\ - ],\ - "linkType": "SOFT"\ - }],\ - ["virtual:34fbe5a7dba3086dcbcce8a7faed986b10f7a208f11db70499feb2c1afd76e24089e5b95f9e3b937e89512de1cf4937177cc2000303a1e908baefc73362a7d48#npm:5.0.0", {\ - "packageLocation": "./.yarn/__virtual__/ajv-keywords-virtual-75ea4b6cf0/0/cache/ajv-keywords-npm-5.0.0-50b946aaa2-239dd46383.zip/node_modules/ajv-keywords/",\ - "packageDependencies": [\ - ["ajv-keywords", "virtual:34fbe5a7dba3086dcbcce8a7faed986b10f7a208f11db70499feb2c1afd76e24089e5b95f9e3b937e89512de1cf4937177cc2000303a1e908baefc73362a7d48#npm:5.0.0"],\ - ["@types/ajv", null],\ - ["ajv", "npm:8.8.1"],\ - ["fast-deep-equal", "npm:3.1.3"]\ - ],\ - "packagePeers": [\ - "@types/ajv",\ - "ajv"\ - ],\ - "linkType": "HARD"\ - }],\ ["virtual:f84d18c473fad3c01e1cf352f81ad13de804ca40da5bf6e752464a2e78dcb097ad579b06da5ff33a55ba9957fb9c74909b99fc5e215420a3f9b5dc87ad71363b#npm:3.5.2", {\ "packageLocation": "./.yarn/__virtual__/ajv-keywords-virtual-11d24a6cf1/0/cache/ajv-keywords-npm-3.5.2-0e391b70e2-7dc5e59316.zip/node_modules/ajv-keywords/",\ "packageDependencies": [\ @@ -5703,35 +5534,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["args", [\ - ["npm:5.0.1", {\ - "packageLocation": "./.yarn/cache/args-npm-5.0.1-cd7b0f9dcc-51e2a05f32.zip/node_modules/args/",\ - "packageDependencies": [\ - ["args", "npm:5.0.1"],\ - ["camelcase", "npm:5.0.0"],\ - ["chalk", "npm:2.4.2"],\ - ["leven", "npm:2.1.0"],\ - ["mri", "npm:1.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["array-back", [\ - ["npm:3.1.0", {\ - "packageLocation": "./.yarn/cache/array-back-npm-3.1.0-a52d25f5a3-7205004fcd.zip/node_modules/array-back/",\ - "packageDependencies": [\ - ["array-back", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:4.0.2", {\ - "packageLocation": "./.yarn/cache/array-back-npm-4.0.2-f735073f8f-f306032707.zip/node_modules/array-back/",\ - "packageDependencies": [\ - ["array-back", "npm:4.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["array-buffer-byte-length", [\ ["npm:1.0.0", {\ "packageLocation": "./.yarn/cache/array-buffer-byte-length-npm-1.0.0-331671f28a-044e101ce1.zip/node_modules/array-buffer-byte-length/",\ @@ -5920,15 +5722,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["atomic-sleep", [\ - ["npm:1.0.0", {\ - "packageLocation": "./.yarn/cache/atomic-sleep-npm-1.0.0-17d8a762a3-b95275afb2.zip/node_modules/atomic-sleep/",\ - "packageDependencies": [\ - ["atomic-sleep", "npm:1.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["available-typed-arrays", [\ ["npm:1.0.5", {\ "packageLocation": "./.yarn/cache/available-typed-arrays-npm-1.0.5-88f321e4d3-20eb47b3ce.zip/node_modules/available-typed-arrays/",\ @@ -6276,15 +6069,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["bl", [\ - ["npm:1.2.3", {\ - "packageLocation": "./.yarn/cache/bl-npm-1.2.3-49c4213ca5-123f097989.zip/node_modules/bl/",\ - "packageDependencies": [\ - ["bl", "npm:1.2.3"],\ - ["readable-stream", "npm:2.3.7"],\ - ["safe-buffer", "npm:5.2.1"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:2.2.1", {\ "packageLocation": "./.yarn/cache/bl-npm-2.2.1-f294e1ea12-4f5d9b2589.zip/node_modules/bl/",\ "packageDependencies": [\ @@ -6743,13 +6527,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["camelcase", [\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/camelcase-npm-5.0.0-c808398846-8bfe920e04.zip/node_modules/camelcase/",\ - "packageDependencies": [\ - ["camelcase", "npm:5.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:5.3.1", {\ "packageLocation": "./.yarn/cache/camelcase-npm-5.3.1-5db8af62c5-e6effce26b.zip/node_modules/camelcase/",\ "packageDependencies": [\ @@ -6797,15 +6574,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["cargo-cp-artifact", [\ - ["npm:0.1.6", {\ - "packageLocation": "./.yarn/cache/cargo-cp-artifact-npm-0.1.6-fe2dd40a8f-2f5d2f3e73.zip/node_modules/cargo-cp-artifact/",\ - "packageDependencies": [\ - ["cargo-cp-artifact", "npm:0.1.6"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["cbor", [\ ["npm:8.1.0", {\ "packageLocation": "./.yarn/cache/cbor-npm-8.1.0-c1a4d6266a-a90338435d.zip/node_modules/cbor/",\ @@ -7333,42 +7101,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["command-line-args", [\ - ["npm:5.2.1", {\ - "packageLocation": "./.yarn/cache/command-line-args-npm-5.2.1-093a68d295-e759519087.zip/node_modules/command-line-args/",\ - "packageDependencies": [\ - ["command-line-args", "npm:5.2.1"],\ - ["array-back", "npm:3.1.0"],\ - ["find-replace", "npm:3.0.0"],\ - ["lodash.camelcase", "npm:4.3.0"],\ - ["typical", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["command-line-commands", [\ - ["npm:3.0.2", {\ - "packageLocation": "./.yarn/cache/command-line-commands-npm-3.0.2-782bf8a159-2cf5409af0.zip/node_modules/command-line-commands/",\ - "packageDependencies": [\ - ["command-line-commands", "npm:3.0.2"],\ - ["array-back", "npm:4.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["command-line-usage", [\ - ["npm:6.1.3", {\ - "packageLocation": "./.yarn/cache/command-line-usage-npm-6.1.3-145c2dabe1-8261d4e553.zip/node_modules/command-line-usage/",\ - "packageDependencies": [\ - ["command-line-usage", "npm:6.1.3"],\ - ["array-back", "npm:4.0.2"],\ - ["chalk", "npm:2.4.2"],\ - ["table-layout", "npm:1.0.2"],\ - ["typical", "npm:5.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["commander", [\ ["npm:2.20.3", {\ "packageLocation": "./.yarn/cache/commander-npm-2.20.3-d8dcbaa39b-ab8c07884e.zip/node_modules/commander/",\ @@ -9655,15 +9387,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["fast-decode-uri-component", [\ - ["npm:1.0.1", {\ - "packageLocation": "./.yarn/cache/fast-decode-uri-component-npm-1.0.1-578ba9fecf-427a48fe09.zip/node_modules/fast-decode-uri-component/",\ - "packageDependencies": [\ - ["fast-decode-uri-component", "npm:1.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["fast-deep-equal", [\ ["npm:3.1.3", {\ "packageLocation": "./.yarn/cache/fast-deep-equal-npm-3.1.3-790edcfcf5-e21a9d8d84.zip/node_modules/fast-deep-equal/",\ @@ -9722,24 +9445,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["fast-redact", [\ - ["npm:3.0.2", {\ - "packageLocation": "./.yarn/cache/fast-redact-npm-3.0.2-98d6f1d433-f4ffdf48f1.zip/node_modules/fast-redact/",\ - "packageDependencies": [\ - ["fast-redact", "npm:3.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["fast-safe-stringify", [\ - ["npm:2.1.1", {\ - "packageLocation": "./.yarn/cache/fast-safe-stringify-npm-2.1.1-7ce89033ca-a851cbddc4.zip/node_modules/fast-safe-stringify/",\ - "packageDependencies": [\ - ["fast-safe-stringify", "npm:2.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["fastest-levenshtein", [\ ["npm:1.0.12", {\ "packageLocation": "./.yarn/cache/fastest-levenshtein-npm-1.0.12-a32b4ef51e-e1a013698d.zip/node_modules/fastest-levenshtein/",\ @@ -9749,15 +9454,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["fastify-warning", [\ - ["npm:0.2.0", {\ - "packageLocation": "./.yarn/cache/fastify-warning-npm-0.2.0-f9c53563fc-c19ebccf54.zip/node_modules/fastify-warning/",\ - "packageDependencies": [\ - ["fastify-warning", "npm:0.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["fastq", [\ ["npm:1.13.0", {\ "packageLocation": "./.yarn/cache/fastq-npm-1.13.0-a45963881c-32cf15c29a.zip/node_modules/fastq/",\ @@ -9854,28 +9550,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["find-my-way", [\ - ["npm:2.2.5", {\ - "packageLocation": "./.yarn/cache/find-my-way-npm-2.2.5-3bef2f72f0-9330349565.zip/node_modules/find-my-way/",\ - "packageDependencies": [\ - ["find-my-way", "npm:2.2.5"],\ - ["fast-decode-uri-component", "npm:1.0.1"],\ - ["safe-regex2", "npm:2.0.0"],\ - ["semver-store", "npm:0.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["find-replace", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/find-replace-npm-3.0.0-686bd07d28-6b04bcfd79.zip/node_modules/find-replace/",\ - "packageDependencies": [\ - ["find-replace", "npm:3.0.0"],\ - ["array-back", "npm:3.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["find-up", [\ ["npm:2.1.0", {\ "packageLocation": "./.yarn/cache/find-up-npm-2.1.0-9f6cb1765c-43284fe4da.zip/node_modules/find-up/",\ @@ -9955,15 +9629,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["flatstr", [\ - ["npm:1.0.12", {\ - "packageLocation": "./.yarn/cache/flatstr-npm-1.0.12-4311d37d16-e1bb562c94.zip/node_modules/flatstr/",\ - "packageDependencies": [\ - ["flatstr", "npm:1.0.12"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["flatted", [\ ["npm:3.2.7", {\ "packageLocation": "./.yarn/cache/flatted-npm-3.2.7-0da10b7c56-427633049d.zip/node_modules/flatted/",\ @@ -10308,16 +9973,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["git-config", [\ - ["npm:0.0.7", {\ - "packageLocation": "./.yarn/cache/git-config-npm-0.0.7-fd037544b3-99a7e20306.zip/node_modules/git-config/",\ - "packageDependencies": [\ - ["git-config", "npm:0.0.7"],\ - ["iniparser", "npm:1.0.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["git-raw-commits", [\ ["npm:2.0.10", {\ "packageLocation": "./.yarn/cache/git-raw-commits-npm-2.0.10-66e3a843dd-66e2d7b4cd.zip/node_modules/git-raw-commits/",\ @@ -11117,36 +10772,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["iniparser", [\ - ["npm:1.0.5", {\ - "packageLocation": "./.yarn/cache/iniparser-npm-1.0.5-446fd8dfb0-eba0ec2d68.zip/node_modules/iniparser/",\ - "packageDependencies": [\ - ["iniparser", "npm:1.0.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["inquirer", [\ - ["npm:7.3.3", {\ - "packageLocation": "./.yarn/cache/inquirer-npm-7.3.3-9e86782610-4d387fc1eb.zip/node_modules/inquirer/",\ - "packageDependencies": [\ - ["inquirer", "npm:7.3.3"],\ - ["ansi-escapes", "npm:4.3.2"],\ - ["chalk", "npm:4.1.2"],\ - ["cli-cursor", "npm:3.1.0"],\ - ["cli-width", "npm:3.0.0"],\ - ["external-editor", "npm:3.1.0"],\ - ["figures", "npm:3.2.0"],\ - ["lodash", "npm:4.17.21"],\ - ["mute-stream", "npm:0.0.8"],\ - ["run-async", "npm:2.4.1"],\ - ["rxjs", "npm:6.6.7"],\ - ["string-width", "npm:4.2.3"],\ - ["strip-ansi", "npm:6.0.1"],\ - ["through", "npm:2.3.8"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:8.2.0", {\ "packageLocation": "./.yarn/cache/inquirer-npm-8.2.0-2bfa19a3d0-861d1a9324.zip/node_modules/inquirer/",\ "packageDependencies": [\ @@ -11918,13 +11544,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["jmespath", [\ - ["npm:0.15.0", {\ - "packageLocation": "./.yarn/cache/jmespath-npm-0.15.0-df80ed6dd1-353bb9e69c.zip/node_modules/jmespath/",\ - "packageDependencies": [\ - ["jmespath", "npm:0.15.0"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:0.16.0", {\ "packageLocation": "./.yarn/cache/jmespath-npm-0.16.0-d47535c65a-2d602493a1.zip/node_modules/jmespath/",\ "packageDependencies": [\ @@ -11933,15 +11552,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["joycon", [\ - ["npm:2.2.5", {\ - "packageLocation": "./.yarn/cache/joycon-npm-2.2.5-fff23ab519-930bb748c0.zip/node_modules/joycon/",\ - "packageDependencies": [\ - ["joycon", "npm:2.2.5"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["js-base64", [\ ["npm:2.6.4", {\ "packageLocation": "./.yarn/cache/js-base64-npm-2.6.4-569350f803-5f4084078d.zip/node_modules/js-base64/",\ @@ -12544,15 +12154,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["leven", [\ - ["npm:2.1.0", {\ - "packageLocation": "./.yarn/cache/leven-npm-2.1.0-19f0a16606-f7b4a01b15.zip/node_modules/leven/",\ - "packageDependencies": [\ - ["leven", "npm:2.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["levn", [\ ["npm:0.3.0", {\ "packageLocation": "./.yarn/cache/levn-npm-0.3.0-48d774b1c2-0d084a5242.zip/node_modules/levn/",\ @@ -13018,15 +12619,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["make-promises-safe", [\ - ["npm:5.1.0", {\ - "packageLocation": "./.yarn/cache/make-promises-safe-npm-5.1.0-7a3dd5a2e9-6e59ed8c56.zip/node_modules/make-promises-safe/",\ - "packageDependencies": [\ - ["make-promises-safe", "npm:5.1.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["map-obj", [\ ["npm:1.0.1", {\ "packageLocation": "./.yarn/cache/map-obj-npm-1.0.1-fa55100fac-9949e7baec.zip/node_modules/map-obj/",\ @@ -13559,15 +13151,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["moment", [\ - ["npm:2.29.4", {\ - "packageLocation": "./.yarn/cache/moment-npm-2.29.4-902943305d-0ec3f9c2bc.zip/node_modules/moment/",\ - "packageDependencies": [\ - ["moment", "npm:2.29.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["mongodb", [\ ["npm:3.7.3", {\ "packageLocation": "./.yarn/cache/mongodb-npm-3.7.3-c479129d1e-ef7690fe6e.zip/node_modules/mongodb/",\ @@ -13616,15 +13199,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["mri", [\ - ["npm:1.1.4", {\ - "packageLocation": "./.yarn/cache/mri-npm-1.1.4-d22a399f26-e65b9aed3b.zip/node_modules/mri/",\ - "packageDependencies": [\ - ["mri", "npm:1.1.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["ms", [\ ["npm:2.0.0", {\ "packageLocation": "./.yarn/cache/ms-npm-2.0.0-9e1101a471-0e6a22b8b7.zip/node_modules/ms/",\ @@ -13750,49 +13324,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["neon-cli", [\ - ["npm:0.10.1", {\ - "packageLocation": "./.yarn/cache/neon-cli-npm-0.10.1-f6ee1b3cec-284e7ec9e3.zip/node_modules/neon-cli/",\ - "packageDependencies": [\ - ["neon-cli", "npm:0.10.1"],\ - ["chalk", "npm:4.1.2"],\ - ["command-line-args", "npm:5.2.1"],\ - ["command-line-commands", "npm:3.0.2"],\ - ["command-line-usage", "npm:6.1.3"],\ - ["git-config", "npm:0.0.7"],\ - ["handlebars", "npm:4.7.7"],\ - ["inquirer", "npm:7.3.3"],\ - ["make-promises-safe", "npm:5.1.0"],\ - ["rimraf", "npm:3.0.2"],\ - ["semver", "npm:7.3.8"],\ - ["toml", "npm:3.0.0"],\ - ["ts-typed-json", "npm:0.3.2"],\ - ["validate-npm-package-license", "npm:3.0.4"],\ - ["validate-npm-package-name", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["neon-load-or-build", [\ - ["npm:2.2.2", {\ - "packageLocation": "./.yarn/cache/neon-load-or-build-npm-2.2.2-548a286943-3cafba0e26.zip/node_modules/neon-load-or-build/",\ - "packageDependencies": [\ - ["neon-load-or-build", "npm:2.2.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["neon-tag-prebuild", [\ - ["https://github.com/shumkov/neon-tag-prebuild.git#commit=a429834da27432b129eceb737e4d2b3f03fa5496", {\ - "packageLocation": "./.yarn/cache/neon-tag-prebuild-https-d665d28b1f-00a16bf27c.zip/node_modules/neon-tag-prebuild/",\ - "packageDependencies": [\ - ["neon-tag-prebuild", "https://github.com/shumkov/neon-tag-prebuild.git#commit=a429834da27432b129eceb737e4d2b3f03fa5496"],\ - ["mkdirp", "npm:1.0.4"],\ - ["node-abi", "npm:2.30.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["net", [\ ["npm:1.0.2", {\ "packageLocation": "./.yarn/cache/net-npm-1.0.2-1d5514df5b-d97e215d92.zip/node_modules/net/",\ @@ -13836,16 +13367,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["node-abi", [\ - ["npm:2.30.1", {\ - "packageLocation": "./.yarn/cache/node-abi-npm-2.30.1-36a2c4e28a-3f4b0c912c.zip/node_modules/node-abi/",\ - "packageDependencies": [\ - ["node-abi", "npm:2.30.1"],\ - ["semver", "npm:5.7.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["node-fetch", [\ ["npm:2.6.7", {\ "packageLocation": "./.yarn/cache/node-fetch-npm-2.6.7-777aa2a6df-8d816ffd1e.zip/node_modules/node-fetch/",\ @@ -14925,63 +14446,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["pino", [\ - ["npm:6.13.3", {\ - "packageLocation": "./.yarn/cache/pino-npm-6.13.3-50e2aceb53-a580decd47.zip/node_modules/pino/",\ - "packageDependencies": [\ - ["pino", "npm:6.13.3"],\ - ["fast-redact", "npm:3.0.2"],\ - ["fast-safe-stringify", "npm:2.1.1"],\ - ["fastify-warning", "npm:0.2.0"],\ - ["flatstr", "npm:1.0.12"],\ - ["pino-pretty", "npm:4.8.0"],\ - ["pino-std-serializers", "npm:3.2.0"],\ - ["quick-format-unescaped", "npm:4.0.4"],\ - ["sonic-boom", "npm:1.4.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["pino-multi-stream", [\ - ["npm:5.3.0", {\ - "packageLocation": "./.yarn/cache/pino-multi-stream-npm-5.3.0-ecb9b754cb-10ddb85983.zip/node_modules/pino-multi-stream/",\ - "packageDependencies": [\ - ["pino-multi-stream", "npm:5.3.0"],\ - ["pino", "npm:6.13.3"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["pino-pretty", [\ - ["npm:4.8.0", {\ - "packageLocation": "./.yarn/cache/pino-pretty-npm-4.8.0-0c822e28cb-8e2e4cdb80.zip/node_modules/pino-pretty/",\ - "packageDependencies": [\ - ["pino-pretty", "npm:4.8.0"],\ - ["@hapi/bourne", "npm:2.0.0"],\ - ["args", "npm:5.0.1"],\ - ["chalk", "npm:4.1.2"],\ - ["dateformat", "npm:4.6.3"],\ - ["fast-safe-stringify", "npm:2.1.1"],\ - ["jmespath", "npm:0.15.0"],\ - ["joycon", "npm:2.2.5"],\ - ["pump", "npm:3.0.0"],\ - ["readable-stream", "npm:3.6.0"],\ - ["rfdc", "npm:1.3.0"],\ - ["split2", "npm:3.2.2"],\ - ["strip-json-comments", "npm:3.1.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ - ["pino-std-serializers", [\ - ["npm:3.2.0", {\ - "packageLocation": "./.yarn/cache/pino-std-serializers-npm-3.2.0-9fd67503a4-77e29675b1.zip/node_modules/pino-std-serializers/",\ - "packageDependencies": [\ - ["pino-std-serializers", "npm:3.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["pkg-dir", [\ ["npm:2.0.0", {\ "packageLocation": "./.yarn/cache/pkg-dir-npm-2.0.0-2b4bf4abd1-8c72b71230.zip/node_modules/pkg-dir/",\ @@ -15201,17 +14665,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["protocol-buffers-encodings", [\ - ["npm:1.1.1", {\ - "packageLocation": "./.yarn/cache/protocol-buffers-encodings-npm-1.1.1-07111209e8-1b22d6d05b.zip/node_modules/protocol-buffers-encodings/",\ - "packageDependencies": [\ - ["protocol-buffers-encodings", "npm:1.1.1"],\ - ["signed-varint", "npm:2.0.1"],\ - ["varint", "npm:5.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["prr", [\ ["npm:1.0.1", {\ "packageLocation": "./.yarn/cache/prr-npm-1.0.1-608d442761-3bca2db047.zip/node_modules/prr/",\ @@ -15339,15 +14792,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["quick-format-unescaped", [\ - ["npm:4.0.4", {\ - "packageLocation": "./.yarn/cache/quick-format-unescaped-npm-4.0.4-7e22c9b7dc-7bc32b9935.zip/node_modules/quick-format-unescaped/",\ - "packageDependencies": [\ - ["quick-format-unescaped", "npm:4.0.4"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["quick-lru", [\ ["npm:4.0.1", {\ "packageLocation": "./.yarn/cache/quick-lru-npm-4.0.1-ef8aa17c9c-bea46e1abf.zip/node_modules/quick-lru/",\ @@ -15579,15 +15023,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["reduce-flatten", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/reduce-flatten-npm-2.0.0-01bd4936fa-64393ef99a.zip/node_modules/reduce-flatten/",\ - "packageDependencies": [\ - ["reduce-flatten", "npm:2.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["regenerate", [\ ["npm:1.4.2", {\ "packageLocation": "./.yarn/cache/regenerate-npm-1.4.2-b296c5b63a-3317a09b2f.zip/node_modules/regenerate/",\ @@ -15848,15 +15283,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["ret", [\ - ["npm:0.2.2", {\ - "packageLocation": "./.yarn/cache/ret-npm-0.2.2-f5d3022812-774964bb41.zip/node_modules/ret/",\ - "packageDependencies": [\ - ["ret", "npm:0.2.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["retry", [\ ["npm:0.12.0", {\ "packageLocation": "./.yarn/cache/retry-npm-0.12.0-72ac7fb4cc-623bd7d2e5.zip/node_modules/retry/",\ @@ -15978,16 +15404,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["safe-regex2", [\ - ["npm:2.0.0", {\ - "packageLocation": "./.yarn/cache/safe-regex2-npm-2.0.0-eadecc9909-f5e182fca0.zip/node_modules/safe-regex2/",\ - "packageDependencies": [\ - ["safe-regex2", "npm:2.0.0"],\ - ["ret", "npm:0.2.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["safe-stable-stringify", [\ ["npm:1.1.1", {\ "packageLocation": "./.yarn/cache/safe-stable-stringify-npm-1.1.1-1c282e1c55-e32a30720e.zip/node_modules/safe-stable-stringify/",\ @@ -16103,15 +15519,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["semver-store", [\ - ["npm:0.3.0", {\ - "packageLocation": "./.yarn/cache/semver-store-npm-0.3.0-0fc88fd5b9-b38f747123.zip/node_modules/semver-store/",\ - "packageDependencies": [\ - ["semver-store", "npm:0.3.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["serialize-javascript", [\ ["npm:6.0.0", {\ "packageLocation": "./.yarn/cache/serialize-javascript-npm-6.0.0-0bb8a3c88d-56f90b562a.zip/node_modules/serialize-javascript/",\ @@ -16319,16 +15726,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["signed-varint", [\ - ["npm:2.0.1", {\ - "packageLocation": "./.yarn/cache/signed-varint-npm-2.0.1-18301876e5-a9fd2d954d.zip/node_modules/signed-varint/",\ - "packageDependencies": [\ - ["signed-varint", "npm:2.0.1"],\ - ["varint", "npm:5.0.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["simple-swizzle", [\ ["npm:0.2.2", {\ "packageLocation": "./.yarn/cache/simple-swizzle-npm-0.2.2-8dee37fad1-a7f3f2ab5c.zip/node_modules/simple-swizzle/",\ @@ -16536,25 +15933,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["sonic-boom", [\ - ["npm:1.4.1", {\ - "packageLocation": "./.yarn/cache/sonic-boom-npm-1.4.1-e42b921f99-189fa8fe5c.zip/node_modules/sonic-boom/",\ - "packageDependencies": [\ - ["sonic-boom", "npm:1.4.1"],\ - ["atomic-sleep", "npm:1.0.0"],\ - ["flatstr", "npm:1.0.12"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:2.3.1", {\ - "packageLocation": "./.yarn/cache/sonic-boom-npm-2.3.1-0ba04b648c-4f5022de97.zip/node_modules/sonic-boom/",\ - "packageDependencies": [\ - ["sonic-boom", "npm:2.3.1"],\ - ["atomic-sleep", "npm:1.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["sort-keys", [\ ["npm:4.2.0", {\ "packageLocation": "./.yarn/cache/sort-keys-npm-4.2.0-bf52ceef80-1535ffd5a7.zip/node_modules/sort-keys/",\ @@ -17135,19 +16513,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["table-layout", [\ - ["npm:1.0.2", {\ - "packageLocation": "./.yarn/cache/table-layout-npm-1.0.2-0b3fe79240-8f41b5671f.zip/node_modules/table-layout/",\ - "packageDependencies": [\ - ["table-layout", "npm:1.0.2"],\ - ["array-back", "npm:4.0.2"],\ - ["deep-extend", "npm:0.6.0"],\ - ["typical", "npm:5.2.0"],\ - ["wordwrapjs", "npm:4.0.1"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["taketalk", [\ ["npm:1.0.0", {\ "packageLocation": "./.yarn/cache/taketalk-npm-1.0.0-2fc66802cb-b9a6ae2d6e.zip/node_modules/taketalk/",\ @@ -17506,15 +16871,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ],\ "linkType": "HARD"\ }],\ - ["npm:3.0.2", {\ - "packageLocation": "./.yarn/cache/through2-npm-3.0.2-403f837012-47c9586c73.zip/node_modules/through2/",\ - "packageDependencies": [\ - ["through2", "npm:3.0.2"],\ - ["inherits", "npm:2.0.4"],\ - ["readable-stream", "npm:3.6.0"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:4.0.2", {\ "packageLocation": "./.yarn/cache/through2-npm-4.0.2-da7b2da443-ac7430bd54.zip/node_modules/through2/",\ "packageDependencies": [\ @@ -17597,15 +16953,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["toml", [\ - ["npm:3.0.0", {\ - "packageLocation": "./.yarn/cache/toml-npm-3.0.0-f993270804-5d7f1d8413.zip/node_modules/toml/",\ - "packageDependencies": [\ - ["toml", "npm:3.0.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["touch", [\ ["npm:3.1.0", {\ "packageLocation": "./.yarn/cache/touch-npm-3.1.0-e2eacebbda-e0be589cb5.zip/node_modules/touch/",\ @@ -17824,15 +17171,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["ts-typed-json", [\ - ["npm:0.3.2", {\ - "packageLocation": "./.yarn/cache/ts-typed-json-npm-0.3.2-6ec963b162-141c976da0.zip/node_modules/ts-typed-json/",\ - "packageDependencies": [\ - ["ts-typed-json", "npm:0.3.2"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["tsconfig-paths", [\ ["npm:3.12.0", {\ "packageLocation": "./.yarn/cache/tsconfig-paths-npm-3.12.0-b78aadfb3f-4999ec6cd1.zip/node_modules/tsconfig-paths/",\ @@ -18040,22 +17378,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["typical", [\ - ["npm:4.0.0", {\ - "packageLocation": "./.yarn/cache/typical-npm-4.0.0-2255d8d515-a242081956.zip/node_modules/typical/",\ - "packageDependencies": [\ - ["typical", "npm:4.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:5.2.0", {\ - "packageLocation": "./.yarn/cache/typical-npm-5.2.0-d4de46c932-ccaeb151a9.zip/node_modules/typical/",\ - "packageDependencies": [\ - ["typical", "npm:5.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["ua-parser-js", [\ ["npm:1.0.33", {\ "packageLocation": "./.yarn/cache/ua-parser-js-npm-1.0.33-60ab7da777-460adef512.zip/node_modules/ua-parser-js/",\ @@ -18382,20 +17704,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }]\ ]],\ ["varint", [\ - ["npm:5.0.0", {\ - "packageLocation": "./.yarn/cache/varint-npm-5.0.0-c2491b868a-527c65ad87.zip/node_modules/varint/",\ - "packageDependencies": [\ - ["varint", "npm:5.0.0"]\ - ],\ - "linkType": "HARD"\ - }],\ - ["npm:5.0.2", {\ - "packageLocation": "./.yarn/cache/varint-npm-5.0.2-fcb43e79c5-e1a66bf9a6.zip/node_modules/varint/",\ - "packageDependencies": [\ - ["varint", "npm:5.0.2"]\ - ],\ - "linkType": "HARD"\ - }],\ ["npm:6.0.0", {\ "packageLocation": "./.yarn/cache/varint-npm-6.0.0-a638e8f225-7684113c9d.zip/node_modules/varint/",\ "packageDependencies": [\ @@ -19127,17 +18435,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD"\ }]\ ]],\ - ["wordwrapjs", [\ - ["npm:4.0.1", {\ - "packageLocation": "./.yarn/cache/wordwrapjs-npm-4.0.1-b6c3c84d76-3d927f3c95.zip/node_modules/wordwrapjs/",\ - "packageDependencies": [\ - ["wordwrapjs", "npm:4.0.1"],\ - ["reduce-flatten", "npm:2.0.0"],\ - ["typical", "npm:5.2.0"]\ - ],\ - "linkType": "HARD"\ - }]\ - ]],\ ["workerpool", [\ ["npm:6.2.0", {\ "packageLocation": "./.yarn/cache/workerpool-npm-6.2.0-d2a722f6bb-3493b4f0ef.zip/node_modules/workerpool/",\ diff --git a/.yarn/cache/@dashevo-abci-https-9fb519f2ca-aaf41ab7fa.zip b/.yarn/cache/@dashevo-abci-https-9fb519f2ca-aaf41ab7fa.zip deleted file mode 100644 index 0f04c9d69a2..00000000000 Binary files a/.yarn/cache/@dashevo-abci-https-9fb519f2ca-aaf41ab7fa.zip and /dev/null differ diff --git a/.yarn/cache/@hapi-bourne-npm-2.0.0-8eeda7e0a2-2ea0922101.zip b/.yarn/cache/@hapi-bourne-npm-2.0.0-8eeda7e0a2-2ea0922101.zip deleted file mode 100644 index 7b0f02dc258..00000000000 Binary files a/.yarn/cache/@hapi-bourne-npm-2.0.0-8eeda7e0a2-2ea0922101.zip and /dev/null differ diff --git a/.yarn/cache/@types-pino-npm-6.3.12-19c7982858-8017351466.zip b/.yarn/cache/@types-pino-npm-6.3.12-19c7982858-8017351466.zip deleted file mode 100644 index dfed8ac6e72..00000000000 Binary files a/.yarn/cache/@types-pino-npm-6.3.12-19c7982858-8017351466.zip and /dev/null differ diff --git a/.yarn/cache/@types-pino-pretty-npm-4.7.3-5ebf57cfd2-40fe67e73d.zip b/.yarn/cache/@types-pino-pretty-npm-4.7.3-5ebf57cfd2-40fe67e73d.zip deleted file mode 100644 index 98c7a35e627..00000000000 Binary files a/.yarn/cache/@types-pino-pretty-npm-4.7.3-5ebf57cfd2-40fe67e73d.zip and /dev/null differ diff --git a/.yarn/cache/@types-pino-std-serializers-npm-2.4.1-e7c36178c0-a156e25882.zip b/.yarn/cache/@types-pino-std-serializers-npm-2.4.1-e7c36178c0-a156e25882.zip deleted file mode 100644 index 31a47a212a2..00000000000 Binary files a/.yarn/cache/@types-pino-std-serializers-npm-2.4.1-e7c36178c0-a156e25882.zip and /dev/null differ diff --git a/.yarn/cache/ajv-keywords-npm-5.0.0-50b946aaa2-239dd46383.zip b/.yarn/cache/ajv-keywords-npm-5.0.0-50b946aaa2-239dd46383.zip deleted file mode 100644 index 7ebc0a276f6..00000000000 Binary files a/.yarn/cache/ajv-keywords-npm-5.0.0-50b946aaa2-239dd46383.zip and /dev/null differ diff --git a/.yarn/cache/args-npm-5.0.1-cd7b0f9dcc-51e2a05f32.zip b/.yarn/cache/args-npm-5.0.1-cd7b0f9dcc-51e2a05f32.zip deleted file mode 100644 index 5a4d861d199..00000000000 Binary files a/.yarn/cache/args-npm-5.0.1-cd7b0f9dcc-51e2a05f32.zip and /dev/null differ diff --git a/.yarn/cache/array-back-npm-3.1.0-a52d25f5a3-7205004fcd.zip b/.yarn/cache/array-back-npm-3.1.0-a52d25f5a3-7205004fcd.zip deleted file mode 100644 index 7e02ce53a39..00000000000 Binary files a/.yarn/cache/array-back-npm-3.1.0-a52d25f5a3-7205004fcd.zip and /dev/null differ diff --git a/.yarn/cache/array-back-npm-4.0.2-f735073f8f-f306032707.zip b/.yarn/cache/array-back-npm-4.0.2-f735073f8f-f306032707.zip deleted file mode 100644 index 6884e6ac0cc..00000000000 Binary files a/.yarn/cache/array-back-npm-4.0.2-f735073f8f-f306032707.zip and /dev/null differ diff --git a/.yarn/cache/atomic-sleep-npm-1.0.0-17d8a762a3-b95275afb2.zip b/.yarn/cache/atomic-sleep-npm-1.0.0-17d8a762a3-b95275afb2.zip deleted file mode 100644 index d172f9448b5..00000000000 Binary files a/.yarn/cache/atomic-sleep-npm-1.0.0-17d8a762a3-b95275afb2.zip and /dev/null differ diff --git a/.yarn/cache/bl-npm-1.2.3-49c4213ca5-123f097989.zip b/.yarn/cache/bl-npm-1.2.3-49c4213ca5-123f097989.zip deleted file mode 100644 index b7c6cb8640e..00000000000 Binary files a/.yarn/cache/bl-npm-1.2.3-49c4213ca5-123f097989.zip and /dev/null differ diff --git a/.yarn/cache/camelcase-npm-5.0.0-c808398846-8bfe920e04.zip b/.yarn/cache/camelcase-npm-5.0.0-c808398846-8bfe920e04.zip deleted file mode 100644 index cdc64a3c0b3..00000000000 Binary files a/.yarn/cache/camelcase-npm-5.0.0-c808398846-8bfe920e04.zip and /dev/null differ diff --git a/.yarn/cache/cargo-cp-artifact-npm-0.1.6-fe2dd40a8f-2f5d2f3e73.zip b/.yarn/cache/cargo-cp-artifact-npm-0.1.6-fe2dd40a8f-2f5d2f3e73.zip deleted file mode 100644 index 2da3bc5d400..00000000000 Binary files a/.yarn/cache/cargo-cp-artifact-npm-0.1.6-fe2dd40a8f-2f5d2f3e73.zip and /dev/null differ diff --git a/.yarn/cache/command-line-args-npm-5.2.1-093a68d295-e759519087.zip b/.yarn/cache/command-line-args-npm-5.2.1-093a68d295-e759519087.zip deleted file mode 100644 index d5cc8adc2c3..00000000000 Binary files a/.yarn/cache/command-line-args-npm-5.2.1-093a68d295-e759519087.zip and /dev/null differ diff --git a/.yarn/cache/command-line-commands-npm-3.0.2-782bf8a159-2cf5409af0.zip b/.yarn/cache/command-line-commands-npm-3.0.2-782bf8a159-2cf5409af0.zip deleted file mode 100644 index c7e7294a472..00000000000 Binary files a/.yarn/cache/command-line-commands-npm-3.0.2-782bf8a159-2cf5409af0.zip and /dev/null differ diff --git a/.yarn/cache/command-line-usage-npm-6.1.3-145c2dabe1-8261d4e553.zip b/.yarn/cache/command-line-usage-npm-6.1.3-145c2dabe1-8261d4e553.zip deleted file mode 100644 index 17bff004f38..00000000000 Binary files a/.yarn/cache/command-line-usage-npm-6.1.3-145c2dabe1-8261d4e553.zip and /dev/null differ diff --git a/.yarn/cache/fast-decode-uri-component-npm-1.0.1-578ba9fecf-427a48fe09.zip b/.yarn/cache/fast-decode-uri-component-npm-1.0.1-578ba9fecf-427a48fe09.zip deleted file mode 100644 index a2ebdfe0b21..00000000000 Binary files a/.yarn/cache/fast-decode-uri-component-npm-1.0.1-578ba9fecf-427a48fe09.zip and /dev/null differ diff --git a/.yarn/cache/fast-redact-npm-3.0.2-98d6f1d433-f4ffdf48f1.zip b/.yarn/cache/fast-redact-npm-3.0.2-98d6f1d433-f4ffdf48f1.zip deleted file mode 100644 index e74e97b048a..00000000000 Binary files a/.yarn/cache/fast-redact-npm-3.0.2-98d6f1d433-f4ffdf48f1.zip and /dev/null differ diff --git a/.yarn/cache/fast-safe-stringify-npm-2.1.1-7ce89033ca-a851cbddc4.zip b/.yarn/cache/fast-safe-stringify-npm-2.1.1-7ce89033ca-a851cbddc4.zip deleted file mode 100644 index 0de375bb1a1..00000000000 Binary files a/.yarn/cache/fast-safe-stringify-npm-2.1.1-7ce89033ca-a851cbddc4.zip and /dev/null differ diff --git a/.yarn/cache/fastify-warning-npm-0.2.0-f9c53563fc-c19ebccf54.zip b/.yarn/cache/fastify-warning-npm-0.2.0-f9c53563fc-c19ebccf54.zip deleted file mode 100644 index c8595ca6e75..00000000000 Binary files a/.yarn/cache/fastify-warning-npm-0.2.0-f9c53563fc-c19ebccf54.zip and /dev/null differ diff --git a/.yarn/cache/find-my-way-npm-2.2.5-3bef2f72f0-9330349565.zip b/.yarn/cache/find-my-way-npm-2.2.5-3bef2f72f0-9330349565.zip deleted file mode 100644 index 0b65f54fe7a..00000000000 Binary files a/.yarn/cache/find-my-way-npm-2.2.5-3bef2f72f0-9330349565.zip and /dev/null differ diff --git a/.yarn/cache/find-replace-npm-3.0.0-686bd07d28-6b04bcfd79.zip b/.yarn/cache/find-replace-npm-3.0.0-686bd07d28-6b04bcfd79.zip deleted file mode 100644 index 550c3235b6b..00000000000 Binary files a/.yarn/cache/find-replace-npm-3.0.0-686bd07d28-6b04bcfd79.zip and /dev/null differ diff --git a/.yarn/cache/flatstr-npm-1.0.12-4311d37d16-e1bb562c94.zip b/.yarn/cache/flatstr-npm-1.0.12-4311d37d16-e1bb562c94.zip deleted file mode 100644 index 0ead0ea76a6..00000000000 Binary files a/.yarn/cache/flatstr-npm-1.0.12-4311d37d16-e1bb562c94.zip and /dev/null differ diff --git a/.yarn/cache/git-config-npm-0.0.7-fd037544b3-99a7e20306.zip b/.yarn/cache/git-config-npm-0.0.7-fd037544b3-99a7e20306.zip deleted file mode 100644 index 11bd0fc7a0f..00000000000 Binary files a/.yarn/cache/git-config-npm-0.0.7-fd037544b3-99a7e20306.zip and /dev/null differ diff --git a/.yarn/cache/iniparser-npm-1.0.5-446fd8dfb0-eba0ec2d68.zip b/.yarn/cache/iniparser-npm-1.0.5-446fd8dfb0-eba0ec2d68.zip deleted file mode 100644 index 1f0c3ce6d7f..00000000000 Binary files a/.yarn/cache/iniparser-npm-1.0.5-446fd8dfb0-eba0ec2d68.zip and /dev/null differ diff --git a/.yarn/cache/inquirer-npm-7.3.3-9e86782610-4d387fc1eb.zip b/.yarn/cache/inquirer-npm-7.3.3-9e86782610-4d387fc1eb.zip deleted file mode 100644 index 9e14affd9d2..00000000000 Binary files a/.yarn/cache/inquirer-npm-7.3.3-9e86782610-4d387fc1eb.zip and /dev/null differ diff --git a/.yarn/cache/jmespath-npm-0.15.0-df80ed6dd1-353bb9e69c.zip b/.yarn/cache/jmespath-npm-0.15.0-df80ed6dd1-353bb9e69c.zip deleted file mode 100644 index 3f85bba8b31..00000000000 Binary files a/.yarn/cache/jmespath-npm-0.15.0-df80ed6dd1-353bb9e69c.zip and /dev/null differ diff --git a/.yarn/cache/joycon-npm-2.2.5-fff23ab519-930bb748c0.zip b/.yarn/cache/joycon-npm-2.2.5-fff23ab519-930bb748c0.zip deleted file mode 100644 index a73836079da..00000000000 Binary files a/.yarn/cache/joycon-npm-2.2.5-fff23ab519-930bb748c0.zip and /dev/null differ diff --git a/.yarn/cache/leven-npm-2.1.0-19f0a16606-f7b4a01b15.zip b/.yarn/cache/leven-npm-2.1.0-19f0a16606-f7b4a01b15.zip deleted file mode 100644 index 6eba0706ba5..00000000000 Binary files a/.yarn/cache/leven-npm-2.1.0-19f0a16606-f7b4a01b15.zip and /dev/null differ diff --git a/.yarn/cache/make-promises-safe-npm-5.1.0-7a3dd5a2e9-6e59ed8c56.zip b/.yarn/cache/make-promises-safe-npm-5.1.0-7a3dd5a2e9-6e59ed8c56.zip deleted file mode 100644 index 0771f5ff8e7..00000000000 Binary files a/.yarn/cache/make-promises-safe-npm-5.1.0-7a3dd5a2e9-6e59ed8c56.zip and /dev/null differ diff --git a/.yarn/cache/moment-npm-2.29.4-902943305d-0ec3f9c2bc.zip b/.yarn/cache/moment-npm-2.29.4-902943305d-0ec3f9c2bc.zip deleted file mode 100644 index 78acd14bed8..00000000000 Binary files a/.yarn/cache/moment-npm-2.29.4-902943305d-0ec3f9c2bc.zip and /dev/null differ diff --git a/.yarn/cache/mri-npm-1.1.4-d22a399f26-e65b9aed3b.zip b/.yarn/cache/mri-npm-1.1.4-d22a399f26-e65b9aed3b.zip deleted file mode 100644 index 5eb6997d644..00000000000 Binary files a/.yarn/cache/mri-npm-1.1.4-d22a399f26-e65b9aed3b.zip and /dev/null differ diff --git a/.yarn/cache/neon-cli-npm-0.10.1-f6ee1b3cec-284e7ec9e3.zip b/.yarn/cache/neon-cli-npm-0.10.1-f6ee1b3cec-284e7ec9e3.zip deleted file mode 100644 index a394f97f944..00000000000 Binary files a/.yarn/cache/neon-cli-npm-0.10.1-f6ee1b3cec-284e7ec9e3.zip and /dev/null differ diff --git a/.yarn/cache/neon-load-or-build-npm-2.2.2-548a286943-3cafba0e26.zip b/.yarn/cache/neon-load-or-build-npm-2.2.2-548a286943-3cafba0e26.zip deleted file mode 100644 index 96d1001a7cf..00000000000 Binary files a/.yarn/cache/neon-load-or-build-npm-2.2.2-548a286943-3cafba0e26.zip and /dev/null differ diff --git a/.yarn/cache/neon-tag-prebuild-https-d665d28b1f-00a16bf27c.zip b/.yarn/cache/neon-tag-prebuild-https-d665d28b1f-00a16bf27c.zip deleted file mode 100644 index 609ef81c0b0..00000000000 Binary files a/.yarn/cache/neon-tag-prebuild-https-d665d28b1f-00a16bf27c.zip and /dev/null differ diff --git a/.yarn/cache/node-abi-npm-2.30.1-36a2c4e28a-3f4b0c912c.zip b/.yarn/cache/node-abi-npm-2.30.1-36a2c4e28a-3f4b0c912c.zip deleted file mode 100644 index 78cb2c39d72..00000000000 Binary files a/.yarn/cache/node-abi-npm-2.30.1-36a2c4e28a-3f4b0c912c.zip and /dev/null differ diff --git a/.yarn/cache/pino-multi-stream-npm-5.3.0-ecb9b754cb-10ddb85983.zip b/.yarn/cache/pino-multi-stream-npm-5.3.0-ecb9b754cb-10ddb85983.zip deleted file mode 100644 index ff8066cad1a..00000000000 Binary files a/.yarn/cache/pino-multi-stream-npm-5.3.0-ecb9b754cb-10ddb85983.zip and /dev/null differ diff --git a/.yarn/cache/pino-npm-6.13.3-50e2aceb53-a580decd47.zip b/.yarn/cache/pino-npm-6.13.3-50e2aceb53-a580decd47.zip deleted file mode 100644 index 3b894655171..00000000000 Binary files a/.yarn/cache/pino-npm-6.13.3-50e2aceb53-a580decd47.zip and /dev/null differ diff --git a/.yarn/cache/pino-pretty-npm-4.8.0-0c822e28cb-8e2e4cdb80.zip b/.yarn/cache/pino-pretty-npm-4.8.0-0c822e28cb-8e2e4cdb80.zip deleted file mode 100644 index 2c078dd27f1..00000000000 Binary files a/.yarn/cache/pino-pretty-npm-4.8.0-0c822e28cb-8e2e4cdb80.zip and /dev/null differ diff --git a/.yarn/cache/pino-std-serializers-npm-3.2.0-9fd67503a4-77e29675b1.zip b/.yarn/cache/pino-std-serializers-npm-3.2.0-9fd67503a4-77e29675b1.zip deleted file mode 100644 index fa0c61ed0b2..00000000000 Binary files a/.yarn/cache/pino-std-serializers-npm-3.2.0-9fd67503a4-77e29675b1.zip and /dev/null differ diff --git a/.yarn/cache/protocol-buffers-encodings-npm-1.1.1-07111209e8-1b22d6d05b.zip b/.yarn/cache/protocol-buffers-encodings-npm-1.1.1-07111209e8-1b22d6d05b.zip deleted file mode 100644 index 1fcfbe9317f..00000000000 Binary files a/.yarn/cache/protocol-buffers-encodings-npm-1.1.1-07111209e8-1b22d6d05b.zip and /dev/null differ diff --git a/.yarn/cache/quick-format-unescaped-npm-4.0.4-7e22c9b7dc-7bc32b9935.zip b/.yarn/cache/quick-format-unescaped-npm-4.0.4-7e22c9b7dc-7bc32b9935.zip deleted file mode 100644 index 8ce3d464d80..00000000000 Binary files a/.yarn/cache/quick-format-unescaped-npm-4.0.4-7e22c9b7dc-7bc32b9935.zip and /dev/null differ diff --git a/.yarn/cache/reduce-flatten-npm-2.0.0-01bd4936fa-64393ef99a.zip b/.yarn/cache/reduce-flatten-npm-2.0.0-01bd4936fa-64393ef99a.zip deleted file mode 100644 index 7ab0e9472f8..00000000000 Binary files a/.yarn/cache/reduce-flatten-npm-2.0.0-01bd4936fa-64393ef99a.zip and /dev/null differ diff --git a/.yarn/cache/ret-npm-0.2.2-f5d3022812-774964bb41.zip b/.yarn/cache/ret-npm-0.2.2-f5d3022812-774964bb41.zip deleted file mode 100644 index 495e63ba04e..00000000000 Binary files a/.yarn/cache/ret-npm-0.2.2-f5d3022812-774964bb41.zip and /dev/null differ diff --git a/.yarn/cache/safe-regex2-npm-2.0.0-eadecc9909-f5e182fca0.zip b/.yarn/cache/safe-regex2-npm-2.0.0-eadecc9909-f5e182fca0.zip deleted file mode 100644 index 8ae7c9e5e53..00000000000 Binary files a/.yarn/cache/safe-regex2-npm-2.0.0-eadecc9909-f5e182fca0.zip and /dev/null differ diff --git a/.yarn/cache/semver-store-npm-0.3.0-0fc88fd5b9-b38f747123.zip b/.yarn/cache/semver-store-npm-0.3.0-0fc88fd5b9-b38f747123.zip deleted file mode 100644 index 3075d8a1670..00000000000 Binary files a/.yarn/cache/semver-store-npm-0.3.0-0fc88fd5b9-b38f747123.zip and /dev/null differ diff --git a/.yarn/cache/signed-varint-npm-2.0.1-18301876e5-a9fd2d954d.zip b/.yarn/cache/signed-varint-npm-2.0.1-18301876e5-a9fd2d954d.zip deleted file mode 100644 index e5b624d2677..00000000000 Binary files a/.yarn/cache/signed-varint-npm-2.0.1-18301876e5-a9fd2d954d.zip and /dev/null differ diff --git a/.yarn/cache/sonic-boom-npm-1.4.1-e42b921f99-189fa8fe5c.zip b/.yarn/cache/sonic-boom-npm-1.4.1-e42b921f99-189fa8fe5c.zip deleted file mode 100644 index 7e23ef07671..00000000000 Binary files a/.yarn/cache/sonic-boom-npm-1.4.1-e42b921f99-189fa8fe5c.zip and /dev/null differ diff --git a/.yarn/cache/sonic-boom-npm-2.3.1-0ba04b648c-4f5022de97.zip b/.yarn/cache/sonic-boom-npm-2.3.1-0ba04b648c-4f5022de97.zip deleted file mode 100644 index 3a5ef019545..00000000000 Binary files a/.yarn/cache/sonic-boom-npm-2.3.1-0ba04b648c-4f5022de97.zip and /dev/null differ diff --git a/.yarn/cache/table-layout-npm-1.0.2-0b3fe79240-8f41b5671f.zip b/.yarn/cache/table-layout-npm-1.0.2-0b3fe79240-8f41b5671f.zip deleted file mode 100644 index e8b724b78d6..00000000000 Binary files a/.yarn/cache/table-layout-npm-1.0.2-0b3fe79240-8f41b5671f.zip and /dev/null differ diff --git a/.yarn/cache/through2-npm-3.0.2-403f837012-47c9586c73.zip b/.yarn/cache/through2-npm-3.0.2-403f837012-47c9586c73.zip deleted file mode 100644 index 7dbb5653351..00000000000 Binary files a/.yarn/cache/through2-npm-3.0.2-403f837012-47c9586c73.zip and /dev/null differ diff --git a/.yarn/cache/toml-npm-3.0.0-f993270804-5d7f1d8413.zip b/.yarn/cache/toml-npm-3.0.0-f993270804-5d7f1d8413.zip deleted file mode 100644 index 6474c4f487e..00000000000 Binary files a/.yarn/cache/toml-npm-3.0.0-f993270804-5d7f1d8413.zip and /dev/null differ diff --git a/.yarn/cache/ts-typed-json-npm-0.3.2-6ec963b162-141c976da0.zip b/.yarn/cache/ts-typed-json-npm-0.3.2-6ec963b162-141c976da0.zip deleted file mode 100644 index 3c662d46ad5..00000000000 Binary files a/.yarn/cache/ts-typed-json-npm-0.3.2-6ec963b162-141c976da0.zip and /dev/null differ diff --git a/.yarn/cache/typical-npm-4.0.0-2255d8d515-a242081956.zip b/.yarn/cache/typical-npm-4.0.0-2255d8d515-a242081956.zip deleted file mode 100644 index 2aa38eae5bf..00000000000 Binary files a/.yarn/cache/typical-npm-4.0.0-2255d8d515-a242081956.zip and /dev/null differ diff --git a/.yarn/cache/typical-npm-5.2.0-d4de46c932-ccaeb151a9.zip b/.yarn/cache/typical-npm-5.2.0-d4de46c932-ccaeb151a9.zip deleted file mode 100644 index 1762727eb8e..00000000000 Binary files a/.yarn/cache/typical-npm-5.2.0-d4de46c932-ccaeb151a9.zip and /dev/null differ diff --git a/.yarn/cache/varint-npm-5.0.0-c2491b868a-527c65ad87.zip b/.yarn/cache/varint-npm-5.0.0-c2491b868a-527c65ad87.zip deleted file mode 100644 index 5e951610617..00000000000 Binary files a/.yarn/cache/varint-npm-5.0.0-c2491b868a-527c65ad87.zip and /dev/null differ diff --git a/.yarn/cache/varint-npm-5.0.2-fcb43e79c5-e1a66bf9a6.zip b/.yarn/cache/varint-npm-5.0.2-fcb43e79c5-e1a66bf9a6.zip deleted file mode 100644 index df72d8406ff..00000000000 Binary files a/.yarn/cache/varint-npm-5.0.2-fcb43e79c5-e1a66bf9a6.zip and /dev/null differ diff --git a/.yarn/cache/wordwrapjs-npm-4.0.1-b6c3c84d76-3d927f3c95.zip b/.yarn/cache/wordwrapjs-npm-4.0.1-b6c3c84d76-3d927f3c95.zip deleted file mode 100644 index ccd3653cc26..00000000000 Binary files a/.yarn/cache/wordwrapjs-npm-4.0.1-b6c3c84d76-3d927f3c95.zip and /dev/null differ diff --git a/Cargo.lock b/Cargo.lock index 451b625e837..53af8fffa8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -508,7 +508,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" dependencies = [ "camino", "cargo-platform", - "semver 1.0.17", + "semver", "serde", "serde_json", ] @@ -591,7 +591,7 @@ checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", - "libloading 0.7.4", + "libloading", ] [[package]] @@ -1169,16 +1169,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "drive-nodejs" -version = "0.24.0-dev.1" -dependencies = [ - "drive", - "drive-abci", - "neon", - "num 0.4.0", -] - [[package]] name = "ed" version = "0.2.2" @@ -1401,7 +1391,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aba3510011eee8825018be07f08d9643421de007eaf62a3bde58d89b058abfa7" dependencies = [ "lazy_static", - "num 0.2.1", + "num", ] [[package]] @@ -1890,16 +1880,6 @@ version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" -[[package]] -name = "libloading" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.7.4" @@ -2119,47 +2099,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" -[[package]] -name = "neon" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e15415261d880aed48122e917a45e87bb82cf0260bb6db48bbab44b7464373" -dependencies = [ - "neon-build", - "neon-macros", - "neon-runtime", - "semver 0.9.0", - "smallvec", -] - -[[package]] -name = "neon-build" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bac98a702e71804af3dacfde41edde4a16076a7bbe889ae61e56e18c5b1c811" - -[[package]] -name = "neon-macros" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7288eac8b54af7913c60e0eb0e2a7683020dffa342ab3fd15e28f035ba897cf" -dependencies = [ - "quote", - "syn 1.0.109", - "syn-mid", -] - -[[package]] -name = "neon-runtime" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4676720fa8bb32c64c3d9f49c47a47289239ec46b4bdb66d0913cc512cb0daca" -dependencies = [ - "cfg-if", - "libloading 0.6.7", - "smallvec", -] - [[package]] name = "nohash-hasher" version = "0.2.0" @@ -2198,25 +2137,11 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" dependencies = [ - "num-bigint 0.2.6", - "num-complex 0.2.4", - "num-integer", - "num-iter", - "num-rational 0.2.4", - "num-traits", -] - -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint 0.4.3", - "num-complex 0.4.3", + "num-bigint", + "num-complex", "num-integer", "num-iter", - "num-rational 0.4.1", + "num-rational", "num-traits", ] @@ -2231,17 +2156,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - [[package]] name = "num-cmp" version = "0.1.0" @@ -2258,15 +2172,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "num-complex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" -dependencies = [ - "num-traits", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -2306,19 +2211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" dependencies = [ "autocfg", - "num-bigint 0.2.6", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint 0.4.3", + "num-bigint", "num-integer", "num-traits", ] @@ -2977,7 +2870,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.17", + "semver", ] [[package]] @@ -3085,15 +2978,6 @@ dependencies = [ "cc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.17" @@ -3103,12 +2987,6 @@ dependencies = [ "serde", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "serde" version = "1.0.160" @@ -3397,17 +3275,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn-mid" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baa8e7560a164edb1621a55d18a0c59abf49d360f47aa7b821061dd7eea7fac9" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "synstructure" version = "0.12.6" @@ -3446,7 +3313,7 @@ source = "git+https://github.com/dashpay/rs-tenderdash-abci#e66a7d6683c0843f11e9 dependencies = [ "bytes", "prost", - "semver 1.0.17", + "semver", "tenderdash-proto", "thiserror", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 1e84b12d923..0353b5edae1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,6 @@ members = [ "packages/rs-drive", "packages/rs-platform-value", "packages/rs-drive-abci", - "packages/rs-drive-nodejs", "packages/dashpay-contract", "packages/withdrawals-contract", "packages/masternode-reward-shares-contract", diff --git a/package.json b/package.json index a3170a24d7f..813502242d9 100644 --- a/package.json +++ b/package.json @@ -59,14 +59,12 @@ "packages/wallet-lib", "packages/js-dash-sdk", "packages/dapi", - "packages/js-drive", "packages/dashmate", "packages/platform-test-suite", "packages/masternode-reward-shares-contract", "packages/dash-spv", "packages/wasm-dpp", - "packages/withdrawals-contract", - "packages/rs-drive-nodejs" + "packages/withdrawals-contract" ], "resolutions": { "elliptic": "^6.5.4", diff --git a/packages/js-drive/.env.example b/packages/js-drive/.env.example deleted file mode 100644 index c0afd31ff42..00000000000 --- a/packages/js-drive/.env.example +++ /dev/null @@ -1,71 +0,0 @@ -# ABCI host and port to listen -ABCI_HOST=0.0.0.0 -ABCI_PORT=26658 - -DB_PATH=./db - -# GroveDB database file -GROVEDB_LATEST_FILE=${DB_PATH}/latest_state - -# Cache size for Data Contracts -DATA_CONTRACTS_GLOBAL_CACHE_SIZE=500 -DATA_CONTRACTS_BLOCK_CACHE_SIZE=200 - -# DashCore JSON-RPC host, port and credentials -# Read more: https://dashcore.readme.io/docs/core-api-ref-remote-procedure-calls -CORE_JSON_RPC_HOST=127.0.0.1 -CORE_JSON_RPC_PORT=9998 -CORE_JSON_RPC_USERNAME=dashrpc -CORE_JSON_RPC_PASSWORD=password - -# DashCore ZMQ host and port -CORE_ZMQ_HOST=127.0.0.1 -CORE_ZMQ_PORT=29998 -CORE_ZMQ_CONNECTION_RETRIES=16 - -NETWORK=testnet - -INITIAL_CORE_CHAINLOCKED_HEIGHT= - -# https://github.com/dashevo/dashcore-lib/blob/286c33a9d29d33f05d874c47a9b33764a0be0cf1/lib/constants/index.js#L42-L57 -VALIDATOR_SET_LLMQ_TYPE=100 - -# DPNS Contract - -DPNS_MASTER_PUBLIC_KEY= -DPNS_SECOND_PUBLIC_KEY= - -# Dashpay Contract - -DASHPAY_MASTER_PUBLIC_KEY= -DASHPAY_SECOND_PUBLIC_KEY= - -# Feature flags contract - -FEATURE_FLAGS_MASTER_PUBLIC_KEY= -FEATURE_FLAGS_SECOND_PUBLIC_KEY= - -# Masternode reward shares contract - -MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY= -MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY= - -# Withdrawals contract - -WITHDRAWALS_MASTER_PUBLIC_KEY= -WITHDRAWALS_SECOND_PUBLIC_KEY= - -# logging -LOG_STDOUT_LEVEL=info - -LOG_PRETTY_FILE_LEVEL=silent -LOG_PRETTY_FILE_PATH=/tmp/drive-pretty.log - -LOG_JSON_FILE_LEVEL=silent -LOG_JSON_FILE_PATH=/tmp/drive-json.log - -LOG_STATE_REPOSITORY=false - -NODE_ENV=production - -TENDERDASH_P2P_PORT=26656 diff --git a/packages/js-drive/.eslintrc b/packages/js-drive/.eslintrc deleted file mode 100644 index 53708855109..00000000000 --- a/packages/js-drive/.eslintrc +++ /dev/null @@ -1,36 +0,0 @@ -{ - "extends": "airbnb-base", - "env": { - "es2021": true, - "node": true - }, - "parser": "babel-eslint", - "rules": { - "no-plusplus": 0, - "eol-last": [ - "error", - "always" - ], - "no-continue": "off", - "class-methods-use-this": "off", - "no-await-in-loop": "off", - "no-restricted-syntax": [ - "error", - { - "selector": "LabeledStatement", - "message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand." - }, - { - "selector": "WithStatement", - "message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize." - } - ], - "curly": [ - "error", - "all" - ] - }, - "globals": { - "BigInt": true - } -} diff --git a/packages/js-drive/.mocharc.yml b/packages/js-drive/.mocharc.yml deleted file mode 100644 index 4f6cc77a7d5..00000000000 --- a/packages/js-drive/.mocharc.yml +++ /dev/null @@ -1,4 +0,0 @@ -exit: true -timeout: 5000 -file: - - ./lib/test/bootstrap.js diff --git a/packages/js-drive/CHANGELOG.md b/packages/js-drive/CHANGELOG.md deleted file mode 100644 index e0e0e75d9aa..00000000000 --- a/packages/js-drive/CHANGELOG.md +++ /dev/null @@ -1,509 +0,0 @@ -## [0.21.1](https://github.com/dashevo/js-drive/compare/v0.21.0...v0.21.1) (2021-10-28) - - -### Bug Fixes - -* getFeatureFlagForHeight must not try to fetch feature flags before they were created ([#575](https://github.com/dashevo/js-drive/issues/575)) - - - -# [0.21.0](https://github.com/dashevo/js-drive/compare/v0.20.0...v0.21.0) (2021-10-14) - - -### Features - -* support higher protocol version ([#571](https://github.com/dashevo/js-drive/issues/571)) -* set protocol version on `begin block` ([#558](https://github.com/dashevo/js-drive/issues/558)) -* comprehensive error codes ([#564](https://github.com/dashevo/js-drive/issues/564), [#572](https://github.com/dashevo/js-drive/issues/572)) -* multiproof for the identity non inclusion proof root tree ([#560](https://github.com/dashevo/js-drive/issues/560)) - - -### Bug Fixes - -* consensus logger wasn't set on error ([#567](https://github.com/dashevo/js-drive/issues/567)) -* previousRootTree not rebuilt on commit, resulting in a wrong proof ([#563](https://github.com/dashevo/js-drive/issues/563)) - - - -# [0.20.0](https://github.com/dashevo/js-drive/compare/v0.19.3...v0.20.0) (2021-07-22) - - -### Features - -* use latest version of Merk storage ([#546](https://github.com/dashevo/js-drive/issues/546)) -* remove chainlock SML verification in favor of more robust core verification ([#536](https://github.com/dashevo/js-drive/issues/536)) -* remove SML instant lock verification in favor of more robust core verification [#533](https://github.com/dashevo/js-drive/issues/533)) -* make compatible with Tenderdash v0.5 ([#527](https://github.com/dashevo/js-drive/issues/527)) -* add additional info to proofs ([#518](https://github.com/dashevo/js-drive/issues/518), [#523](https://github.com/dashevo/js-drive/issues/523), [#525](https://github.com/dashevo/js-drive/issues/525), [#540](https://github.com/dashevo/js-drive/issues/540), [#542](https://github.com/dashevo/js-drive/issues/542)) -* validator set rotation ([#446](https://github.com/dashevo/js-drive/issues/446), [#515](https://github.com/dashevo/js-drive/issues/515), [#517](https://github.com/dashevo/js-drive/issues/517), [#530](https://github.com/dashevo/js-drive/issues/530), [#531](https://github.com/dashevo/js-drive/issues/531), ) - - -### Bug Fixes - -* invalid instant lock if no blocks are produced ([#513](https://github.com/dashevo/js-drive/issues/513)) -* `getProofs` method was missing from `PublicKeyToIdentityIdStoreRootTreeLeaf` class ([#544](https://github.com/dashevo/js-drive/issues/544)) -* typo in trace output ([#516](https://github.com/dashevo/js-drive/issues/516)) - - -### BREAKING CHANGES - -* `document`, `dataContract`, `identity`, `identityIdsByPublicKeyHashes` and `identitiesByPublicKeyHashes` query handlers now returns Protobuf messages instead of cbor'ed data. data is not sent if a proof is requested -* `VALIDATOR_SET_LLMQ_TYPE` env is required -* due to changes in hashing algorithm `appHash` is no longer same and not reproducible for old blocks hence new nodes would not be able to sync -* removing SML IS lock verification make some previously invalid transactions valid -* not compatible with Tenderdash v0.4 -* new ABCI messages and types not compatible with previous ones - - - -## [0.19.3](https://github.com/dashevo/js-drive/compare/v0.19.2...v0.19.3) (2021-06-04) - - -### Bug Fixes - -* documents were deleted using wrong id ([#514](https://github.com/dashevo/js-drive/issues/514)) - - - -## [0.19.2](https://github.com/dashevo/js-drive/compare/v0.19.1...v0.19.2) (2021-05-25) - - -### Bug Fixes - -* InvalidQuery error due to feature flags ([#512](https://github.com/dashevo/js-drive/issues/512)) - - - -## [0.19.1](https://github.com/dashevo/js-drive/compare/v0.19.0...v0.19.1) (2021-05-13) - - -### Bug Fixes - -* feature flags contract height variable has had an invalid name ([#509](https://github.com/dashevo/js-drive/issues/509)) - - - -# [0.19.0](https://github.com/dashevo/js-drive/compare/v0.18.1...v0.19.0) (2021-05-05) - - -### Features - -* use Dash Core to verify chain locks ([#503](https://github.com/dashevo/js-drive/issues/503), [#505](https://github.com/dashevo/js-drive/issues/505), [#506](https://github.com/dashevo/js-drive/issues/506)) -* verify instant locks using Dash Core ([#499](https://github.com/dashevo/js-drive/issues/499), [#501](https://github.com/dashevo/js-drive/issues/501), [#492](https://github.com/dashevo/js-drive/issues/492), [#498](https://github.com/dashevo/js-drive/issues/498)) -* feature flags ([#491](https://github.com/dashevo/js-drive/issues/491), [#504](https://github.com/dashevo/js-drive/issues/504), [#485](https://github.com/dashevo/js-drive/issues/485)) -* output Core network on start ([#490](https://github.com/dashevo/js-drive/issues/490)) -* update js-dp-services-ctl to 0.19-dev ([#486](https://github.com/dashevo/js-drive/issues/486)) -* enable docker build npm cache ([#478](https://github.com/dashevo/js-drive/issues/478)) -* do not setup node if SKIP_TEST_SUITE option is set ([#480](https://github.com/dashevo/js-drive/issues/480)) -* remove regtest fallbacks ([#477](https://github.com/dashevo/js-drive/issues/477)) -* add `verifyInstantLock` in favor of `getSMLStore` method ([#474](https://github.com/dashevo/js-drive/issues/474)) - - -### Bug Fixes - -* error loading shared library libzmq.so.5 ([#483](https://github.com/dashevo/js-drive/issues/483)) -* blockExecutionContext header might be null ([#481](https://github.com/dashevo/js-drive/issues/481)) - - -### BREAKING CHANGES - -* running in standalone regtest mode is not supported anymore -* `fetchSMLStore` method has been removed -* See [DPP v0.19 breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.19.0) - - -# [0.18.1](https://github.com/dashevo/js-drive/compare/v0.18.0...v0.18.1) (2021-03-08) - - -### Documentation - -* polish changelog ([ac434e](https://github.com/dashevo/dapi/commit/ac434eea9e1588077445ac13a7f4c066a710a3ec)) - - - -# [0.18.0](https://github.com/dashevo/js-drive/compare/v0.17.14...v0.18.0) (2021-03-03) - - -### Bug Fixes - -* ABCI request length error still not parsing properly ([#476](https://github.com/dashevo/js-drive/issues/476)) - - -### Features - -* output ABCI connection error message ([ff3660a](https://github.com/dashevo/js-drive/commit/ff3660a638f0f4170ff3f7242f84c256e75fa4c6)) -* getProofs ABCI query endpoint ([#451](https://github.com/dashevo/js-drive/issues/451), [#462](https://github.com/dashevo/js-drive/issues/462)) - - - -## [0.17.14](https://github.com/dashevo/js-drive/compare/v0.18.0-dev.5...v0.17.14) (2021-02-20) - - -### Bug Fixes - -* can't parse ABCI request length error ([f55fac7](https://github.com/dashevo/js-drive/commit/f55fac7aced9334cf26e930cfaf23258cec66a9d)) - - - -## [0.17.13](https://github.com/dashevo/js-drive/compare/v0.17.12...v0.17.13) (2021-02-19) - - -### Features - -* reimplemented ABCI server for better reliability ([#475](https://github.com/dashevo/js-drive/issues/475)) - - - -## [0.17.12](https://github.com/dashevo/js-drive/compare/v0.17.11...v0.17.12) (2021-02-16) - - -### Features - -* better handle abci connection errors ([f4348e9](https://github.com/dashevo/js-drive/commit/f4348e944825dc9b554eec8dcf7752e972081b2a)) - - - -## [0.17.11](https://github.com/dashevo/js-drive/compare/v0.17.8...v0.17.11) (2021-02-16) - - -### Bug Fixes - -* stack overflow due to write on write error ([cb3e0ac](https://github.com/dashevo/js-drive/commit/cb3e0ac4212d95372c2b402496125afdf5e69cea)) - - - -## [0.17.10](https://github.com/dashevo/js-drive/compare/v0.17.8...v0.17.10) (2021-02-16) - - -### Bug Fixes - -* abci connection error writes to closed stream ([41a891a](https://github.com/dashevo/js-drive/commit/41a891a922bf2f924c543410dd6d19b3a3ba03d0)) - - - -## [0.17.9](https://github.com/dashevo/js-drive/compare/v0.17.8...v0.17.9) (2021-02-15) - - -### Features - -* robust error handling ([#473](https://github.com/dashevo/js-drive/issues/473)) -* use a different handler for ABCI connection error ([#465](https://github.com/dashevo/js-drive/issues/465), [b9d452a](https://github.com/dashevo/js-drive/commit/b9d452a20bdf75699fa532eb69af7500fc985045)) - - - -## [0.17.8](https://github.com/dashevo/js-drive/compare/v0.17.7...v0.17.8) (2021-02-11) - - -### Bug Fixes - -* could not resolve `previousBlockExecutionStoreTransactions` on query ([#470](https://github.com/dashevo/js-drive/issues/470)) - - -### Features - -* add `driveVersion` to every log output ([#469](https://github.com/dashevo/js-drive/issues/469)) -* await Node logger stream to be ended ([#471](https://github.com/dashevo/js-drive/issues/471)) -* distinguishing log data ([#472](https://github.com/dashevo/js-drive/issues/472)) - - - -## [0.17.7](https://github.com/dashevo/js-drive/compare/v0.17.6...v0.17.7) (2021-02-04) - - -### Features - -* disable state repository and merk logging by default ([#467](https://github.com/dashevo/js-drive/issues/467)) - - - -## [0.17.6](https://github.com/dashevo/js-drive/compare/v0.17.5...v0.17.6) (2021-01-26) - - -### Bug Fixes - -* only info log level is present in log streams ([#463](https://github.com/dashevo/js-drive/issues/463)) - - - -## [0.17.5](https://github.com/dashevo/js-drive/compare/v0.17.4...v0.17.5) (2021-01-21) - - -### Features - -* different logging levels ([#461](https://github.com/dashevo/js-drive/issues/461)) - - -### BREAKING CHANGES - -* `LOGGING_LEVEL` is ignored. Use `LOG_STDOUT_LEVEL`. - - - -## [0.17.4](https://github.com/dashevo/js-drive/compare/v0.17.3...v0.17.4) (2021-01-20) - - -### Bug Fixes - -* logger with context is not used in some cases ([#458](https://github.com/dashevo/js-drive/issues/458)) -* tx counters and logger were not reset ([#460](https://github.com/dashevo/js-drive/issues/460)) - - -### Features - -* log to human-readable and json files ([#459](https://github.com/dashevo/js-drive/issues/459)) - - - -## [0.17.3](https://github.com/dashevo/js-drive/compare/v0.17.2...v0.17.3) (2021-01-20) - - -### Features - -* better logging ([#456](https://github.com/dashevo/js-drive/issues/456)) - - - -## [0.17.2](https://github.com/dashevo/js-drive/compare/v0.17.1...v0.17.2) (2021-01-19) - - -### Bug Fixes - -* could not resolve 'previousBlockExecutionStoreTransactions' ([5a9dbff](https://github.com/dashevo/js-drive/commit/5a9dbffb05cfb85e6e394ed79538d979eb4a73a7)) -* ST isolation leads to non-deterministic results ([#455](https://github.com/dashevo/js-drive/issues/455)) -* handle rawChainLockMessage parsing errors ([#454](https://github.com/dashevo/js-drive/issues/454)) - - - -## [0.17.1](https://github.com/dashevo/js-drive/compare/v0.17.0...v0.17.1) (2021-01-12) - - -### Bug Fixes - -* duplicate MongoDB index name ([#453](https://github.com/dashevo/js-drive/issues/453)) - - - -# [0.17.0](https://github.com/dashevo/js-drive/compare/v0.16.1...v0.17.0) (2020-12-30) - - -### Features - -* introduce `DriveStateRepository#fetchSMLStore` ([#444](https://github.com/dashevo/js-drive/issues/444), [#445](https://github.com/dashevo/js-drive/issues/445)) -* update `dashcore-lib` ([#411](https://github.com/dashevo/js-drive/issues/411), [#442](https://github.com/dashevo/js-drive/issues/442), [#443](https://github.com/dashevo/js-drive/issues/443)) -* add old zmq client from DAPI ([#439](https://github.com/dashevo/js-drive/issues/439)) -* dashpay contract support ([#441](https://github.com/dashevo/js-drive/issues/441)) -* change merk to @dashevo/merk -* gracefull shutdown on SIGINT, SIGTERM, SIGQUIT and unhandled errors ([#427](https://github.com/dashevo/js-drive/issues/427)) -* handle core chain locked height ([#428](https://github.com/dashevo/js-drive/issues/428)) -* implement verify chainlock query handler ([#402](https://github.com/dashevo/js-drive/issues/402)) -* intermediate merk tree for the current block ([#429](https://github.com/dashevo/js-drive/issues/429)) -* pass latestCoreChainLock on block end ([#434](https://github.com/dashevo/js-drive/issues/434)) -* provide proofs for getIdentitiesByPublicKeyHashes endpoint ([#422](https://github.com/dashevo/js-drive/issues/422)) -* provide proofs for getIdentitiyIdsByPublicKeyHashes endpoint ([#419](https://github.com/dashevo/js-drive/issues/419)) -* provide proofs in ABCI query and DAPI getIdentity ([#415](https://github.com/dashevo/js-drive/issues/415)) -* set IDENTITY_SKIP_ASSET_LOCK_CONFIRMATION_VALIDATION to false ([#437](https://github.com/dashevo/js-drive/issues/437)) -* sort keys for MerkDB ([#413](https://github.com/dashevo/js-drive/issues/413)) -* store ChainInfo in MerkDb ([#404](https://github.com/dashevo/js-drive/issues/404)) -* store Data Contracts in merk tree ([#405](https://github.com/dashevo/js-drive/issues/405)) -* store documents in MerkDb ([#410](https://github.com/dashevo/js-drive/issues/410)) -* store height in externalStorage instead of merkDB ([#433](https://github.com/dashevo/js-drive/issues/433)) -* store identities in merk tree ([#400](https://github.com/dashevo/js-drive/issues/400)) -* store Public Key to Identity ID in MerkDb ([#409](https://github.com/dashevo/js-drive/issues/409)) -* update `dpp` to include asset lock verification logic ([#432](https://github.com/dashevo/js-drive/issues/432)) -* introduce merkle forest ([#401](https://github.com/dashevo/js-drive/issues/401)) -* move block execution context out of blockchain state ([#403](https://github.com/dashevo/js-drive/issues/403)) -* add abstraction for MerkDb ([#407](https://github.com/dashevo/js-drive/issues/407)) - - -### Bug Fixes - -* hash was used as a Buffer where it should be hex string ([#440](https://github.com/dashevo/js-drive/issues/440)) -* documents DB transaction is already started error ([#417](https://github.com/dashevo/js-drive/issues/417)) -* e.getErrors is not a function error ([#418](https://github.com/dashevo/js-drive/issues/418)) -* missing nested indexed fields and transaction ([#426](https://github.com/dashevo/js-drive/issues/426)) - - -### BREAKING CHANGES - -* AppHash is not equal to nils anymore. -* data created with 0.16 and lower versions of Drive is not compatible anymore -* ABCI query responses are changed - - - -## [0.16.1](https://github.com/dashevo/js-drive/compare/v0.16.0...v0.16.1) (2020-10-29) - - -### Bug Fixes - -* `header` is not present in `RequestEndBlock` ([#399](https://github.com/dashevo/js-drive/issues/399)) - - - -# [0.16.0](https://github.com/dashevo/js-drive/compare/v0.15.0...v0.16.0) (2020-10-28) - - -### Bug Fixes - -* incorrect deliver state transition hash logging ([#396](https://github.com/dashevo/js-drive/issues/396)) - - -### Features - -* verify DPNS contract existence ([#397](https://github.com/dashevo/js-drive/issues/397)) -* add `LoggedStateRepositoryDecorator` ([#393](https://github.com/dashevo/js-drive/issues/393)) -* debug mode to respond internal error with message and stack ([#383](https://github.com/dashevo/js-drive/issues/383)) -* implement `fetchIdentityIdsByPublicKeys` method ([#385](https://github.com/dashevo/js-drive/issues/385)) -* implement `storeIdentityPublicKeyHashes` method ([#387](https://github.com/dashevo/js-drive/issues/387)) -* implement getting identities by multiple public keys hashes ([#388](https://github.com/dashevo/js-drive/issues/388), [#395](https://github.com/dashevo/js-drive/issues/395), [#386](https://github.com/dashevo/js-drive/issues/386)) -* update DPP to 0.16.0 ([#392](https://github.com/dashevo/js-drive/issues/392)) - - -### Refactoring - -* remove unnecessary InvalidDocumentTypeError handling ([#384](https://github.com/dashevo/js-drive/issues/384)) - - -### BREAKING CHANGES - -* If `DPNS_CONTRACT_ID` is set it requires `DPNS_CONTRACT_BLOCK_HEIGHT` to be set too. -* See [DPP v0.16 breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.16.0) - - - -# [0.15.0](https://github.com/dashevo/js-drive/compare/v0.14.0...v0.15.0) (2020-09-04) - - -### Bug Fixes - -* internal errors are not logged ([#380](https://github.com/dashevo/js-drive/issues/380)) -* unique index throws duplicate key error (#378) - - -### Features - -* handle protocol and software versions ([#377](https://github.com/dashevo/js-drive/issues/377)) -* handle user-defined binary fields ([#373](https://github.com/dashevo/js-drive/issues/373), [#381](https://github.com/dashevo/js-drive/issues/381)) - - -### BREAKING CHANGES - -* protocol version (`AppVersion`) is required in a Tendermint block header -* the previous state is not compatible due to new DPP serialization format -* See [DPP breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.15.0) - - - -# [0.14.0](https://github.com/dashevo/drive/compare/v0.13.2...v0.14.0) (2020-07-23) - - -### Features - -* increase MongoDB query allowed field length ([#366](https://github.com/dashevo/drive/issues/366)) -* logging of block execution process ([#365](https://github.com/dashevo/drive/issues/365)) -* use test suite to run functional and e2e tests ([#362](https://github.com/dashevo/drive/issues/362)) -* update to DPP v0.14 with timestamps ([#363](https://github.com/dashevo/drive/issues/363)) - - -### BREAKING CHANGES - -* See [DPP v0.14 breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.14.0) - - - -## [0.13.2](https://github.com/dashevo/drive/compare/v0.13.0-dev.2...v0.13.2) (2020-06-12) - - -### Bug Fixes - -* internal errors lead to inability to fix bugs as it leads to a state inconsistency ([#360](https://github.com/dashevo/drive/issues/360)) - - - -## [0.13.1](https://github.com/dashevo/drive/compare/v0.13.0...v0.13.1) (2020-06-12) - - -### Bug Fixes - -* document repository not created properly due to missing `await` ([#358](https://github.com/dashevo/drive/issues/358)) - - - -# [0.13.0](https://github.com/dashevo/drive/compare/v0.12.1...v0.13.0) (2020-06-08) - - -### Features - -* update to DPP 0.13 ([#336](https://github.com/dashevo/drive/issues/336), [#338](https://github.com/dashevo/drive/issues/338), [#340](https://github.com/dashevo/drive/issues/340), [#344](https://github.com/dashevo/drive/issues/344), [#346](https://github.com/dashevo/drive/issues/346), [#348](https://github.com/dashevo/drive/issues/348), [#354](https://github.com/dashevo/drive/issues/354), [#357](https://github.com/dashevo/drive/issues/357)) -* wait mongoDB replica set initialization ([#349](https://github.com/dashevo/drive/issues/349)) -* wait for Core to be synced before starting ([#345](https://github.com/dashevo/drive/issues/345), [#353](https://github.com/dashevo/drive/issues/353), [#356](https://github.com/dashevo/drive/issues/356)) -* get identity by public key endpoints ([#341](https://github.com/dashevo/drive/issues/341)) -* store identity id with identity's public key as a DB key ([#337](https://github.com/dashevo/drive/issues/337), [#339](https://github.com/dashevo/drive/issues/339)) - - -### Code Refactoring - -* use async function with cache to connect and get `MongoClient` ([#350](https://github.com/dashevo/drive/issues/350)) - - -### BREAKING CHANGES - -* see [DPP breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.13.0) - - - -## [0.12.2](https://github.com/dashevo/drive/compare/v0.12.1...v0.12.2) (2020-05-21) - - -### Bug Fixes - -* validateFee error handling expects only BalanceIsNotEnoughError ([#343](https://github.com/dashevo/drive/issues/343)) - - - -## [0.12.1](https://github.com/dashevo/drive/compare/v0.12.0...v0.12.1) (2020-04-22) - - -### Features - -* update `dpp` version to `0.12.1` ([#335](https://github.com/dashevo/drive/issues/335)) - - -# [0.12.0](https://github.com/dashevo/drive/compare/v0.11.1...v0.12.0) (2020-04-18) - -### Features - -* publish docker image with tag for every Semver segment ([#332](https://github.com/dashevo/drive/issues/332)) -* introduce ABCI and Machine logic, remove API and upgrade to DPP 0.12 ([#328](https://github.com/dashevo/drive/issues/328)) -* validate fee, reduce balance and move fees to distribution pool ([#329](https://github.com/dashevo/drive/issues/329)) - -### BREAKING CHANGES - -* JSON RPC and gRPC endpoints are removed. Use Tendermint ABCI query endpoint in order to fetch data -* see [DPP breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.12.0) - - -## [0.11.1](https://github.com/dashevo/drive/compare/v0.11.0...v0.11.1) (2020-03-17) - -### Bug Fixes - -* do not validate ST second time in `applyStateTransition` ([d296608](https://github.com/dashevo/drive/commit/d29660886deb7e5556c5346da54506aebc005bfa)) -* check for MongoDb replica set on start ([286074f](https://github.com/dashevo/drive/commit/286074fe297bb693ffe7492523e560aeb2512330)) - -# [0.11.0](https://github.com/dashevo/drive/compare/v0.7.0...v0.11.0) (2020-03-09) - -### Bug Fixes - -* prevent to update dependencies with major version `0` to minor versions ([9f1dd95](https://github.com/dashevo/drive/commit/9f1dd95fe2294de2d0a3157807eec9598d0f0db7)) - -### Features - -* upgrade DPP to v0.11 ([9797e51](https://github.com/dashevo/drive/commit/9797e51bee6899c07aabcf733fa54650037c42cd)) - -### Chore - -* update gRPC errors ([1d31326](https://github.com/dashevo/drive/commit/1d31326977b2b5f1537426d9d31d89f459aaace6)) - -### BREAKING CHANGES - -* see [DPP breaking changes](https://github.com/dashevo/js-dpp/releases/tag/v0.11.0) diff --git a/packages/js-drive/Dockerfile b/packages/js-drive/Dockerfile deleted file mode 100644 index 0dfb7f69180..00000000000 --- a/packages/js-drive/Dockerfile +++ /dev/null @@ -1,114 +0,0 @@ -# syntax = docker/dockerfile:1.3 -FROM node:16-alpine3.16 as builder - -ARG NODE_ENV=production -ENV NODE_ENV ${NODE_ENV} - -ARG CARGO_BUILD_PROFILE=debug -ENV CARGO_BUILD_PROFILE ${CARGO_BUILD_PROFILE} - -RUN apk update && \ - apk --no-cache upgrade && \ - apk add --no-cache git \ - openssh-client \ - linux-headers \ - python3 \ - alpine-sdk \ - cmake \ - zeromq-dev \ - ca-certificates \ - gcc \ - clang \ - libc-dev \ - binutils \ - bash - -# Install Rust -ENV RUSTUP_HOME=/usr/local/rustup \ - CARGO_HOME=/usr/local/cargo \ - PATH=/usr/local/cargo/bin:$PATH \ - RUST_VERSION=stable - -RUN set -eux; \ - apkArch="$(apk --print-arch)"; \ - case "$apkArch" in \ - x86_64) rustArch='x86_64-unknown-linux-musl'; rustupSha256='bdf022eb7cba403d0285bb62cbc47211f610caec24589a72af70e1e900663be9' ;; \ - aarch64) rustArch='aarch64-unknown-linux-musl'; rustupSha256='89ce657fe41e83186f5a6cdca4e0fd40edab4fd41b0f9161ac6241d49fbdbbbe' ;; \ - *) echo >&2 "unsupported architecture: $apkArch"; exit 1 ;; \ - esac; \ - url="https://static.rust-lang.org/rustup/archive/1.24.3/${rustArch}/rustup-init"; \ - wget "$url"; \ - echo "${rustupSha256} *rustup-init" | sha256sum -c -; \ - chmod +x rustup-init; \ - ./rustup-init -y --no-modify-path --profile minimal --default-toolchain $RUST_VERSION --default-host ${rustArch}; \ - rm rustup-init; \ - chmod -R a+w $RUSTUP_HOME $CARGO_HOME; \ - rustup --version; \ - cargo --version; \ - rustc --version; - -# Enable corepack https://github.com/nodejs/corepack -RUN corepack enable - -# Print build output -RUN yarn config set enableInlineBuilds true - -WORKDIR /platform - -# Copy yarn and Cargo files -COPY .yarn /platform/.yarn -COPY .cargo /platform/.cargo -COPY package.json yarn.lock .yarnrc.yml .pnp.* Cargo.toml Cargo.lock rust-toolchain.toml ./ - -# Copy only necessary packages from monorepo -COPY packages/js-drive packages/js-drive -COPY packages/rs-dpp packages/rs-dpp -COPY packages/wasm-dpp packages/wasm-dpp -COPY packages/rs-drive packages/rs-drive -COPY packages/rs-drive-abci packages/rs-drive-abci -COPY packages/rs-platform-value packages/rs-platform-value -COPY packages/rs-drive-nodejs packages/rs-drive-nodejs -COPY packages/dapi-grpc packages/dapi-grpc -COPY packages/js-dpp packages/js-dpp -COPY packages/js-grpc-common packages/js-grpc-common -COPY packages/dashpay-contract packages/dashpay-contract -COPY packages/dpns-contract packages/dpns-contract -COPY packages/feature-flags-contract packages/feature-flags-contract -COPY packages/masternode-reward-shares-contract packages/masternode-reward-shares-contract -COPY packages/withdrawals-contract packages/withdrawals-contract -COPY packages/data-contracts packages/data-contracts - -# Build RS Drive Node.JS binding -RUN --mount=type=cache,target=target \ - --mount=type=cache,target=$CARGO_HOME/git \ - --mount=type=cache,target=$CARGO_HOME/registry \ - yarn workspace @dashevo/rs-drive build - -# Install Drive-specific dependencies using previous -# node_modules directory to reuse built binaries -RUN --mount=type=cache,target=/tmp/unplugged \ - cp -R /tmp/unplugged /platform/.yarn/ && \ - yarn workspaces focus --production @dashevo/drive && \ - cp -R /platform/.yarn/unplugged /tmp/ - -FROM node:16-alpine3.16 - -ARG NODE_ENV=production -ENV NODE_ENV ${NODE_ENV} - -LABEL maintainer="Dash Developers " -LABEL description="Drive Node.JS" - -# Install ZMQ shared library -RUN apk update && apk add --no-cache zeromq-dev - -WORKDIR /platform - -COPY --from=builder /platform /platform - -# Remove Rust sources -RUN rm -rf packages/rs-drive packages/rs-drive-abci packages/rs-dpp packages/rs-platform-value - -RUN cp /platform/packages/js-drive/.env.example /platform/packages/js-drive/.env - -EXPOSE 26658 diff --git a/packages/js-drive/LICENSE b/packages/js-drive/LICENSE deleted file mode 100644 index 54f58e74bf7..00000000000 --- a/packages/js-drive/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017-2023 Dash Core Group, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/packages/js-drive/README.md b/packages/js-drive/README.md deleted file mode 100644 index 23763e50481..00000000000 --- a/packages/js-drive/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# Drive - -[![Latest Release](https://img.shields.io/github/v/release/dashpay/platform)](https://github.com/dashpay/platform/releases/latest) -[![Build Status](https://github.com/dashpay/platform/actions/workflows/release.yml/badge.svg)](https://github.com/dashpay/platform/actions/workflows/release.yml) -[![Release Date](https://img.shields.io/github/release-date/dashpay/platform)](https://github.com/dashpay/platform/releases/latest) -[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen)](https://github.com/RichardLitt/standard-readme) - -Replicated state machine for Dash Platform - -Drive is the storage component of Dash Platform, allowing developers to store and secure their application data through Dash's masternode network. Application data structures are defined by a data contract, which is stored on Drive and used to verify/validate updates to your application data. - -## Table of Contents -- [Install](#install) -- [Usage](#usage) -- [Configuration](#configuration) -- [Tests](#tests) -- [Maintainer](#maintainer) -- [Contributing](#contributing) -- [License](#license) - -## Install - -1. [Install Node.JS 12 or higher](https://nodejs.org/en/download/) -2. Copy `.env.example` to `.env` file -3. Install npm dependencies: `npm install` - -## Usage - -```bash -npm run abci -``` - -## Configuration - -Drive uses environment variables for configuration. -Variables are read from `.env` file and can be overwritten by variables -defined in env or directly passed to the process. - -See all available settings in [.env.example](.env.example). - -## Tests - -[Read](test/) about tests in `test/` folder. - -## Maintainer - -[@shumkov](https://github.com/shumkov) - -## Contributing - -Feel free to dive in! [Open an issue](https://github.com/dashpay/platform/issues/new/choose) or submit PRs. - -## License - -[MIT](LICENSE) © Dash Core Group, Inc. diff --git a/packages/js-drive/db/.gitignore b/packages/js-drive/db/.gitignore deleted file mode 100644 index 593bcf0e80e..00000000000 --- a/packages/js-drive/db/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -!.gitignore -* diff --git a/packages/js-drive/lib/abci/closeAbciServerFactory.js b/packages/js-drive/lib/abci/closeAbciServerFactory.js deleted file mode 100644 index 141cdeb9b3b..00000000000 --- a/packages/js-drive/lib/abci/closeAbciServerFactory.js +++ /dev/null @@ -1,25 +0,0 @@ -const { promisify } = require('util'); - -/** - * - * @param {net.Server} abciServer - * @return {closeAbciServer} - */ -function closeAbciServerFactory(abciServer) { - /** - * @typedef {closeAbciServer} - * @return {Promise} - */ - async function closeAbciServer() { - if (!abciServer.listening) { - return; - } - - const close = promisify(abciServer.close.bind(abciServer)); - await close(); - } - - return closeAbciServer; -} - -module.exports = closeAbciServerFactory; diff --git a/packages/js-drive/lib/abci/errors/AbstractAbciError.js b/packages/js-drive/lib/abci/errors/AbstractAbciError.js deleted file mode 100644 index ae054bc477d..00000000000 --- a/packages/js-drive/lib/abci/errors/AbstractAbciError.js +++ /dev/null @@ -1,68 +0,0 @@ -const cbor = require('cbor'); - -const DriveError = require('../../errors/DriveError'); - -/** - * @abstract - */ -class AbstractAbciError extends DriveError { - /** - * - * @param {number} code - * @param {string} message - * @param {Object} data - */ - constructor(code, message, data) { - super(message); - - this.code = code; - this.data = data; - } - - /** - * @returns {string} - */ - getMessage() { - return this.message; - } - - /** - * Get error code - * - * @returns {number} - */ - getCode() { - return this.code; - } - - /** - * Get error data - * - * @returns {Object} - */ - getData() { - return this.data; - } - - /** - * @returns {{code: number, info: string}} - */ - getAbciResponse() { - const info = { - message: this.getMessage(), - }; - - const data = this.getData(); - - if (Object.keys(data).length > 0) { - info.data = data; - } - - return { - code: this.getCode(), - info: cbor.encode(info).toString('base64'), - }; - } -} - -module.exports = AbstractAbciError; diff --git a/packages/js-drive/lib/abci/errors/DPPValidationAbciError.js b/packages/js-drive/lib/abci/errors/DPPValidationAbciError.js deleted file mode 100644 index 7fcf434a5c0..00000000000 --- a/packages/js-drive/lib/abci/errors/DPPValidationAbciError.js +++ /dev/null @@ -1,44 +0,0 @@ -const cbor = require('cbor'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class DPPValidationAbciError extends AbstractAbciError { - /** - * - * @param {string} message - * @param {AbstractConsensusError} consensusError - */ - constructor(message, consensusError) { - const args = consensusError.getConstructorArguments(); - - const data = { }; - if (args.length > 0) { - data.arguments = args; - } - - super(consensusError.getCode(), message, data); - } - - /** - * @returns {{code: number, info: string}} - */ - getAbciResponse() { - const info = { }; - - const data = this.getData(); - - let encodedInfo; - if (Object.keys(data).length > 0) { - info.data = data; - - encodedInfo = cbor.encode(info).toString('base64'); - } - - return { - code: this.getCode(), - info: encodedInfo, - }; - } -} - -module.exports = DPPValidationAbciError; diff --git a/packages/js-drive/lib/abci/errors/InternalAbciError.js b/packages/js-drive/lib/abci/errors/InternalAbciError.js deleted file mode 100644 index bc5ac65b1c4..00000000000 --- a/packages/js-drive/lib/abci/errors/InternalAbciError.js +++ /dev/null @@ -1,25 +0,0 @@ -const grpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class InternalAbciError extends AbstractAbciError { - /** - * - * @param {Error} error - * @param {Object} [data] - */ - constructor(error, data = {}) { - super(grpcErrorCodes.INTERNAL, 'Internal error', data); - - this.error = error; - } - - /** - * @returns {Error} - */ - getError() { - return this.error; - } -} - -module.exports = InternalAbciError; diff --git a/packages/js-drive/lib/abci/errors/InvalidArgumentAbciError.js b/packages/js-drive/lib/abci/errors/InvalidArgumentAbciError.js deleted file mode 100644 index dc66740da1f..00000000000 --- a/packages/js-drive/lib/abci/errors/InvalidArgumentAbciError.js +++ /dev/null @@ -1,16 +0,0 @@ -const grpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class InvalidArgumentAbciError extends AbstractAbciError { - /** - * - * @param {string} message - * @param {Object} [data] - */ - constructor(message, data = {}) { - super(grpcErrorCodes.INVALID_ARGUMENT, message, data); - } -} - -module.exports = InvalidArgumentAbciError; diff --git a/packages/js-drive/lib/abci/errors/NotFoundAbciError.js b/packages/js-drive/lib/abci/errors/NotFoundAbciError.js deleted file mode 100644 index 1daeb9325c1..00000000000 --- a/packages/js-drive/lib/abci/errors/NotFoundAbciError.js +++ /dev/null @@ -1,16 +0,0 @@ -const grpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class NotFoundAbciError extends AbstractAbciError { - /** - * - * @param {string} message - * @param {Object} [data] - */ - constructor(message, data = {}) { - super(grpcErrorCodes.NOT_FOUND, message, data); - } -} - -module.exports = NotFoundAbciError; diff --git a/packages/js-drive/lib/abci/errors/UnavailableAbciError.js b/packages/js-drive/lib/abci/errors/UnavailableAbciError.js deleted file mode 100644 index 227aff45fe4..00000000000 --- a/packages/js-drive/lib/abci/errors/UnavailableAbciError.js +++ /dev/null @@ -1,16 +0,0 @@ -const grpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class UnavailableAbciError extends AbstractAbciError { - /** - * - * @param {string} message - * @param {Object} [data] - */ - constructor(message, data = {}) { - super(grpcErrorCodes.UNAVAILABLE, message, data); - } -} - -module.exports = UnavailableAbciError; diff --git a/packages/js-drive/lib/abci/errors/UnimplementedAbciError.js b/packages/js-drive/lib/abci/errors/UnimplementedAbciError.js deleted file mode 100644 index 81e279f2039..00000000000 --- a/packages/js-drive/lib/abci/errors/UnimplementedAbciError.js +++ /dev/null @@ -1,16 +0,0 @@ -const grpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const AbstractAbciError = require('./AbstractAbciError'); - -class UnimplementedAbciError extends AbstractAbciError { - /** - * - * @param {string} message - * @param {Object} [data] - */ - constructor(message, data = {}) { - super(grpcErrorCodes.UNIMPLEMENTED, message, data); - } -} - -module.exports = UnimplementedAbciError; diff --git a/packages/js-drive/lib/abci/errors/VerboseInternalAbciError.js b/packages/js-drive/lib/abci/errors/VerboseInternalAbciError.js deleted file mode 100644 index fe13d71c83c..00000000000 --- a/packages/js-drive/lib/abci/errors/VerboseInternalAbciError.js +++ /dev/null @@ -1,30 +0,0 @@ -const InternalAbciError = require('./InternalAbciError'); - -class VerboseInternalAbciError extends InternalAbciError { - /** - * - * @param {InternalAbciError} error - */ - constructor(error) { - const originalError = error.getError(); - let [, errorPath] = originalError.stack.toString().split(/\r\n|\n/); - - if (!errorPath) { - errorPath = originalError.stack; - } - - const message = `${originalError.message} ${errorPath.trim()}`; - - const data = error.getData() || {}; - data.stack = originalError.stack; - - super( - originalError, - data, - ); - - this.message = message; - } -} - -module.exports = VerboseInternalAbciError; diff --git a/packages/js-drive/lib/abci/errors/createContextLoggerFactory.js b/packages/js-drive/lib/abci/errors/createContextLoggerFactory.js deleted file mode 100644 index 4e9b52354f6..00000000000 --- a/packages/js-drive/lib/abci/errors/createContextLoggerFactory.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * - * @param {AsyncLocalStorage} abciAsyncLocalStorage - * @return {createContextLogger} - */ -function createContextLoggerFactory(abciAsyncLocalStorage) { - /** - * @typedef {createContextLogger} - * @param {Logger} logger - * @param {Object} context - * @return {Logger} - */ - function createContextLogger(logger, context) { - const contextLogger = logger.child(context); - - abciAsyncLocalStorage.getStore().set('logger', contextLogger); - - return contextLogger; - } - - return createContextLogger; -} - -module.exports = createContextLoggerFactory; diff --git a/packages/js-drive/lib/abci/errors/enrichErrorWithContextLoggerFactory.js b/packages/js-drive/lib/abci/errors/enrichErrorWithContextLoggerFactory.js deleted file mode 100644 index 2493c6d7c92..00000000000 --- a/packages/js-drive/lib/abci/errors/enrichErrorWithContextLoggerFactory.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Add consensus logger to an error (factory) - * - * @param {AsyncLocalStorage} abciAsyncLocalStorage - * @return {enrichErrorWithContextLogger} - */ -function enrichErrorWithContextLoggerFactory(abciAsyncLocalStorage) { - /** - * Add consensus logger to an error - * - * @typedef enrichErrorWithContextLogger - * - * @param {Function} method - * - * @return {Function} - */ - function enrichErrorWithContextLogger(method) { - /** - * @param {*[]} args - */ - async function methodHandler(...args) { - return abciAsyncLocalStorage.run( - new Map(), - () => method(...args).catch((error) => { - // eslint-disable-next-line no-param-reassign - error.contextLogger = abciAsyncLocalStorage.getStore().get('logger'); - - return Promise.reject(error); - }), - ); - } - - return methodHandler; - } - - return enrichErrorWithContextLogger; -} - -module.exports = enrichErrorWithContextLoggerFactory; diff --git a/packages/js-drive/lib/abci/errors/wrapInErrorHandlerFactory.js b/packages/js-drive/lib/abci/errors/wrapInErrorHandlerFactory.js deleted file mode 100644 index 8445605f767..00000000000 --- a/packages/js-drive/lib/abci/errors/wrapInErrorHandlerFactory.js +++ /dev/null @@ -1,63 +0,0 @@ -const AbstractAbciError = require('./AbstractAbciError'); -const InternalAbciError = require('./InternalAbciError'); -const VerboseInternalAbciError = require('./VerboseInternalAbciError'); - -/** - * @param {BaseLogger} logger - * @param {boolean} isProductionEnvironment - * - * @return wrapInErrorHandler - */ -function wrapInErrorHandlerFactory(logger, isProductionEnvironment) { - /** - * Wrap ABCI methods in error handler - * - * @typedef wrapInErrorHandler - * - * @param {Function} method - * - * @return {Function} - */ - function wrapInErrorHandler(method) { - /** - * @param {*[]} args - */ - async function methodErrorHandler(...args) { - try { - return await method(...args); - } catch (e) { - let abciError = e; - - // Wrap all non ABCI errors to an internal ABCI error - if (!(e instanceof AbstractAbciError)) { - abciError = new InternalAbciError(e); - } - - // Log only internal ABCI errors - if (abciError instanceof InternalAbciError) { - const originalError = abciError.getError(); - - const preferredLogger = originalError.contextLogger || logger; - delete originalError.contextLogger; - - preferredLogger.error( - { err: originalError }, - originalError.message, - ); - - if (!isProductionEnvironment) { - abciError = new VerboseInternalAbciError(abciError); - } - } - - return abciError.getAbciResponse(); - } - } - - return methodErrorHandler; - } - - return wrapInErrorHandler; -} - -module.exports = wrapInErrorHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/checkTxHandlerFactory.js b/packages/js-drive/lib/abci/handlers/checkTxHandlerFactory.js deleted file mode 100644 index 05057f6a239..00000000000 --- a/packages/js-drive/lib/abci/handlers/checkTxHandlerFactory.js +++ /dev/null @@ -1,44 +0,0 @@ -const { - tendermint: { - abci: { - ResponseCheckTx, - }, - }, -} = require('@dashevo/abci/types'); - -/** - * @param {unserializeStateTransition} unserializeStateTransition - * @param {AsyncLocalStorage} unserializeStateTransition - * @param {createContextLogger} createContextLogger - * @param {Logger} logger - * - * @returns {checkTxHandler} - */ -function checkTxHandlerFactory( - unserializeStateTransition, - createContextLogger, - logger, -) { - /** - * CheckTx ABCI Handler - * - * @typedef checkTxHandler - * - * @param {abci.RequestCheckTx} request - * - * @returns {Promise} - */ - async function checkTxHandler({ tx: stateTransitionByteArray }) { - createContextLogger(logger, { - abciMethod: 'checkTx', - }); - - await unserializeStateTransition(stateTransitionByteArray); - - return new ResponseCheckTx(); - } - - return checkTxHandler; -} - -module.exports = checkTxHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/errors/NetworkProtocolVersionIsNotSetError.js b/packages/js-drive/lib/abci/handlers/errors/NetworkProtocolVersionIsNotSetError.js deleted file mode 100644 index 39a8ca62828..00000000000 --- a/packages/js-drive/lib/abci/handlers/errors/NetworkProtocolVersionIsNotSetError.js +++ /dev/null @@ -1,9 +0,0 @@ -const DriveError = require('../../../errors/DriveError'); - -class NetworkProtocolVersionIsNotSetError extends DriveError { - constructor() { - super('Network protocol version is not set'); - } -} - -module.exports = NetworkProtocolVersionIsNotSetError; diff --git a/packages/js-drive/lib/abci/handlers/errors/NotSupportedNetworkProtocolVersionError.js b/packages/js-drive/lib/abci/handlers/errors/NotSupportedNetworkProtocolVersionError.js deleted file mode 100644 index 5422637b6b2..00000000000 --- a/packages/js-drive/lib/abci/handlers/errors/NotSupportedNetworkProtocolVersionError.js +++ /dev/null @@ -1,30 +0,0 @@ -const DriveError = require('../../../errors/DriveError'); - -class NotSupportedNetworkProtocolVersionError extends DriveError { - /** - * @param {Long} networkProtocolVersion - * @param {Long} latestProtocolVersion - */ - constructor(networkProtocolVersion, latestProtocolVersion) { - super(`Block protocol version ${networkProtocolVersion} not supported. Expected to be less or equal to ${latestProtocolVersion}.`); - - this.networkProtocolVersion = networkProtocolVersion; - this.latestProtocolVersion = latestProtocolVersion; - } - - /** - * @returns {Long} - */ - getNetworkProtocolVersion() { - return this.networkProtocolVersion; - } - - /** - * @returns {Long} - */ - getLatestProtocolVersion() { - return this.latestProtocolVersion; - } -} - -module.exports = NotSupportedNetworkProtocolVersionError; diff --git a/packages/js-drive/lib/abci/handlers/extendVoteHandlerFactory.js b/packages/js-drive/lib/abci/handlers/extendVoteHandlerFactory.js deleted file mode 100644 index 9d0e1ef786c..00000000000 --- a/packages/js-drive/lib/abci/handlers/extendVoteHandlerFactory.js +++ /dev/null @@ -1,67 +0,0 @@ -const { - tendermint: { - abci: { - ResponseExtendVote, - }, - types: { - VoteExtensionType, - }, - }, -} = require('@dashevo/abci/types'); - -/** - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {createContextLogger} createContextLogger - * - * @return {extendVoteHandler} - */ -function extendVoteHandlerFactory(proposalBlockExecutionContext, createContextLogger) { - /** - * @typedef extendVoteHandler - * @return {Promise} - */ - async function extendVoteHandler() { - const contextLogger = createContextLogger(proposalBlockExecutionContext.getContextLogger(), { - abciMethod: 'extendVote', - }); - - contextLogger.debug('ExtendVote ABCI method requested'); - - const unsignedWithdrawalTransactionsMap = proposalBlockExecutionContext - .getWithdrawalTransactionsMap(); - - const voteExtensions = Object.keys(unsignedWithdrawalTransactionsMap) - .sort() - .map((txHashHex) => ({ - type: VoteExtensionType.THRESHOLD_RECOVER, - extension: Buffer.from(txHashHex, 'hex'), - })); - - const voteExtensionTypeName = { - [VoteExtensionType.DEFAULT]: 'default', - [VoteExtensionType.THRESHOLD_RECOVER]: 'threshold recovery', - }; - - voteExtensions.forEach(({ extension, type }) => { - const extensionString = extension.toString('hex'); - - const extensionTruncatedString = extensionString.substring( - 0, - Math.min(30, extensionString.length), - ); - - contextLogger.debug({ - type, - extension: extensionString, - }, `Vote extended to obtain ${voteExtensionTypeName} signature for ${extensionTruncatedString}... payload`); - }); - - return new ResponseExtendVote({ - voteExtensions, - }); - } - - return extendVoteHandler; -} - -module.exports = extendVoteHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/finalizeBlockHandlerFactory.js b/packages/js-drive/lib/abci/handlers/finalizeBlockHandlerFactory.js deleted file mode 100644 index 1d3dfdaf4fb..00000000000 --- a/packages/js-drive/lib/abci/handlers/finalizeBlockHandlerFactory.js +++ /dev/null @@ -1,145 +0,0 @@ -const { - tendermint: { - abci: { - ResponseFinalizeBlock, - RequestProcessProposal, - }, - }, -} = require('@dashevo/abci/types'); - -const lodashCloneDeep = require('lodash/cloneDeep'); - -/** - * - * @return {finalizeBlockHandler} - * @param {GroveDBStore} groveDBStore - * @param {BlockExecutionContextRepository} blockExecutionContextRepository - * @param {BaseLogger} logger - * @param {ExecutionTimer} executionTimer - * @param {BlockExecutionContext} latestBlockExecutionContext - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {processProposal} processProposal - * @param {broadcastWithdrawalTransactions} broadcastWithdrawalTransactions - * @param {createContextLogger} createContextLogger - * - */ -function finalizeBlockHandlerFactory( - groveDBStore, - blockExecutionContextRepository, - logger, - executionTimer, - latestBlockExecutionContext, - proposalBlockExecutionContext, - processProposal, - broadcastWithdrawalTransactions, - createContextLogger, -) { - /** - * @typedef finalizeBlockHandler - * - * @param {abci.RequestFinalizeBlock} request - * @return {Promise} - */ - async function finalizeBlockHandler(request) { - const { - commit: commitInfo, - height, - round, - } = request; - - const contextLogger = createContextLogger(logger, { - height: height.toString(), - round, - abciMethod: 'finalizeBlock', - }); - - const requestToLog = lodashCloneDeep(request); - delete requestToLog.block.data; - - contextLogger.debug('FinalizeBlock ABCI method requested'); - contextLogger.trace({ abciRequest: requestToLog }); - - const lastProcessedRound = proposalBlockExecutionContext.getRound(); - - if (lastProcessedRound !== round) { - contextLogger.warn({ - lastProcessedRound, - round, - }, `Finalizing previously executed round ${round} instead of the last known ${lastProcessedRound}`); - - const { - block: { - header: { - time, - version, - proposerProTxHash, - proposedAppVersion, - coreChainLockedHeight, - }, - data: { - txs, - }, - }, - } = request; - - const processProposalRequest = new RequestProcessProposal({ - height, - txs, - coreChainLockedHeight, - version, - proposedLastCommit: commitInfo, - time, - proposerProTxHash, - proposedAppVersion, - round, - }); - - await processProposal(processProposalRequest, contextLogger); - } - - // Send withdrawal transactions to Core - const unsignedWithdrawalTransactionsMap = proposalBlockExecutionContext - .getWithdrawalTransactionsMap(); - - const { thresholdVoteExtensions } = commitInfo; - - await broadcastWithdrawalTransactions( - proposalBlockExecutionContext, - thresholdVoteExtensions, - unsignedWithdrawalTransactionsMap, - ); - - proposalBlockExecutionContext.setLastCommitInfo(commitInfo); - - // Store proposal block execution context - await blockExecutionContextRepository.store( - proposalBlockExecutionContext, - { - useTransaction: true, - }, - ); - - // Commit the current block db transactions into storage - await groveDBStore.commitTransaction(); - - // Update last block execution context with proposal data - latestBlockExecutionContext.populate(proposalBlockExecutionContext); - - proposalBlockExecutionContext.reset(); - - const blockExecutionTimings = executionTimer.stopTimer('blockExecution'); - - contextLogger.info( - { - timings: blockExecutionTimings, - }, - `Block #${height} finalized in ${round + 1} round(s) and ${blockExecutionTimings} seconds`, - ); - - return new ResponseFinalizeBlock(); - } - - return finalizeBlockHandler; -} - -module.exports = finalizeBlockHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/infoHandlerFactory.js b/packages/js-drive/lib/abci/handlers/infoHandlerFactory.js deleted file mode 100644 index 0d056c005d0..00000000000 --- a/packages/js-drive/lib/abci/handlers/infoHandlerFactory.js +++ /dev/null @@ -1,94 +0,0 @@ -const { - tendermint: { - abci: { - ResponseInfo, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const { version: driveVersion } = require('../../../package.json'); - -/** - * @param {BlockExecutionContext} latestBlockExecutionContext - * @param {BlockExecutionContextRepository} blockExecutionContextRepository - * @param {Long} latestProtocolVersion - * @param {updateSimplifiedMasternodeList} updateSimplifiedMasternodeList - * @param {BaseLogger} logger - * @param {GroveDBStore} groveDBStore - * @param {createContextLogger} createContextLogger - * @return {infoHandler} - */ -function infoHandlerFactory( - latestBlockExecutionContext, - blockExecutionContextRepository, - latestProtocolVersion, - updateSimplifiedMasternodeList, - logger, - groveDBStore, - createContextLogger, -) { - /** - * Info ABCI handler - * - * @typedef infoHandler - * - * @param {abci.RequestInfo} request - * @return {Promise} - */ - async function infoHandler(request) { - let contextLogger = createContextLogger(logger, { - abciMethod: 'info', - }); - - contextLogger.debug('Info ABCI method requested'); - contextLogger.trace({ abciRequest: request }); - - // Initialize current heights - - let lastHeight = Long.fromNumber(0); - let lastCoreChainLockedHeight = 0; - - // Initialize latest Block Execution Context - const persistedBlockExecutionContext = await blockExecutionContextRepository.fetch(); - if (!persistedBlockExecutionContext.isEmpty()) { - latestBlockExecutionContext.populate(persistedBlockExecutionContext); - - lastHeight = latestBlockExecutionContext.getHeight(); - lastCoreChainLockedHeight = latestBlockExecutionContext.getCoreChainLockedHeight(); - - contextLogger = createContextLogger(contextLogger, { - height: lastHeight.toString(), - }); - - // Update SML store to latest saved core chain lock to make sure - // that verify chain lock handler has updated SML Store to verify signatures - await updateSimplifiedMasternodeList(lastCoreChainLockedHeight, { - logger: contextLogger, - }); - } - - const appHash = await groveDBStore.getRootHash(); - - contextLogger.info( - { - lastHeight: lastHeight.toString(), - appHash: appHash.toString('hex').toUpperCase(), - latestProtocolVersion: latestProtocolVersion.toString(), - }, - `Start processing from block #${lastHeight} with appHash ${appHash.toString('hex').toUpperCase()}`, - ); - - return new ResponseInfo({ - version: driveVersion, - appVersion: latestProtocolVersion, - lastBlockHeight: lastHeight, - lastBlockAppHash: appHash, - }); - } - - return infoHandler; -} - -module.exports = infoHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/initChainHandlerFactory.js b/packages/js-drive/lib/abci/handlers/initChainHandlerFactory.js deleted file mode 100644 index 51f1b73aa0c..00000000000 --- a/packages/js-drive/lib/abci/handlers/initChainHandlerFactory.js +++ /dev/null @@ -1,150 +0,0 @@ -const { - tendermint: { - abci: { - ResponseInitChain, - }, - }, -} = require('@dashevo/abci/types'); - -const BlockInfo = require('../../blockExecution/BlockInfo'); -const protoTimestampToMillis = require('../../util/protoTimestampToMillis'); - -/** - * Init Chain ABCI handler - * - * @param {updateSimplifiedMasternodeList} updateSimplifiedMasternodeList - * @param {number} initialCoreChainLockedHeight - * @param {ValidatorSet} validatorSet - * @param {createValidatorSetUpdate} createValidatorSetUpdate - * @param {synchronizeMasternodeIdentities} synchronizeMasternodeIdentities - * @param {BaseLogger} logger - * @param {GroveDBStore} groveDBStore - * @param {RSAbci} rsAbci - * @param {createCoreChainLockUpdate} createCoreChainLockUpdate - * @param {createContextLogger} createContextLogger - * @param {SystemIdentityPublicKeys} systemIdentityPublicKeys - * @return {initChainHandler} - */ -function initChainHandlerFactory( - updateSimplifiedMasternodeList, - initialCoreChainLockedHeight, - validatorSet, - createValidatorSetUpdate, - synchronizeMasternodeIdentities, - logger, - groveDBStore, - rsAbci, - createCoreChainLockUpdate, - createContextLogger, - systemIdentityPublicKeys, -) { - /** - * @typedef initChainHandler - * - * @param {abci.RequestInitChain} request - * @return {Promise} - */ - async function initChainHandler(request) { - const { time } = request; - const timeMs = protoTimestampToMillis(time); - - const contextLogger = createContextLogger(logger, { - height: request.initialHeight.toString(), - abciMethod: 'initChain', - }); - - contextLogger.debug('InitChain ABCI method requested'); - contextLogger.trace({ abciRequest: request }); - - await updateSimplifiedMasternodeList( - initialCoreChainLockedHeight, { - logger: contextLogger, - }, - ); - - // Create initial state - - await groveDBStore.startTransaction(); - - // Call RS ABCI - - const initChainRequest = { - genesisTimeMs: timeMs, - systemIdentityPublicKeys, - }; - - logger.debug('Request RS Drive\'s InitChain method'); - logger.trace(initChainRequest); - - await rsAbci.initChain(initChainRequest, true); - - const blockInfo = new BlockInfo( - 0, - 0, - timeMs, - ); - - const synchronizeMasternodeIdentitiesResult = await synchronizeMasternodeIdentities( - initialCoreChainLockedHeight, - blockInfo, - ); - - const { - createdEntities, updatedEntities, removedEntities, fromHeight, toHeight, - } = synchronizeMasternodeIdentitiesResult; - - contextLogger.info( - `Masternode identities are synced for heights from ${fromHeight} to ${toHeight}: ${createdEntities.length} created, ${updatedEntities.length} updated, ${removedEntities.length} removed`, - ); - - contextLogger.trace( - { - createdEntities: createdEntities.map((item) => item.toJSON()), - updatedEntities: updatedEntities.map((item) => item.toJSON()), - removedEntities: removedEntities.map((item) => item.toJSON()), - }, - 'Synchronized masternode identities', - ); - - // Set initial validator set - - await validatorSet.initialize(initialCoreChainLockedHeight); - - const { quorumHash } = validatorSet.getQuorum(); - - const validatorSetUpdate = createValidatorSetUpdate(validatorSet); - - const coreChainLockUpdate = await createCoreChainLockUpdate( - initialCoreChainLockedHeight, - 0, - contextLogger, - ); - - const appHash = await groveDBStore.getRootHash({ useTransaction: true }); - - await groveDBStore.commitTransaction(); - - contextLogger.trace(validatorSetUpdate, `Validator set initialized with ${quorumHash} quorum`); - - contextLogger.info( - { - chainId: request.chainId, - appHash: appHash.toString('hex').toUpperCase(), - initialHeight: request.initialHeight.toString(), - initialCoreHeight: initialCoreChainLockedHeight, - }, - `Init ${request.chainId} chain on block #${request.initialHeight.toString()} with app hash ${appHash.toString('hex').toUpperCase()}`, - ); - - return new ResponseInitChain({ - appHash, - validatorSetUpdate, - initialCoreHeight: initialCoreChainLockedHeight, - nextCoreChainLockUpdate: coreChainLockUpdate, - }); - } - - return initChainHandler; -} - -module.exports = initChainHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js b/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js deleted file mode 100644 index 9f36462f661..00000000000 --- a/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js +++ /dev/null @@ -1,189 +0,0 @@ -const { - tendermint: { - abci: { - ResponsePrepareProposal, - }, - }, -} = require('@dashevo/abci/types'); - -const lodashCloneDeep = require('lodash/cloneDeep'); -const addStateTransitionFeesToBlockFees = require('./proposal/fees/addStateTransitionFeesToBlockFees'); - -const txAction = { - UNKNOWN: 0, // Unknown action - UNMODIFIED: 1, // The Application did not modify this transaction. - ADDED: 2, // The Application added this transaction. - REMOVED: 3, // The Application wants this transaction removed from the proposal and the mempool. -}; - -/** - * @param {deliverTx} wrappedDeliverTx - * @param {BaseLogger} logger - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {beginBlock} beginBlock - * @param {endBlock} endBlock - * @param {createCoreChainLockUpdate} createCoreChainLockUpdate - * @param {ExecutionTimer} executionTimer - * @param {createContextLogger} createContextLogger - * @return {prepareProposalHandler} - */ -function prepareProposalHandlerFactory( - wrappedDeliverTx, - logger, - proposalBlockExecutionContext, - beginBlock, - endBlock, - createCoreChainLockUpdate, - executionTimer, - createContextLogger, -) { - /** - * @typedef prepareProposalHandler - * @param {abci.RequestPrepareProposal} request - * @return {Promise} - */ - async function prepareProposalHandler(request) { - const { - height, - maxTxBytes, - txs, - coreChainLockedHeight, - version, - localLastCommit: lastCommitInfo, - time, - proposerProTxHash, - proposedAppVersion, - round, - quorumHash, - } = request; - - const contextLogger = createContextLogger(logger, { - height: height.toString(), - round, - abciMethod: 'prepareProposal', - }); - - const requestToLog = lodashCloneDeep(request); - delete requestToLog.txs; - - contextLogger.debug('PrepareProposal ABCI method requested'); - contextLogger.trace({ abciRequest: requestToLog }); - - contextLogger.info(`Preparing a block proposal for height #${height} round #${round}`); - - await beginBlock( - { - lastCommitInfo, - height, - coreChainLockedHeight, - version, - time, - proposerProTxHash: Buffer.from(proposerProTxHash), - proposedAppVersion, - round, - quorumHash, - }, - contextLogger, - ); - - let totalSizeBytes = 0; - - const txRecords = []; - const txResults = []; - const blockFees = { - storageFee: 0, - processingFee: 0, - refundsPerEpoch: {}, - }; - - let validTxCount = 0; - let invalidTxCount = 0; - - for (const tx of txs) { - totalSizeBytes += tx.length; - - if (totalSizeBytes > maxTxBytes) { - break; - } - - txRecords.push({ - tx, - action: txAction.UNMODIFIED, - }); - - const { - code, - info, - fees, - } = await wrappedDeliverTx(tx, round, contextLogger); - - if (code === 0) { - validTxCount += 1; - // TODO We probably should calculate fees for invalid transitions as well - addStateTransitionFeesToBlockFees(blockFees, fees); - } else { - invalidTxCount += 1; - } - - const txResult = { code }; - - if (info) { - txResult.info = info; - } - - txResults.push(txResult); - } - - const coreChainLockUpdate = await createCoreChainLockUpdate( - coreChainLockedHeight, - round, - contextLogger, - ); - - const { - consensusParamUpdates, - validatorSetUpdate, - appHash, - } = await endBlock({ - height, - round, - fees: blockFees, - coreChainLockedHeight, - }, contextLogger); - - const roundExecutionTime = executionTimer.getTimer('roundExecution', true); - - const mempoolTxCount = txs.length - validTxCount - invalidTxCount; - - contextLogger.info( - { - roundExecutionTime, - validTxCount, - invalidTxCount, - mempoolTxCount, - }, - `Prepared block proposal for height #${height} with appHash ${appHash.toString('hex').toUpperCase()}` - + ` in ${roundExecutionTime} seconds (valid txs = ${validTxCount}, invalid txs = ${invalidTxCount}, mempool txs = ${mempoolTxCount})`, - ); - - proposalBlockExecutionContext.setPrepareProposalResult({ - appHash, - txResults, - consensusParamUpdates, - validatorSetUpdate, - }); - - return new ResponsePrepareProposal({ - appHash, - txResults, - consensusParamUpdates, - validatorSetUpdate, - coreChainLockUpdate, - txRecords, - }); - } - - return prepareProposalHandler; -} - -module.exports = prepareProposalHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/processProposalHandlerFactory.js b/packages/js-drive/lib/abci/handlers/processProposalHandlerFactory.js deleted file mode 100644 index ee942a773be..00000000000 --- a/packages/js-drive/lib/abci/handlers/processProposalHandlerFactory.js +++ /dev/null @@ -1,99 +0,0 @@ -const { - tendermint: { - abci: { - ResponseProcessProposal, - }, - }, -} = require('@dashevo/abci/types'); - -const lodashCloneDeep = require('lodash/cloneDeep'); -const statuses = require('./proposal/statuses'); - -/** - * @param {BaseLogger} logger - * @param {verifyChainLock} verifyChainLock - * @param {processProposal} processProposal - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {createContextLogger} createContextLogger - * @return {processProposalHandler} - */ -function processProposalHandlerFactory( - logger, - verifyChainLock, - processProposal, - proposalBlockExecutionContext, - createContextLogger, -) { - /** - * @typedef processProposalHandler - * @param {abci.RequestProcessProposal} request - * @return {Promise} - */ - async function processProposalHandler(request) { - const { - height, - coreChainLockUpdate, - round, - } = request; - - const contextLogger = createContextLogger(logger, { - height: height.toString(), - round, - abciMethod: 'processProposal', - }); - - const requestToLog = lodashCloneDeep(request); - delete requestToLog.txs; - - contextLogger.debug('ProcessProposal ABCI method requested'); - contextLogger.trace({ abciRequest: requestToLog }); - - // Skip process proposal if it was already prepared for this height and round - const prepareProposalResult = proposalBlockExecutionContext.getPrepareProposalResult(); - - if (prepareProposalResult - && proposalBlockExecutionContext.getHeight().toNumber() === height.toNumber() - && proposalBlockExecutionContext.getRound() === round) { - contextLogger.debug('Skip processing proposal and return prepared result'); - - const { - appHash, - txResults, - consensusParamUpdates, - validatorSetUpdate, - } = prepareProposalResult; - - return new ResponseProcessProposal({ - status: statuses.ACCEPT, - appHash, - txResults, - consensusParamUpdates, - validatorSetUpdate, - }); - } - - if (coreChainLockUpdate) { - const chainLockIsValid = await verifyChainLock(coreChainLockUpdate); - - if (!chainLockIsValid) { - contextLogger.warn({ - coreChainLockUpdate, - }, `Block proposal #${height} round #${round} rejected due to invalid core chain locked height update`); - - return new ResponseProcessProposal({ - status: statuses.REJECT, - }); - } - - logger.debug({ - coreChainLockUpdate, - }, `ChainLock is valid for height ${coreChainLockUpdate.coreBlockHeight}`); - } - - return processProposal(request, contextLogger); - } - - return processProposalHandler; -} - -module.exports = processProposalHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/beginBlockFactory.js b/packages/js-drive/lib/abci/handlers/proposal/beginBlockFactory.js deleted file mode 100644 index a159db141e4..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/beginBlockFactory.js +++ /dev/null @@ -1,224 +0,0 @@ -const { hash } = require('@dashevo/dpp/lib/util/hash'); - -const NotSupportedNetworkProtocolVersionError = require('../errors/NotSupportedNetworkProtocolVersionError'); -const NetworkProtocolVersionIsNotSetError = require('../errors/NetworkProtocolVersionIsNotSetError'); - -const BlockInfo = require('../../../blockExecution/BlockInfo'); -const protoTimestampToMillis = require('../../../util/protoTimestampToMillis'); - -/** - * Begin Block - * - * @param {GroveDBStore} groveDBStore - * @param {BlockExecutionContext} latestBlockExecutionContext - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {Long} latestProtocolVersion - * @param {DashPlatformProtocol} dpp - * @param {DashPlatformProtocol} transactionalDpp - * @param {updateSimplifiedMasternodeList} updateSimplifiedMasternodeList - * @param {waitForChainLockedHeight} waitForChainLockedHeight - * @param {synchronizeMasternodeIdentities} synchronizeMasternodeIdentities - * @param {RSAbci} rsAbci - * @param {ExecutionTimer} executionTimer - * @param {LastSyncedCoreHeightRepository} lastSyncedCoreHeightRepository - * @param {SimplifiedMasternodeList} simplifiedMasternodeList - * - * @return {beginBlock} - */ -function beginBlockFactory( - groveDBStore, - latestBlockExecutionContext, - proposalBlockExecutionContext, - latestProtocolVersion, - dpp, - transactionalDpp, - updateSimplifiedMasternodeList, - waitForChainLockedHeight, - synchronizeMasternodeIdentities, - rsAbci, - executionTimer, - lastSyncedCoreHeightRepository, - simplifiedMasternodeList, -) { - /** - * @typedef beginBlock - * @param {Object} request - * @param {ILastCommitInfo} request.lastCommitInfo - * @param {Long} request.height - * @param {number} request.coreChainLockedHeight - * @param {IConsensus} request.version - * @param {Long} request.proposedAppVersion - * @param {ITimestamp} request.time - * @param {Buffer} request.proposerProTxHash - * @param {Buffer} request.quorumHash - * @param {BaseLogger} contextLogger - * - * @return {Promise} - */ - async function beginBlock(request, contextLogger) { - const { - lastCommitInfo, - height, - coreChainLockedHeight, - version, - time, - proposerProTxHash, - proposedAppVersion, - round, - quorumHash, - } = request; - - if (proposalBlockExecutionContext.isEmpty()) { - executionTimer.clearTimer('blockExecution'); - executionTimer.startTimer('blockExecution'); - } - - executionTimer.clearTimer('roundExecution'); - executionTimer.startTimer('roundExecution'); - - // Validate protocol version - - if (version.app.eq(0)) { - throw new NetworkProtocolVersionIsNotSetError(); - } - - if (version.app.gt(latestProtocolVersion)) { - throw new NotSupportedNetworkProtocolVersionError( - version.app, - latestProtocolVersion, - ); - } - - // Make sure Core has the same height as the network - - await waitForChainLockedHeight(coreChainLockedHeight); - - // Reset block execution context - proposalBlockExecutionContext.reset(); - - proposalBlockExecutionContext.setContextLogger(contextLogger); - proposalBlockExecutionContext.setHeight(height); - proposalBlockExecutionContext.setVersion(version); - proposalBlockExecutionContext.setProposedAppVersion(proposedAppVersion); - proposalBlockExecutionContext.setRound(round); - proposalBlockExecutionContext.setTimeMs(protoTimestampToMillis(time)); - proposalBlockExecutionContext.setCoreChainLockedHeight(coreChainLockedHeight); - proposalBlockExecutionContext.setLastCommitInfo(lastCommitInfo); - - // Update SML - const isSimplifiedMasternodeListUpdated = await updateSimplifiedMasternodeList( - coreChainLockedHeight, - { - logger: contextLogger, - }, - ); - - // Set protocol version to DPP - dpp.setProtocolVersion(version.app.toNumber()); - transactionalDpp.setProtocolVersion(version.app.toNumber()); - - // Restart transaction if already started - if (await groveDBStore.isTransactionStarted()) { - await groveDBStore.abortTransaction(); - } - - await groveDBStore.startTransaction(); - - const lastSyncedHeightResult = await lastSyncedCoreHeightRepository.fetch({ - useTransaction: true, - }); - - const lastSyncedCoreHeight = lastSyncedHeightResult.getValue() || 0; - - // Call RS ABCI - - /** - * @type {BlockBeginRequest} - */ - const rsRequest = { - blockHeight: height.toNumber(), - blockTimeMs: proposalBlockExecutionContext.getTimeMs(), - proposerProTxHash, - validatorSetQuorumHash: quorumHash, - coreChainLockedHeight, - lastSyncedCoreHeight, - // TODO: Since we don't have HPMNs now and every masternode can be a validator, - // we pass the whole list - totalHpmns: simplifiedMasternodeList.getStore() - .getCurrentSML() - .getValidMasternodesList() - .length, - proposedAppVersion: proposedAppVersion.toNumber(), - }; - - if (!latestBlockExecutionContext.isEmpty()) { - rsRequest.previousBlockTimeMs = latestBlockExecutionContext.getTimeMs(); - } - - contextLogger.debug(rsRequest, 'Request RS Drive\'s BlockBegin method'); - - const rsResponse = await rsAbci.blockBegin(rsRequest, true); - - const withdrawalTransactionsMap = (rsResponse.unsignedWithdrawalTransactions || []).reduce( - (map, transactionBytes) => ({ - ...map, - [hash(transactionBytes).toString('hex')]: transactionBytes, - }), - {}, - ); - - proposalBlockExecutionContext.setWithdrawalTransactionsMap(withdrawalTransactionsMap); - proposalBlockExecutionContext.setEpochInfo(rsResponse.epochInfo); - - const { currentEpochIndex, isEpochChange } = rsResponse; - - if (isEpochChange) { - const debugData = { - currentEpochIndex, - blockTime: proposalBlockExecutionContext.getTimeMs(), - }; - - if (rsRequest.previousBlockTimeMs) { - debugData.previousBlockTimeMs = rsRequest.previousBlockTimeMs; - } - - const blockTimeFormatted = new Date(proposalBlockExecutionContext.getTimeMs()).toUTCString(); - - contextLogger.info(debugData, `Epoch #${currentEpochIndex} started on block #${height} at ${blockTimeFormatted}`); - } - - // Synchronize masternode identities - - if (isSimplifiedMasternodeListUpdated) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(proposalBlockExecutionContext); - - const synchronizeMasternodeIdentitiesResult = await synchronizeMasternodeIdentities( - coreChainLockedHeight, - blockInfo, - ); - - const { - createdEntities, updatedEntities, removedEntities, fromHeight, toHeight, - } = synchronizeMasternodeIdentitiesResult; - - contextLogger.info( - `Masternode identities are synced for heights from ${fromHeight} to ${toHeight}: ${createdEntities.length} created, ${updatedEntities.length} updated, ${removedEntities.length} removed`, - ); - - if (createdEntities.length > 0 || updatedEntities.length > 0 || removedEntities.length > 0) { - contextLogger.trace( - { - createdEntities: createdEntities.map((item) => item.toJSON()), - updatedEntities: updatedEntities.map((item) => item.toJSON()), - removedEntities: removedEntities.map((item) => item.toJSON()), - }, - 'Synchronized masternode identities', - ); - } - } - } - - return beginBlock; -} - -module.exports = beginBlockFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.js b/packages/js-drive/lib/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.js deleted file mode 100644 index 3bc4818b684..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.js +++ /dev/null @@ -1,64 +0,0 @@ -const BlockInfo = require('../../../blockExecution/BlockInfo'); - -/** - * @param {CoreRpcClient} coreRpcClient - * @param {updateWithdrawalTransactionIdAndStatus} updateWithdrawalTransactionIdAndStatus - * - * @return {broadcastWithdrawalTransactions} - */ -function broadcastWithdrawalTransactionsFactory( - coreRpcClient, - updateWithdrawalTransactionIdAndStatus, -) { - /** - * @typedef broadcastWithdrawalTransactions - * - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {{{ extension: Buffer, signature: Buffer }}[]} thresholdVoteExtensions - * @param {Object} unsignedWithdrawalTransactionsMap - * - * @return {Promise} - */ - async function broadcastWithdrawalTransactions( - proposalBlockExecutionContext, - thresholdVoteExtensions, - unsignedWithdrawalTransactionsMap, - ) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(proposalBlockExecutionContext); - - const transactionIdMap = {}; - - for (const { extension, signature } of (thresholdVoteExtensions || [])) { - const withdrawalTransactionHash = extension.toString('hex'); - - const unsignedWithdrawalTransactionBytes = unsignedWithdrawalTransactionsMap[ - withdrawalTransactionHash - ]; - - if (unsignedWithdrawalTransactionBytes) { - const transactionBytes = Buffer.concat([ - unsignedWithdrawalTransactionBytes, - signature, - ]); - - transactionIdMap[unsignedWithdrawalTransactionBytes.toString('hex')] = transactionBytes; - - // TODO: think about Core error handling - await coreRpcClient.sendRawTransaction(transactionBytes.toString('hex')); - } - } - - await updateWithdrawalTransactionIdAndStatus( - blockInfo, - proposalBlockExecutionContext.getCoreChainLockedHeight(), - transactionIdMap, - { - useTransaction: true, - }, - ); - } - - return broadcastWithdrawalTransactions; -} - -module.exports = broadcastWithdrawalTransactionsFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/createConsensusParamUpdateFactory.js b/packages/js-drive/lib/abci/handlers/proposal/createConsensusParamUpdateFactory.js deleted file mode 100644 index 4ac31ad0377..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/createConsensusParamUpdateFactory.js +++ /dev/null @@ -1,69 +0,0 @@ -const { - tendermint: { - types: { - ConsensusParams, - }, - }, -} = require('@dashevo/abci/types'); - -const featureFlagTypes = require('@dashevo/feature-flags-contract/lib/featureFlagTypes'); - -/** - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {getFeatureFlagForHeight} getFeatureFlagForHeight - * @return {createConsensusParamUpdate} - */ -function createConsensusParamUpdateFactory( - proposalBlockExecutionContext, - getFeatureFlagForHeight, -) { - /** - * @typedef createConsensusParamUpdate - * @param {number} height - * @param {number} round - * @param {BaseLogger} contextLogger - * @return {Promise} - */ - async function createConsensusParamUpdate(height, round, contextLogger) { - const contextVersion = proposalBlockExecutionContext.getVersion(); - - // Update consensus params feature flag - - const updateConsensusParamsFeatureFlag = await getFeatureFlagForHeight( - featureFlagTypes.UPDATE_CONSENSUS_PARAMS, - height, - true, - ); - - let consensusParamUpdates; - if (updateConsensusParamsFeatureFlag) { - // Use previous version if we aren't going to update it - let version = { - appVersion: contextVersion.app, - }; - - if (updateConsensusParamsFeatureFlag.get('version')) { - version = updateConsensusParamsFeatureFlag.get('version'); - } - - consensusParamUpdates = new ConsensusParams({ - block: updateConsensusParamsFeatureFlag.get('block'), - evidence: updateConsensusParamsFeatureFlag.get('evidence'), - version, - }); - - contextLogger.info( - { - consensusParamUpdates, - }, - 'Update consensus params', - ); - } - - return consensusParamUpdates; - } - - return createConsensusParamUpdate; -} - -module.exports = createConsensusParamUpdateFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/createCoreChainLockUpdateFactory.js b/packages/js-drive/lib/abci/handlers/proposal/createCoreChainLockUpdateFactory.js deleted file mode 100644 index 8a712216696..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/createCoreChainLockUpdateFactory.js +++ /dev/null @@ -1,49 +0,0 @@ -const { - tendermint: { - types: { - CoreChainLock, - }, - }, -} = require('@dashevo/abci/types'); -/** - * - * @param {LatestCoreChainLock} latestCoreChainLock - * @return {createCoreChainLockUpdate} - */ -function createCoreChainLockUpdateFactory( - latestCoreChainLock, -) { - /** - * @typedef createCoreChainLockUpdate - * @param {number} contextCoreChainLockedHeight - * @param {number} round - * @param {BaseLogger} contextLogger - * @return {Promise} - */ - async function createCoreChainLockUpdate(contextCoreChainLockedHeight, round, contextLogger) { - // Update Core Chain Locks - const coreChainLock = latestCoreChainLock.getChainLock(); - - let coreChainLockUpdate; - if (coreChainLock && coreChainLock.height > contextCoreChainLockedHeight) { - coreChainLockUpdate = new CoreChainLock({ - coreBlockHeight: coreChainLock.height, - coreBlockHash: coreChainLock.blockHash, - signature: coreChainLock.signature, - }); - - contextLogger.debug( - { - nextCoreChainLockHeight: coreChainLock.height, - }, - `Provide next chain lock for Core height ${coreChainLock.height}`, - ); - } - - return coreChainLockUpdate; - } - - return createCoreChainLockUpdate; -} - -module.exports = createCoreChainLockUpdateFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/deliverTxFactory.js b/packages/js-drive/lib/abci/handlers/proposal/deliverTxFactory.js deleted file mode 100644 index 760c9e5e99b..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/deliverTxFactory.js +++ /dev/null @@ -1,281 +0,0 @@ -const crypto = require('crypto'); -const { FeeResult } = require('@dashevo/rs-drive'); - -const stateTransitionTypes = require('@dashevo/dpp/lib/stateTransition/stateTransitionTypes'); -const AbstractDocumentTransition = require( - '@dashevo/dpp/lib/document/stateTransition/DocumentsBatchTransition/documentTransition/AbstractDocumentTransition', -); - -const DPPValidationAbciError = require('../../errors/DPPValidationAbciError'); - -const DOCUMENT_ACTION_DESCRIPTIONS = { - [AbstractDocumentTransition.ACTIONS.CREATE]: 'Create', - [AbstractDocumentTransition.ACTIONS.REPLACE]: 'Replace', - [AbstractDocumentTransition.ACTIONS.DELETE]: 'Delete', -}; - -const DATA_CONTRACT_ACTION_DESCRIPTIONS = { - [stateTransitionTypes.DATA_CONTRACT_CREATE]: 'Create', - [stateTransitionTypes.DATA_CONTRACT_UPDATE]: 'Update', -}; - -const TIMERS = require('../timers'); - -/** - * @param {unserializeStateTransition} transactionalUnserializeStateTransition - * @param {DashPlatformProtocol} transactionalDpp - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {ExecutionTimer} executionTimer - * @param {IdentityBalanceStoreRepository} identityBalanceRepository - * @param {calculateStateTransitionFee} calculateStateTransitionFee - * @param {calculateStateTransitionFeeFromOperations} calculateStateTransitionFeeFromOperations - * @param {createContextLogger} createContextLogger - * - * @return {deliverTx} - */ -function deliverTxFactory( - transactionalUnserializeStateTransition, - transactionalDpp, - proposalBlockExecutionContext, - executionTimer, - identityBalanceRepository, - calculateStateTransitionFee, - calculateStateTransitionFeeFromOperations, - createContextLogger, -) { - /** - * @typedef deliverTx - * - * @param {Buffer} stateTransitionByteArray - * @param {number} round - * @param {BaseLogger} contextLogger - * @return {Promise<{ - * code: number, - * fees: BlockFees}>} - */ - async function deliverTx(stateTransitionByteArray, round, contextLogger) { - const blockHeight = proposalBlockExecutionContext.getHeight(); - - // Start execution timer - - executionTimer.clearTimer(TIMERS.DELIVER_TX.OVERALL); - executionTimer.clearTimer(TIMERS.DELIVER_TX.VALIDATE_BASIC); - executionTimer.clearTimer(TIMERS.DELIVER_TX.VALIDATE_FEE); - executionTimer.clearTimer(TIMERS.DELIVER_TX.VALIDATE_SIGNATURE); - executionTimer.clearTimer(TIMERS.DELIVER_TX.VALIDATE_STATE); - executionTimer.clearTimer(TIMERS.DELIVER_TX.APPLY); - - executionTimer.startTimer(TIMERS.DELIVER_TX.OVERALL); - - const stHash = crypto - .createHash('sha256') - .update(stateTransitionByteArray) - .digest() - .toString('hex') - .toUpperCase(); - - const txContextLogger = createContextLogger(contextLogger, { - txId: stHash, - }); - - txContextLogger.info(`Deliver state transition ${stHash} from block #${blockHeight}`); - - const stateTransition = await transactionalUnserializeStateTransition( - stateTransitionByteArray, - { - logger: txContextLogger, - executionTimer, - }, - ); - - // Logging - /* istanbul ignore next */ - switch (stateTransition.getType()) { - case stateTransitionTypes.DATA_CONTRACT_UPDATE: - case stateTransitionTypes.DATA_CONTRACT_CREATE: { - const dataContract = stateTransition.getDataContract(); - - // Save data contracts in order to create databases for documents on block commit - proposalBlockExecutionContext.addDataContract(dataContract); - - const description = DATA_CONTRACT_ACTION_DESCRIPTIONS[stateTransition.getType()]; - - txContextLogger.info( - { - dataContractId: dataContract.getId().toString(), - }, - `${description} Data Contract with id: ${dataContract.getId()}`, - ); - - break; - } - case stateTransitionTypes.IDENTITY_CREATE: { - const identityId = stateTransition.getIdentityId(); - - txContextLogger.info( - { - identityId: identityId.toString(), - }, - `Create Identity with id: ${identityId}`, - ); - - break; - } - case stateTransitionTypes.IDENTITY_TOP_UP: { - const identityId = stateTransition.getIdentityId(); - - txContextLogger.info( - { - identityId: identityId.toString(), - }, - `Top up Identity with id: ${identityId}`, - ); - - break; - } - case stateTransitionTypes.IDENTITY_UPDATE: { - const identityId = stateTransition.getIdentityId(); - - txContextLogger.info( - { - identityId: identityId.toString(), - }, - `Update Identity with id: ${identityId}`, - ); - break; - } - case stateTransitionTypes.DOCUMENTS_BATCH: { - stateTransition.getTransitions().forEach((transition) => { - const description = DOCUMENT_ACTION_DESCRIPTIONS[transition.getAction()]; - - txContextLogger.info( - { - documentId: transition.getId().toString(), - }, - `${description} Document with id: ${transition.getId()}`, - ); - }); - - break; - } - default: - break; - } - - // Remove dry run operations from state transition execution context - - const stateTransitionExecutionContext = stateTransition.getExecutionContext(); - - const predictedStateTransitionOperations = stateTransitionExecutionContext.getOperations(); - const predictedStateTransitionFees = calculateStateTransitionFeeFromOperations( - predictedStateTransitionOperations, - stateTransition.getOwnerId(), - ); - - stateTransitionExecutionContext.clearDryOperations(); - - // Validate against state - - executionTimer.startTimer(TIMERS.DELIVER_TX.VALIDATE_STATE); - - const result = await transactionalDpp.stateTransition.validateState(stateTransition); - - if (!result.isValid()) { - const consensusError = result.getFirstError(); - const message = 'State transition is invalid against the state'; - - txContextLogger.info(message); - txContextLogger.debug({ - consensusError, - }); - - throw new DPPValidationAbciError(message, result.getFirstError()); - } - - executionTimer.stopTimer(TIMERS.DELIVER_TX.VALIDATE_STATE, true); - - executionTimer.startTimer(TIMERS.DELIVER_TX.APPLY); - - // Apply state transition to the state - - await transactionalDpp.stateTransition.apply(stateTransition); - - executionTimer.stopTimer(TIMERS.DELIVER_TX.APPLY, true); - - // Update identity balance - - const actualStateTransitionFees = calculateStateTransitionFee(stateTransition); - - const actualStateTransitionOperations = stateTransition.getExecutionContext().getOperations(); - - if (actualStateTransitionFees.desiredAmount > predictedStateTransitionFees.desiredAmount) { - txContextLogger.warn({ - predictedFee: predictedStateTransitionFees.desiredAmount, - actualFee: actualStateTransitionFees.desiredAmount, - }, `Actual fees are greater than predicted for ${actualStateTransitionFees.desiredAmount - predictedStateTransitionFees.desiredAmount} credits`); - } - - const feeResult = FeeResult.create( - actualStateTransitionFees.storageFee, - actualStateTransitionFees.processingFee, - actualStateTransitionFees.feeRefunds, - ); - - const applyFeesToBalanceResult = await identityBalanceRepository.applyFees( - stateTransition.getOwnerId(), - feeResult, - { useTransaction: true }, - ); - - const transactionFees = applyFeesToBalanceResult.getValue(); - - const deliverTxTiming = executionTimer.stopTimer(TIMERS.DELIVER_TX.OVERALL); - - txContextLogger.trace( - { - timings: { - overall: deliverTxTiming, - validateBasic: executionTimer.getTimer(TIMERS.DELIVER_TX.VALIDATE_BASIC, true), - validateFee: executionTimer.getTimer(TIMERS.DELIVER_TX.VALIDATE_FEE, true), - validateSignature: executionTimer.getTimer(TIMERS.DELIVER_TX.VALIDATE_SIGNATURE, true), - validateState: executionTimer.getTimer(TIMERS.DELIVER_TX.VALIDATE_STATE, true), - apply: executionTimer.getTimer(TIMERS.DELIVER_TX.APPLY, true), - }, - fees: { - predicted: { - storage: predictedStateTransitionFees.storageFee, - processing: predictedStateTransitionFees.processingFee, - refunds: predictedStateTransitionFees.totalRefunds, - requiredAmount: predictedStateTransitionFees.requiredAmount, - desiredAmount: predictedStateTransitionFees.desiredAmount, - operations: predictedStateTransitionOperations.map((operation) => operation.toJSON()), - }, - actual: { - storage: actualStateTransitionFees.storageFee, - processing: actualStateTransitionFees.processingFee, - refunds: actualStateTransitionFees.totalRefunds, - requiredAmount: actualStateTransitionFees.requiredAmount, - desiredAmount: actualStateTransitionFees.desiredAmount, - operations: actualStateTransitionOperations.map((operation) => operation.toJSON()), - }, - debt: actualStateTransitionFees.desiredAmount - transactionFees.processingFee, - }, - txType: stateTransition.getType(), - }, - `${stateTransition.constructor.name} execution took ${deliverTxTiming} seconds and cost ${actualStateTransitionFees.desiredAmount} credits`, - ); - - return { - code: 0, - fees: { - storageFee: transactionFees.storageFee, - processingFee: transactionFees.processingFee, - refundsPerEpoch: transactionFees.sumFeeRefundsPerEpoch(), - }, - }; - } - - return deliverTx; -} - -module.exports = deliverTxFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/endBlockFactory.js b/packages/js-drive/lib/abci/handlers/proposal/endBlockFactory.js deleted file mode 100644 index 307e50fd95b..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/endBlockFactory.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Begin block ABCI - * - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {ValidatorSet} validatorSet - * @param {createValidatorSetUpdate} createValidatorSetUpdate - * @param {getFeatureFlagForHeight} getFeatureFlagForHeight - * @param {RSAbci} rsAbci - * @param {createConsensusParamUpdate} createConsensusParamUpdate - * @param {rotateAndCreateValidatorSetUpdate} rotateAndCreateValidatorSetUpdate - * @param {GroveDBStore} groveDBStore - * @param {ExecutionTimer} executionTimer - * - * @return {endBlock} - */ -function endBlockFactory( - proposalBlockExecutionContext, - validatorSet, - createValidatorSetUpdate, - getFeatureFlagForHeight, - createConsensusParamUpdate, - rotateAndCreateValidatorSetUpdate, - rsAbci, - groveDBStore, - executionTimer, -) { - /** - * @typedef endBlock - * - * @param {Object} request - * @param {number} request.height - * @param {number} request.round - * @param { - * storageFee: number, - * processingFee: number, - * feeRefunds: Object, - * feeRefundsSum: number - * } request.fees - * @param {number} request.coreChainLockedHeight - * @param {BaseLogger} contextLogger - * @return {Promise<{ - * consensusParamUpdates: ConsensusParams, - * validatorSetUpdate: ValidatorSetUpdate, - * nextCoreChainLockUpdate: CoreChainLock, - * }>} - */ - async function endBlock( - request, - contextLogger, - ) { - const { - height, - round, - fees, - coreChainLockedHeight, - } = request; - - // Call RS ABCI - - const rsRequest = { - fees, - }; - - contextLogger.debug(rsRequest, 'Request RS Drive\'s BlockEnd method'); - - const rsResponse = await rsAbci.blockEnd(rsRequest, true); - - contextLogger.debug(rsResponse, 'RS Drive\'s BlockEnd method response'); - - const { currentEpochIndex } = proposalBlockExecutionContext.getEpochInfo(); - - const { - processingFee, - storageFee, - feeRefundsSum, - } = fees; - - if (processingFee > 0 || storageFee > 0) { - contextLogger.debug({ - currentEpochIndex, - processingFee, - storageFee, - feeRefundsSum, - }, `${processingFee} processing fees added to epoch #${currentEpochIndex}. ${storageFee} storage fees added to distribution pool. ${feeRefundsSum} credits refunded to identities`); - } - - if (rsResponse.proposersPaidCount) { - contextLogger.debug({ - currentEpochIndex, - proposersPaidCount: rsResponse.proposersPaidCount, - paidEpochIndex: rsResponse.paidEpochIndex, - }, `${rsResponse.proposersPaidCount} masternodes were paid for epoch #${rsResponse.paidEpochIndex}`); - } - - if (rsResponse.refundedEpochsCount) { - contextLogger.debug({ - currentEpochIndex, - refundedEpochsCount: rsResponse.refundedEpochsCount, - }, `${rsResponse.refundedEpochsCount} epochs were refunded`); - } - - const consensusParamUpdates = await createConsensusParamUpdate(height, round, contextLogger); - - const validatorSetUpdate = await rotateAndCreateValidatorSetUpdate( - height, - coreChainLockedHeight, - round, - contextLogger, - ); - - const appHash = await groveDBStore.getRootHash({ useTransaction: true }); - - executionTimer.stopTimer('roundExecution', true); - - return { - consensusParamUpdates, - validatorSetUpdate, - appHash, - }; - } - - return endBlock; -} - -module.exports = endBlockFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/fees/addStateTransitionFeesToBlockFees.js b/packages/js-drive/lib/abci/handlers/proposal/fees/addStateTransitionFeesToBlockFees.js deleted file mode 100644 index 2e81f9c2ad5..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/fees/addStateTransitionFeesToBlockFees.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @param {BlockFees} blockFees - * @param {BlockFees} stFees - */ -function addStateTransitionFeesToBlockFees(blockFees, stFees) { - /* eslint-disable no-param-reassign */ - blockFees.storageFee += stFees.storageFee; - blockFees.processingFee += stFees.processingFee; - - for (const [epochIndex, credits] of Object.entries(stFees.refundsPerEpoch)) { - if (!blockFees.refundsPerEpoch[epochIndex]) { - blockFees.refundsPerEpoch[epochIndex] = 0; - } - - blockFees.refundsPerEpoch[epochIndex] += credits; - } - - return blockFees; -} - -module.exports = addStateTransitionFeesToBlockFees; diff --git a/packages/js-drive/lib/abci/handlers/proposal/processProposalFactory.js b/packages/js-drive/lib/abci/handlers/proposal/processProposalFactory.js deleted file mode 100644 index 85907f69401..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/processProposalFactory.js +++ /dev/null @@ -1,139 +0,0 @@ -const { - tendermint: { - abci: { - ResponseProcessProposal, - }, - }, -} = require('@dashevo/abci/types'); - -const statuses = require('./statuses'); - -const addStateTransitionFeesToBlockFees = require('./fees/addStateTransitionFeesToBlockFees'); - -/** - * - * @param {deliverTx} wrappedDeliverTx - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {beginBlock} beginBlock - * @param {endBlock} endBlock - * @param {ExecutionTimer} executionTimer - * - * @return {processProposal} - */ -function processProposalFactory( - wrappedDeliverTx, - proposalBlockExecutionContext, - beginBlock, - endBlock, - executionTimer, -) { - /** - * @param {abci.RequestProcessProposal} request - * @param {BaseLogger} contextLogger - * - * @typedef processProposal - */ - async function processProposal(request, contextLogger) { - const { - height, - txs, - coreChainLockedHeight, - version, - proposedLastCommit: lastCommitInfo, - time, - proposerProTxHash, - proposedAppVersion, - round, - quorumHash, - } = request; - - contextLogger.info(`Processing a block proposal for height #${height} round #${round}`); - - await beginBlock( - { - lastCommitInfo, - height, - coreChainLockedHeight, - version, - time, - proposerProTxHash: Buffer.from(proposerProTxHash), - proposedAppVersion, - round, - quorumHash, - }, - contextLogger, - ); - - const txResults = []; - const blockFees = { - storageFee: 0, - processingFee: 0, - refundsPerEpoch: {}, - }; - - let validTxCount = 0; - let invalidTxCount = 0; - - for (const tx of txs) { - const { - code, - info, - fees, - } = await wrappedDeliverTx(tx, round, contextLogger); - - if (code === 0) { - validTxCount += 1; - // TODO We should calculate fees for invalid transitions as well - addStateTransitionFeesToBlockFees(blockFees, fees); - } else { - invalidTxCount += 1; - } - - const txResult = { code }; - - if (info) { - txResult.info = info; - } - - txResults.push(txResult); - } - - // Revert consensus logger after deliverTx - proposalBlockExecutionContext.setContextLogger(contextLogger); - - const { - consensusParamUpdates, - validatorSetUpdate, - appHash, - } = await endBlock({ - height, - round, - fees: blockFees, - coreChainLockedHeight, - }, contextLogger); - - const roundExecutionTime = executionTimer.getTimer('roundExecution', true); - - contextLogger.info( - { - roundExecutionTime, - validTxCount, - invalidTxCount, - }, - `Processed proposal #${height} with appHash ${appHash.toString('hex').toUpperCase()}` - + ` in ${roundExecutionTime} seconds (valid txs = ${validTxCount}, invalid txs = ${invalidTxCount})`, - ); - - return new ResponseProcessProposal({ - status: statuses.ACCEPT, - appHash, - txResults, - consensusParamUpdates, - validatorSetUpdate, - }); - } - - return processProposal; -} - -module.exports = processProposalFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.js b/packages/js-drive/lib/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.js deleted file mode 100644 index 9307c5f05c2..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @param {ValidatorSet} validatorSet - * @param {createValidatorSetUpdate} createValidatorSetUpdate - * @return {rotateAndCreateValidatorSetUpdate} - */ -function rotateAndCreateValidatorSetUpdateFactory( - proposalBlockExecutionContext, - validatorSet, - createValidatorSetUpdate, -) { - /** - * @typedef rotateAndCreateValidatorSetUpdate - * @param {number} height - * @param {number} coreChainLockedHeight - * @param {number} round - * @param {BaseLogger} contextLogger - * @return {Promise} - */ - async function rotateAndCreateValidatorSetUpdate( - height, - coreChainLockedHeight, - round, - contextLogger, - ) { - const lastCommitInfo = proposalBlockExecutionContext.getLastCommitInfo(); - - // Rotate validators - - let validatorSetUpdate; - const rotationEntropy = Buffer.from(lastCommitInfo.blockSignature); - if (await validatorSet.rotate(height, coreChainLockedHeight, rotationEntropy)) { - validatorSetUpdate = createValidatorSetUpdate(validatorSet); - - const { quorumHash } = validatorSet.getQuorum(); - - contextLogger.debug( - { - quorumHash, - }, - `Validator set switched to ${quorumHash} quorum`, - ); - } - - return validatorSetUpdate; - } - - return rotateAndCreateValidatorSetUpdate; -} - -module.exports = rotateAndCreateValidatorSetUpdateFactory; diff --git a/packages/js-drive/lib/abci/handlers/proposal/statuses.js b/packages/js-drive/lib/abci/handlers/proposal/statuses.js deleted file mode 100644 index adb8785b6c5..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/statuses.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - UNKNOWN: 0, // Unknown status. Returning this from the application is always an error. - ACCEPT: 1, // Status that signals that the application finds the proposal valid. - REJECT: 2, // Status that signals that the application finds the proposal invalid. -}; diff --git a/packages/js-drive/lib/abci/handlers/proposal/verifyChainLockFactory.js b/packages/js-drive/lib/abci/handlers/proposal/verifyChainLockFactory.js deleted file mode 100644 index 3fb6100b860..00000000000 --- a/packages/js-drive/lib/abci/handlers/proposal/verifyChainLockFactory.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - * - * @param {RpcClient} coreRpcClient - * @param {BlockExecutionContext} latestBlockExecutionContext - * @param {BaseLogger} logger - * @return {verifyChainLock} - */ -function verifyChainLockFactory( - coreRpcClient, - latestBlockExecutionContext, - logger, -) { - /** - * @typedef verifyChainLock - * @param {ChainLockUpdate} coreChainLock - * @return {Promise} - */ - async function verifyChainLock(coreChainLock) { - const serializedCoreChainLock = { - height: coreChainLock.coreBlockHeight, - signature: Buffer.from(coreChainLock.signature).toString('hex'), - blockHash: Buffer.from(coreChainLock.coreBlockHash).toString('hex'), - }; - - const lastCoreChainLockedHeight = latestBlockExecutionContext.getCoreChainLockedHeight(); - if (coreChainLock.coreBlockHeight <= lastCoreChainLockedHeight) { - logger.debug( - { - chainLock: serializedCoreChainLock, - lastCoreChainLockedHeight, - }, - 'Chainlock verification failed: coreBlockHeight must be bigger than the latest core chain locked height', - ); - - return false; - } - - let isVerified; - try { - ({ result: isVerified } = await coreRpcClient.verifyChainLock( - serializedCoreChainLock.blockHash, - serializedCoreChainLock.signature, - serializedCoreChainLock.height, - )); - } catch (e) { - // Invalid signature format - // Parse error - if ([-8, -32700].includes(e.code)) { - logger.debug( - { - err: e, - chainLock: serializedCoreChainLock, - }, - `Chainlock verification failed using verifyChainLock method: ${e.message} ${e.code}`, - ); - - return false; - } - - throw e; - } - - return isVerified; - } - - return verifyChainLock; -} - -module.exports = verifyChainLockFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/dataContractQueryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/query/dataContractQueryHandlerFactory.js deleted file mode 100644 index 2948bae4bcf..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/dataContractQueryHandlerFactory.js +++ /dev/null @@ -1,74 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetDataContractResponse, - }, -} = require('@dashevo/dapi-grpc'); - -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentifierError = require('@dashevo/dpp/lib/identifier/errors/IdentifierError'); - -const NotFoundAbciError = require('../../errors/NotFoundAbciError'); -const InvalidArgumentAbciError = require('../../errors/InvalidArgumentAbciError'); - -/** - * - * @param {DataContractStoreRepository} dataContractRepository - * @param {createQueryResponse} createQueryResponse - * @return {dataContractQueryHandler} - */ -function dataContractQueryHandlerFactory( - dataContractRepository, - createQueryResponse, -) { - /** - * @typedef dataContractQueryHandler - * @param {Object} params - * @param {Object} data - * @param {Buffer} data.id - * @param {RequestQuery} request - * @return {Promise} - */ - async function dataContractQueryHandler(params, { id }, request) { - let contractIdIdentifier; - try { - contractIdIdentifier = new Identifier(id); - } catch (e) { - if (e instanceof IdentifierError) { - throw new InvalidArgumentAbciError('id must be a valid identifier (32 bytes long)'); - } - - throw e; - } - - const response = createQueryResponse(GetDataContractResponse, request.prove); - - if (request.prove) { - const proof = await dataContractRepository.prove(contractIdIdentifier); - - response.getProof().setMerkleProof(proof.getValue()); - } else { - const dataContract = await dataContractRepository.fetch(contractIdIdentifier); - if (dataContract.isNull()) { - throw new NotFoundAbciError('Data Contract not found'); - } - - response.setDataContract(dataContract.getValue().toBuffer()); - } - - return new ResponseQuery({ - value: response.serializeBinary(), - }); - } - - return dataContractQueryHandler; -} - -module.exports = dataContractQueryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/documentQueryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/query/documentQueryHandlerFactory.js deleted file mode 100644 index c78f6445dbb..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/documentQueryHandlerFactory.js +++ /dev/null @@ -1,97 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetDocumentsResponse, - }, -} = require('@dashevo/dapi-grpc'); - -const InvalidArgumentAbciError = require('../../errors/InvalidArgumentAbciError'); -const InvalidQueryError = require('../../../document/errors/InvalidQueryError'); - -/** - * - * @param {fetchDocuments} fetchDocuments - * @param {proveDocuments} proveDocuments - * @param {createQueryResponse} createQueryResponse - * @return {documentQueryHandler} - */ -function documentQueryHandlerFactory( - fetchDocuments, - proveDocuments, - createQueryResponse, -) { - /** - * @typedef {documentQueryHandler} - * @param {Object} params - * @param {Object} data - * @param {Buffer} data.contractId - * @param {string} data.type - * @param {string} [data.where] - * @param {string} [data.orderBy] - * @param {string} [data.limit] - * @param {Buffer} [data.startAfter] - * @param {Buffer} [data.startAt] - * @param {RequestQuery} request - * @return {Promise} - */ - async function documentQueryHandler( - params, - { - contractId, - type, - where, - orderBy, - limit, - startAfter, - startAt, - }, - request, - ) { - const response = createQueryResponse(GetDocumentsResponse, request.prove); - - const options = { - where, - orderBy, - limit, - startAfter: startAfter ? Buffer.from(startAfter) : startAfter, - startAt: startAt ? Buffer.from(startAt) : startAt, - }; - - try { - if (request.prove) { - const proof = await proveDocuments(contractId, type, options); - - response.getProof().setMerkleProof(proof.getValue()); - } else { - const documentsResult = await fetchDocuments(contractId, type, options); - - const documents = documentsResult.getValue(); - - response.setDocumentsList( - documents.map((document) => document.toBuffer()), - ); - } - } catch (e) { - if (e instanceof InvalidQueryError) { - throw new InvalidArgumentAbciError(`Invalid query: ${e.message}`); - } - - throw e; - } - - return new ResponseQuery({ - value: response.serializeBinary(), - }); - } - - return documentQueryHandler; -} - -module.exports = documentQueryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/getProofsQueryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/query/getProofsQueryHandlerFactory.js deleted file mode 100644 index 585fb8db9b4..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/getProofsQueryHandlerFactory.js +++ /dev/null @@ -1,110 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const cbor = require('cbor'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); - -/** - * - * @param {BlockExecutionContext} latestBlockExecutionContext - * @param {IdentityStoreRepository} identityRepository - * @param {DataContractStoreRepository} dataContractRepository - * @param {DocumentRepository} documentRepository - * @return {getProofsQueryHandler} - */ -function getProofsQueryHandlerFactory( - latestBlockExecutionContext, - identityRepository, - dataContractRepository, - documentRepository, -) { - /** - * @typedef getProofsQueryHandler - * @param params - * @param callArguments - * @param {Buffer[]} callArguments.identityIds - * @param {Buffer[]} callArguments.dataContractIds - * @param {{dataContractId: Buffer, documentId: Buffer, type: string}[]} documents - * @return {Promise} - */ - async function getProofsQueryHandler(params, { - identityIds, - dataContractIds, - documents, - }) { - const blockHeight = latestBlockExecutionContext.getHeight(); - const coreChainLockedHeight = latestBlockExecutionContext.getCoreChainLockedHeight(); - const timeMs = latestBlockExecutionContext.getTimeMs(); - const version = latestBlockExecutionContext.getVersion(); - const { - quorumHash, - blockSignature: signature, - } = latestBlockExecutionContext.getLastCommitInfo(); - const round = latestBlockExecutionContext.getRound(); - - const response = { - documentsProof: null, - identitiesProof: null, - dataContractsProof: null, - metadata: { - height: blockHeight.toNumber(), - coreChainLockedHeight, - timeMs, - protocolVersion: version.app.toNumber(), - }, - }; - - if (documents && documents.length) { - const documentsProof = await documentRepository - .proveManyDocumentsFromDifferentContracts(documents); - - response.documentsProof = { - quorumHash, - signature, - merkleProof: documentsProof.getValue(), - round, - }; - } - - if (identityIds && identityIds.length) { - const identitiesProof = await identityRepository.proveMany( - identityIds.map((identityId) => Identifier.from(identityId)), - ); - - response.identitiesProof = { - quorumHash, - signature, - merkleProof: identitiesProof.getValue(), - round, - }; - } - - if (dataContractIds && dataContractIds.length) { - const dataContractsProof = await dataContractRepository.proveMany( - dataContractIds.map((dataContractId) => Identifier.from(dataContractId)), - ); - - response.dataContractsProof = { - quorumHash, - signature, - merkleProof: dataContractsProof.getValue(), - round, - }; - } - - return new ResponseQuery({ - value: await cbor.encodeAsync( - response, - ), - }); - } - - return getProofsQueryHandler; -} - -module.exports = getProofsQueryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.js deleted file mode 100644 index 3b1706bda87..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.js +++ /dev/null @@ -1,70 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetIdentitiesByPublicKeyHashesResponse, - }, -} = require('@dashevo/dapi-grpc'); - -const InvalidArgumentAbciError = require('../../errors/InvalidArgumentAbciError'); - -/** - * - * @param {IdentityStoreRepository} identityRepository - * @param {number} maxIdentitiesPerRequest - * @param {createQueryResponse} createQueryResponse - * @return {identitiesByPublicKeyHashesQueryHandler} - */ -function identitiesByPublicKeyHashesQueryHandlerFactory( - identityRepository, - maxIdentitiesPerRequest, - createQueryResponse, -) { - /** - * @typedef identitiesByPublicKeyHashesQueryHandler - * @param {Object} params - * @param {Object} data - * @param {Buffer[]} data.publicKeyHashes - * @param {RequestQuery} request - * @return {Promise} - */ - async function identitiesByPublicKeyHashesQueryHandler(params, { publicKeyHashes }, request) { - if (publicKeyHashes && publicKeyHashes.length > maxIdentitiesPerRequest) { - throw new InvalidArgumentAbciError( - `Maximum number of ${maxIdentitiesPerRequest} requested items exceeded.`, { - maxIdentitiesPerRequest, - }, - ); - } - - const response = createQueryResponse(GetIdentitiesByPublicKeyHashesResponse, request.prove); - - if (request.prove) { - const proof = await identityRepository.proveManyByPublicKeyHashes(publicKeyHashes); - - response.getProof().setMerkleProof(proof.getValue()); - } else { - const identitiesListResult = await identityRepository.fetchManyByPublicKeyHashes( - publicKeyHashes, - ); - - response.setIdentitiesList( - identitiesListResult.getValue().map((identity) => identity.toBuffer()), - ); - } - - return new ResponseQuery({ - value: response.serializeBinary(), - }); - } - - return identitiesByPublicKeyHashesQueryHandler; -} - -module.exports = identitiesByPublicKeyHashesQueryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/identityQueryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/query/identityQueryHandlerFactory.js deleted file mode 100644 index 179002335b1..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/identityQueryHandlerFactory.js +++ /dev/null @@ -1,75 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetIdentityResponse, - }, -} = require('@dashevo/dapi-grpc'); - -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentifierError = require('@dashevo/dpp/lib/identifier/errors/IdentifierError'); - -const NotFoundAbciError = require('../../errors/NotFoundAbciError'); -const InvalidArgumentAbciError = require('../../errors/InvalidArgumentAbciError'); - -/** - * - * @param {IdentityStoreRepository} identityRepository - * @param {createQueryResponse} createQueryResponse - * @return {identityQueryHandler} - */ -function identityQueryHandlerFactory( - identityRepository, - createQueryResponse, -) { - /** - * @typedef identityQueryHandler - * @param {Object} params - * @param {Object} options - * @param {Buffer} options.id - * @param {RequestQuery} request - * @return {Promise} - */ - async function identityQueryHandler(params, { id }, request) { - let identifier; - try { - identifier = new Identifier(id); - } catch (e) { - if (e instanceof IdentifierError) { - throw new InvalidArgumentAbciError('id must be a valid identifier (32 bytes long)'); - } - - throw e; - } - - const response = createQueryResponse(GetIdentityResponse, request.prove); - - if (request.prove) { - const proof = await identityRepository.prove(identifier); - - response.getProof().setMerkleProof(proof.getValue()); - } else { - const identityResult = await identityRepository.fetch(identifier); - - if (identityResult.isNull()) { - throw new NotFoundAbciError('Identity not found'); - } - - response.setIdentity(identityResult.getValue().toBuffer()); - } - - return new ResponseQuery({ - value: response.serializeBinary(), - }); - } - - return identityQueryHandler; -} - -module.exports = identityQueryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/query/response/createQueryResponseFactory.js b/packages/js-drive/lib/abci/handlers/query/response/createQueryResponseFactory.js deleted file mode 100644 index cf22cf73228..00000000000 --- a/packages/js-drive/lib/abci/handlers/query/response/createQueryResponseFactory.js +++ /dev/null @@ -1,65 +0,0 @@ -const { - v0: { - Proof, - ResponseMetadata, - }, -} = require('@dashevo/dapi-grpc'); - -const UnavailableAbciError = require('../../../errors/UnavailableAbciError'); - -/** - * @param {BlockExecutionContext} latestBlockExecutionContext - * @return {createQueryResponse} - */ -function createQueryResponseFactory( - latestBlockExecutionContext, -) { - /** - * @typedef {createQueryResponse} - * @param {Function} ResponseClass - * @param {boolean} [prove=false] - */ - function createQueryResponse(ResponseClass, prove = false) { - if (latestBlockExecutionContext.isEmpty()) { - throw new UnavailableAbciError('data is not available'); - } - - const blockHeight = latestBlockExecutionContext.getHeight(); - const coreChainLockedHeight = latestBlockExecutionContext.getCoreChainLockedHeight(); - const timeMs = latestBlockExecutionContext.getTimeMs(); - const version = latestBlockExecutionContext.getVersion(); - - const response = new ResponseClass(); - - const metadata = new ResponseMetadata(); - metadata.setHeight(blockHeight); - metadata.setCoreChainLockedHeight(coreChainLockedHeight); - metadata.setTimeMs(timeMs); - metadata.setProtocolVersion(version.app); - - response.setMetadata(metadata); - - if (prove) { - const { - quorumHash, - blockSignature: signature, - } = latestBlockExecutionContext.getLastCommitInfo(); - - const round = latestBlockExecutionContext.getRound(); - - const proof = new Proof(); - - proof.setQuorumHash(quorumHash); - proof.setSignature(signature); - proof.setRound(round); - - response.setProof(proof); - } - - return response; - } - - return createQueryResponse; -} - -module.exports = createQueryResponseFactory; diff --git a/packages/js-drive/lib/abci/handlers/queryHandlerFactory.js b/packages/js-drive/lib/abci/handlers/queryHandlerFactory.js deleted file mode 100644 index 338538af6a0..00000000000 --- a/packages/js-drive/lib/abci/handlers/queryHandlerFactory.js +++ /dev/null @@ -1,58 +0,0 @@ -const cbor = require('cbor'); - -const InvalidArgumentAbciError = require('../errors/InvalidArgumentAbciError'); - -/** - * @param {Object} queryHandlerRouter - * @param {Function} sanitizeUrl - * @param {BaseLogger} logger - * @param {createContextLogger} createContextLogger - * @return {queryHandler} - */ -function queryHandlerFactory(queryHandlerRouter, sanitizeUrl, logger, createContextLogger) { - /** - * Query ABCI Handler - * - * @typedef queryHandler - * - * @param {RequestQuery} request - * @return {Promise} - */ - async function queryHandler(request) { - const { path, data } = request; - - createContextLogger(logger, { - abciMethod: 'query', - }); - - const route = queryHandlerRouter.find('GET', sanitizeUrl(path)); - - if (!route) { - throw new InvalidArgumentAbciError('Invalid path', { path }); - } - - const invalidDataMessage = 'Invalid data format: it should be cbor encoded object.'; - - let encodedData = {}; - - const decodeData = route.store && route.store.rawData === true; - - if (data.length > 0) { - try { - encodedData = decodeData ? Buffer.from(data) : cbor.decode(Buffer.from(data)); - } catch (e) { - throw new InvalidArgumentAbciError(invalidDataMessage); - } - - if (encodedData === null || typeof encodedData !== 'object') { - throw new InvalidArgumentAbciError(invalidDataMessage); - } - } - - return route.handler(route.params, encodedData, request); - } - - return queryHandler; -} - -module.exports = queryHandlerFactory; diff --git a/packages/js-drive/lib/abci/handlers/stateTransition/unserializeStateTransitionFactory.js b/packages/js-drive/lib/abci/handlers/stateTransition/unserializeStateTransitionFactory.js deleted file mode 100644 index 91433eedbbd..00000000000 --- a/packages/js-drive/lib/abci/handlers/stateTransition/unserializeStateTransitionFactory.js +++ /dev/null @@ -1,120 +0,0 @@ -const InvalidStateTransitionError = require('@dashevo/dpp/lib/stateTransition/errors/InvalidStateTransitionError'); -const InvalidArgumentAbciError = require('../../errors/InvalidArgumentAbciError'); - -const DPPValidationAbciError = require('../../errors/DPPValidationAbciError'); - -const TIMERS = require('../timers'); - -/** - * @param {DashPlatformProtocol} dpp - * @param {Object} noopLogger - * @return {unserializeStateTransition} - */ -function unserializeStateTransitionFactory(dpp, noopLogger) { - /** - * @typedef unserializeStateTransition - * @param {Uint8Array} stateTransitionByteArray - * @param {Object} [options] - * @param {BaseLogger} [options.logger] - * @param {ExecutionTimer} [options.executionTimer] - * @return {AbstractStateTransition} - */ - async function unserializeStateTransition(stateTransitionByteArray, options = {}) { - // either use a logger passed or use noop logger - const logger = (options.logger || noopLogger); - - // measure timing if timer is passed - const executionTimer = (options.executionTimer || { - startTimer: () => {}, - stopTimer: () => {}, - }); - - if (!stateTransitionByteArray) { - logger.warn('State transition is not specified'); - - throw new InvalidArgumentAbciError('State Transition is not specified'); - } - - const stateTransitionSerialized = Buffer.from(stateTransitionByteArray); - - executionTimer.startTimer(TIMERS.DELIVER_TX.VALIDATE_BASIC); - - let stateTransition; - try { - stateTransition = await dpp - .stateTransition - .createFromBuffer(stateTransitionSerialized); - } catch (e) { - if (e instanceof InvalidStateTransitionError) { - const consensusError = e.getErrors()[0]; - const message = 'Invalid state transition'; - - logger.info(message); - logger.debug({ - consensusError, - }); - - throw new DPPValidationAbciError(message, consensusError); - } - - throw e; - } - - executionTimer.stopTimer(TIMERS.DELIVER_TX.VALIDATE_BASIC, true); - - executionTimer.startTimer(TIMERS.DELIVER_TX.VALIDATE_SIGNATURE); - - let result = await dpp.stateTransition.validateSignature(stateTransition); - - if (!result.isValid()) { - const consensusError = result.getFirstError(); - const message = 'Invalid state transition signature'; - - logger.info(message); - - logger.debug({ - consensusError, - }); - - throw new DPPValidationAbciError(message, consensusError); - } - - executionTimer.stopTimer(TIMERS.DELIVER_TX.VALIDATE_SIGNATURE, true); - - executionTimer.startTimer(TIMERS.DELIVER_TX.VALIDATE_FEE); - - const executionContext = stateTransition.getExecutionContext(); - - // Pre-calculate fee for validateState and state transition apply - // with worst case costs to validate the whole state transition execution cost - executionContext.enableDryRun(); - - await dpp.stateTransition.validateState(stateTransition); - await dpp.stateTransition.apply(stateTransition); - - executionContext.disableDryRun(); - - result = await dpp.stateTransition.validateFee(stateTransition); - - if (!result.isValid()) { - const consensusError = result.getFirstError(); - const message = 'Insufficient funds to process state transition'; - - logger.info(message); - - logger.debug({ - consensusError, - }); - - throw new DPPValidationAbciError(message, consensusError); - } - - executionTimer.stopTimer(TIMERS.DELIVER_TX.VALIDATE_FEE, true); - - return stateTransition; - } - - return unserializeStateTransition; -} - -module.exports = unserializeStateTransitionFactory; diff --git a/packages/js-drive/lib/abci/handlers/timers.js b/packages/js-drive/lib/abci/handlers/timers.js deleted file mode 100644 index 8aa29e8c4cf..00000000000 --- a/packages/js-drive/lib/abci/handlers/timers.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - DELIVER_TX: { - OVERALL: 'deliverTx:overall', - VALIDATE_BASIC: 'deliverTx:validate:basic', - VALIDATE_FEE: 'deliverTx:validate:fee', - VALIDATE_SIGNATURE: 'deliverTx:validate:signature', - VALIDATE_STATE: 'deliverTx:validate:state', - APPLY: 'deliverTx:apply', - }, -}; diff --git a/packages/js-drive/lib/abci/handlers/validator/createValidatorSetUpdate.js b/packages/js-drive/lib/abci/handlers/validator/createValidatorSetUpdate.js deleted file mode 100644 index 60287f54b5e..00000000000 --- a/packages/js-drive/lib/abci/handlers/validator/createValidatorSetUpdate.js +++ /dev/null @@ -1,49 +0,0 @@ -const { - tendermint: { - abci: { - ValidatorUpdate, - ValidatorSetUpdate, - }, - crypto: { - PublicKey, - }, - }, -} = require('@dashevo/abci/types'); - -/** - * @typedef {createValidatorSetUpdate} - * @param {ValidatorSet} validatorSet - * @return {ValidatorSetUpdate} - */ -function createValidatorSetUpdate(validatorSet) { - const validatorUpdates = validatorSet.getValidators() - .map((validator) => { - const networkInfo = validator.getNetworkInfo(); - - const validatorUpdate = new ValidatorUpdate({ - power: validator.getVotingPower(), - proTxHash: validator.getProTxHash(), - nodeAddress: `tcp://${networkInfo.getHost()}:${networkInfo.getPort()}`, - }); - - if (validator.getPublicKeyShare()) { - validatorUpdate.pubKey = new PublicKey({ - bls12381: validator.getPublicKeyShare(), - }); - } - - return validatorUpdate; - }); - - const { quorumPublicKey, quorumHash } = validatorSet.getQuorum(); - - return new ValidatorSetUpdate({ - validatorUpdates, - thresholdPublicKey: new PublicKey({ - bls12381: Buffer.from(quorumPublicKey, 'hex'), - }), - quorumHash: Buffer.from(quorumHash, 'hex'), - }); -} - -module.exports = createValidatorSetUpdate; diff --git a/packages/js-drive/lib/abci/handlers/verifyVoteExtensionHandlerFactory.js b/packages/js-drive/lib/abci/handlers/verifyVoteExtensionHandlerFactory.js deleted file mode 100644 index c414ef3e4a7..00000000000 --- a/packages/js-drive/lib/abci/handlers/verifyVoteExtensionHandlerFactory.js +++ /dev/null @@ -1,92 +0,0 @@ -const { - tendermint: { - abci: { - ResponseVerifyVoteExtension, - }, - types: { - VoteExtensionType, - }, - }, -} = require('@dashevo/abci/types'); - -const verifyStatus = { - UNKNOWN: 0, // Unknown status. Returning this from the application is always an error. - ACCEPT: 1, // Status that signals that the application finds the vote extension valid. - REJECT: 2, // Status that signals that the application finds the vote extension invalid. -}; - -/** - * @param {BlockExecutionContext} proposalBlockExecutionContext - * @return {verifyVoteExtensionHandler} - */ -function verifyVoteExtensionHandlerFactory(proposalBlockExecutionContext) { - /** - * @typedef verifyVoteExtensionHandler - * - * @param {abci.RequestVerifyVoteExtension} request - * - * @return {Promise} - */ - async function verifyVoteExtensionHandler(request) { - const { - voteExtensions, - } = request; - - const contextLogger = proposalBlockExecutionContext.getContextLogger() - .child({ - abciMethod: 'verifyVoteExtension', - }); - - contextLogger.debug('VerifyVote ABCI method requested'); - contextLogger.trace({ request }); - - const unsignedWithdrawalTransactionsMap = proposalBlockExecutionContext - .getWithdrawalTransactionsMap(); - - const voteExtensionsToCheck = Object.keys(unsignedWithdrawalTransactionsMap || {}) - .sort() - .map((txHashHex) => ({ - type: VoteExtensionType.THRESHOLD_RECOVER, - extension: Buffer.from(txHashHex, 'hex'), - })); - - const numberOfVoteExtensionsMatch = ( - voteExtensionsToCheck.length === (voteExtensions || []).length - ); - - const allVoteExtensionsPresent = voteExtensionsToCheck.reduce((result, nextExtension) => { - const searchedVoteExtension = (voteExtensions || []).find((voteExtension) => ( - voteExtension.type === nextExtension.type - && Buffer.compare(voteExtension.extension, nextExtension.extension) - )); - - if (!searchedVoteExtension) { - const extensionString = nextExtension.extension.toString('hex'); - - const extensionTruncatedString = extensionString.substring( - 0, - Math.min(30, extensionString.length), - ); - - contextLogger.warn({ - type: nextExtension.type, - extension: extensionString, - }, `${nextExtension.type} vote extension ${extensionTruncatedString}... was not found in verify request`); - } - - return result && (searchedVoteExtension !== undefined); - }, true); - - const status = (numberOfVoteExtensionsMatch && allVoteExtensionsPresent) - ? verifyStatus.ACCEPT - : verifyStatus.REJECT; - - return new ResponseVerifyVoteExtension({ - status, - }); - } - - return verifyVoteExtensionHandler; -} - -module.exports = verifyVoteExtensionHandlerFactory; diff --git a/packages/js-drive/lib/blockExecution/BlockExecutionContext.js b/packages/js-drive/lib/blockExecution/BlockExecutionContext.js deleted file mode 100644 index 52df4c12f93..00000000000 --- a/packages/js-drive/lib/blockExecution/BlockExecutionContext.js +++ /dev/null @@ -1,383 +0,0 @@ -const DataContract = require('@dashevo/dpp/lib/dataContract/DataContract'); - -const { - tendermint: { - abci: { - CommitInfo, - }, - version: { - Consensus, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -class BlockExecutionContext { - constructor() { - this.reset(); - } - - /** - * Add Data Contract - * - * @param {DataContract|null} dataContract - */ - addDataContract(dataContract) { - this.dataContracts.push(dataContract); - } - - /** - * Check is data contract with specific ID is persistent in the context - * - * @param {Identifier} dataContractId - * @return {boolean} - */ - hasDataContract(dataContractId) { - const index = this.dataContracts - .findIndex((dataContract) => dataContractId.equals(dataContract.getId())); - - return index !== -1; - } - - /** - * Get Data Contracts - * - * @returns {DataContract[]} - */ - getDataContracts() { - return this.dataContracts; - } - - /** - * - * @param {number} coreChainLockedHeight - * @return {BlockExecutionContext} - */ - setCoreChainLockedHeight(coreChainLockedHeight) { - this.coreChainLockedHeight = coreChainLockedHeight; - - return this; - } - - /** - * - * @return {number} - */ - getCoreChainLockedHeight() { - return this.coreChainLockedHeight; - } - - /** - * @param {Long} height - * @return {BlockExecutionContext} - */ - setHeight(height) { - this.height = height; - - return this; - } - - /** - * - * @return {Long} - */ - getHeight() { - return this.height; - } - - /** - * - * @param {IConsensus} version - * @return {BlockExecutionContext} - */ - setVersion(version) { - this.version = version; - - return this; - } - - /** - * - * @return {IConsensus} - */ - getVersion() { - return this.version; - } - - /** - * - * @param {Long} version - * @return {BlockExecutionContext} - */ - setProposedAppVersion(version) { - this.proposedAppVersion = version; - - return this; - } - - /** - * - * @return {Long} - */ - getProposedAppVersion() { - return this.proposedAppVersion; - } - - /** - * @param {number} timeMs - */ - setTimeMs(timeMs) { - this.timeMs = timeMs; - } - - /** - * @returns {number} - */ - getTimeMs() { - return this.timeMs; - } - - /** - * Set current block lastCommitInfo - * @param {ILastCommitInfo} lastCommitInfo - * @return {BlockExecutionContext} - */ - setLastCommitInfo(lastCommitInfo) { - this.lastCommitInfo = lastCommitInfo; - - return this; - } - - /** - * Get block lastCommitInfo - * - * @return {ILastCommitInfo|null} - */ - getLastCommitInfo() { - return this.lastCommitInfo; - } - - /** - * Set context logger - * - * @param {BaseLogger} logger - */ - setContextLogger(logger) { - this.contextLogger = logger; - } - - /** - * Get context logger - * - * @return {BaseLogger} - */ - getContextLogger() { - if (!this.contextLogger) { - throw new Error('Consensus logger has not been set'); - } - - return this.contextLogger; - } - - /** - * @param {EpochInfo} epochInfo - */ - setEpochInfo(epochInfo) { - this.epochInfo = epochInfo; - } - - /** - * @returns {EpochInfo} - */ - getEpochInfo() { - return this.epochInfo; - } - - /** - * Set withdrawal transactions hash map - * - * @param {Object} withdrawalTransactionsMap - * - * @returns {BlockExecutionContext} - */ - setWithdrawalTransactionsMap(withdrawalTransactionsMap) { - this.withdrawalTransactionsMap = withdrawalTransactionsMap; - - return this; - } - - /** - * Get withdrawal transactions hash map - * - * @return {Object} - */ - getWithdrawalTransactionsMap() { - return this.withdrawalTransactionsMap; - } - - /** - * Set committed round - * - * @param {number} round - * - * @returns {BlockExecutionContext} - */ - setRound(round) { - this.round = round; - - return this; - } - - /** - * Get committed round - * - * @return {number} - */ - getRound() { - return this.round; - } - - /** - * Set PrepareProposal Result - * - * @param {Object} prepareProposalResult - * - * @returns {BlockExecutionContext} - */ - setPrepareProposalResult(prepareProposalResult) { - this.prepareProposalResult = prepareProposalResult; - - return this; - } - - /** - * Get PrepareProposal Result - * - * @return {Object} - */ - getPrepareProposalResult() { - return this.prepareProposalResult; - } - - /** - * Reset state - */ - reset() { - this.dataContracts = []; - this.coreChainLockedHeight = null; - this.height = null; - this.version = null; - this.time = null; - this.lastCommitInfo = null; - this.contextLogger = null; - this.withdrawalTransactionsMap = {}; - this.round = null; - this.epochInfo = null; - this.timeMs = null; - this.prepareProposalResult = null; - this.proposedAppVersion = null; - } - - /** - * Check is the context is not set - * - * @return {boolean} - */ - isEmpty() { - return this.height === null; - } - - /** - * Populate the current instance with data from another instance - * - * @param {BlockExecutionContext} blockExecutionContext - */ - populate(blockExecutionContext) { - this.dataContracts = blockExecutionContext.dataContracts; - this.lastCommitInfo = blockExecutionContext.lastCommitInfo; - this.time = blockExecutionContext.time; - this.height = blockExecutionContext.height; - this.coreChainLockedHeight = blockExecutionContext.coreChainLockedHeight; - this.version = blockExecutionContext.version; - this.contextLogger = blockExecutionContext.contextLogger || null; - this.withdrawalTransactionsMap = blockExecutionContext.withdrawalTransactionsMap; - this.round = blockExecutionContext.round; - this.epochInfo = blockExecutionContext.epochInfo; - this.timeMs = blockExecutionContext.timeMs; - this.prepareProposalResult = blockExecutionContext.prepareProposalResult || null; - this.proposedAppVersion = blockExecutionContext.proposedAppVersion; - } - - /** - * Populate the current instance with data - * - * @param {Object} object - */ - fromObject(object) { - this.dataContracts = object.dataContracts - .map((rawDataContract) => new DataContract(rawDataContract)); - this.lastCommitInfo = CommitInfo.fromObject(object.lastCommitInfo); - this.contextLogger = object.contextLogger; - this.epochInfo = object.epochInfo; - this.timeMs = object.timeMs; - this.height = Long.fromNumber(object.height); - this.coreChainLockedHeight = object.coreChainLockedHeight; - this.version = Consensus.fromObject(object.version); - this.withdrawalTransactionsMap = object.withdrawalTransactionsMap; - this.round = object.round; - this.prepareProposalResult = object.prepareProposalResult; - this.proposedAppVersion = Long.fromNumber(object.proposedAppVersion); - } - - /** - * @param {Object} options - * @param {boolean} [options.skipContextLogger=false] - * @param {boolean} [options.skipPrepareProposalResult=false] - * @return {{ - * dataContracts: Object[], - * height: number, - * version: Object, - * timeMs: number, - * coreChainLockedHeight: number, - * lastCommitInfo: number, - * epochInfo: EpochInfo, - * withdrawalTransactionsMap: Object, - * round: number, - * proposedAppVersion: number, - * }} - */ - toObject(options = {}) { - let time = null; - - if (this.time) { - time = this.time.toJSON(); - time.seconds = Number(time.seconds); - } - - const object = { - dataContracts: this.dataContracts.map((dataContract) => dataContract.toObject()), - timeMs: this.timeMs, - height: this.height ? this.height.toNumber() : null, - version: this.version ? this.version.toJSON() : null, - coreChainLockedHeight: this.coreChainLockedHeight, - lastCommitInfo: this.lastCommitInfo ? CommitInfo.toObject(this.lastCommitInfo) : null, - withdrawalTransactionsMap: this.withdrawalTransactionsMap, - round: this.round, - epochInfo: this.epochInfo, - proposedAppVersion: this.proposedAppVersion ? this.proposedAppVersion.toNumber() : null, - }; - - if (!options.skipContextLogger) { - object.contextLogger = this.contextLogger; - } - - if (!options.skipPrepareProposalResult) { - object.prepareProposalResult = this.prepareProposalResult; - } - - return object; - } -} - -module.exports = BlockExecutionContext; diff --git a/packages/js-drive/lib/blockExecution/BlockExecutionContextRepository.js b/packages/js-drive/lib/blockExecution/BlockExecutionContextRepository.js deleted file mode 100644 index e7e2800ca81..00000000000 --- a/packages/js-drive/lib/blockExecution/BlockExecutionContextRepository.js +++ /dev/null @@ -1,69 +0,0 @@ -const cbor = require('cbor'); - -const BlockExecutionContext = require('./BlockExecutionContext'); - -class BlockExecutionContextRepository { - /** - * - * @param {GroveDBStore} groveDBStore - */ - constructor(groveDBStore) { - this.db = groveDBStore; - } - - /** - * Store block execution context - * - * @param {BlockExecutionContext} blockExecutionContext - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {this} - */ - async store(blockExecutionContext, options = {}) { - await this.db.putAux( - BlockExecutionContextRepository.EXTERNAL_STORE_KEY_NAME, - await cbor.encodeAsync(blockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })), - options, - ); - - return this; - } - - /** - * Fetch block execution stack - * - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {BlockExecutionContext} - */ - async fetch(options = {}) { - const blockExecutionContextEncodedResult = await this.db.getAux( - BlockExecutionContextRepository.EXTERNAL_STORE_KEY_NAME, - options, - ); - - const blockExecutionContextEncoded = blockExecutionContextEncodedResult.getValue(); - - const blockExecutionContext = new BlockExecutionContext(); - - if (!blockExecutionContextEncoded) { - return blockExecutionContext; - } - - const rawBlockExecutionContext = cbor.decode(blockExecutionContextEncoded); - - const context = new BlockExecutionContext(); - - context.fromObject(rawBlockExecutionContext); - - return context; - } -} - -BlockExecutionContextRepository.EXTERNAL_STORE_KEY_NAME = Buffer.from('blockExecutionContext'); - -module.exports = BlockExecutionContextRepository; diff --git a/packages/js-drive/lib/blockExecution/BlockInfo.js b/packages/js-drive/lib/blockExecution/BlockInfo.js deleted file mode 100644 index 75c5f0b553e..00000000000 --- a/packages/js-drive/lib/blockExecution/BlockInfo.js +++ /dev/null @@ -1,54 +0,0 @@ -class BlockInfo { - /** - * @type {number} - */ - height; - - /** - * @type {number} - */ - epoch; - - /** - * @type {number} - */ - timeMs; - - /** - * @param {number} height - * @param {number} epoch - * @param {number} timeMs - */ - constructor(height, epoch, timeMs) { - this.height = height; - this.epoch = epoch; - this.timeMs = timeMs; - } - - /** - * @returns {RawBlockInfo} - */ - toObject() { - return { - height: this.height, - epoch: this.epoch, - timeMs: this.timeMs, - }; - } - - /** - * @param {BlockExecutionContext} blockExecutionContext - * @returns {BlockInfo} - */ - static createFromBlockExecutionContext(blockExecutionContext) { - const epochInfo = blockExecutionContext.getEpochInfo(); - - return new BlockInfo( - blockExecutionContext.getHeight().toNumber(), - epochInfo.currentEpochIndex, - blockExecutionContext.getTimeMs(), - ); - } -} - -module.exports = BlockInfo; diff --git a/packages/js-drive/lib/blockExecution/errors/BlockExecutionContextNotFoundError.js b/packages/js-drive/lib/blockExecution/errors/BlockExecutionContextNotFoundError.js deleted file mode 100644 index 6c7a0d13698..00000000000 --- a/packages/js-drive/lib/blockExecution/errors/BlockExecutionContextNotFoundError.js +++ /dev/null @@ -1,23 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class BlockExecutionContextNotFoundError extends DriveError { - /** - * - * @param {number} round - */ - constructor(round) { - super(`BlockExecutionContext for round ${round} not found`); - - this.round = round; - } - - /** - * - * @return {number} - */ - getRound() { - return this.round; - } -} - -module.exports = BlockExecutionContextNotFoundError; diff --git a/packages/js-drive/lib/blockExecution/errors/ContextsAreMoreThanStackMaxSizeError.js b/packages/js-drive/lib/blockExecution/errors/ContextsAreMoreThanStackMaxSizeError.js deleted file mode 100644 index a5594fd4e5b..00000000000 --- a/packages/js-drive/lib/blockExecution/errors/ContextsAreMoreThanStackMaxSizeError.js +++ /dev/null @@ -1,9 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class ContextsAreMoreThanStackMaxSizeError extends DriveError { - constructor() { - super('Number of contexts is more than stack max size'); - } -} - -module.exports = ContextsAreMoreThanStackMaxSizeError; diff --git a/packages/js-drive/lib/core/LatestCoreChainLock.js b/packages/js-drive/lib/core/LatestCoreChainLock.js deleted file mode 100644 index 1dee1a2a642..00000000000 --- a/packages/js-drive/lib/core/LatestCoreChainLock.js +++ /dev/null @@ -1,42 +0,0 @@ -const EventEmitter = require('events'); - -class LatestCoreChainLock extends EventEmitter { - /** - * - * @param {ChainLock} [chainLock] - */ - constructor(chainLock = undefined) { - super(); - - this.chainLock = chainLock; - } - - /** - * Update latest chainlock - * - * @param {ChainLock} chainLock - * @return {LatestCoreChainLock} - */ - update(chainLock) { - this.chainLock = chainLock; - - this.emit(LatestCoreChainLock.EVENTS.update, this.chainLock); - this.emit(`${LatestCoreChainLock.EVENTS.update}:${this.chainLock.height}`, this.chainLock); - - return this; - } - - /** - * - * @return {ChainLock} - */ - getChainLock() { - return this.chainLock; - } -} - -LatestCoreChainLock.EVENTS = { - update: 'update', -}; - -module.exports = LatestCoreChainLock; diff --git a/packages/js-drive/lib/core/SimplifiedMasternodeList.js b/packages/js-drive/lib/core/SimplifiedMasternodeList.js deleted file mode 100644 index 804d55707b8..00000000000 --- a/packages/js-drive/lib/core/SimplifiedMasternodeList.js +++ /dev/null @@ -1,47 +0,0 @@ -const SimplifiedMNListStore = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListStore'); - -class SimplifiedMasternodeList { - constructor(options) { - this.options = { - maxListsLimit: options.smlMaxListsLimit, - }; - - this.store = undefined; - } - - /** - * @param {SimplifiedMNListDiff[]} smlDiffs - * - * @return SimplifiedMasternodeList - */ - applyDiffs(smlDiffs) { - if (!this.store) { - this.store = new SimplifiedMNListStore([...smlDiffs], this.options); - } else { - smlDiffs.forEach((diff) => { - this.store.addDiff(diff); - }); - } - - return this; - } - - /** - * - * @return {SimplifiedMNListStore|undefined} - */ - getStore() { - return this.store; - } - - /** - * Reset the SML store - * - * @return {void} - */ - reset() { - this.store = undefined; - } -} - -module.exports = SimplifiedMasternodeList; diff --git a/packages/js-drive/lib/core/ZmqClient.js b/packages/js-drive/lib/core/ZmqClient.js deleted file mode 100644 index e3450af613d..00000000000 --- a/packages/js-drive/lib/core/ZmqClient.js +++ /dev/null @@ -1,129 +0,0 @@ -const { EventEmitter } = require('events'); -const zeromq = require('zeromq'); - -const ZMQ_TOPICS = { - hashtx: 'hashtx', - hashtxlock: 'hashtxlock', - hashblock: 'hashblock', - rawblock: 'rawblock', - rawtx: 'rawtx', - rawtxlock: 'rawtxlock', - rawtxlocksig: 'rawtxlocksig', - rawchainlock: 'rawchainlock', - rawchainlocksig: 'rawchainlocksig', -}; - -const defaultOptions = { topics: ZMQ_TOPICS, maxRetryCount: 20 }; - -class ZmqClient extends EventEmitter { - constructor(host, port, options = defaultOptions) { - super(); - this.subscriberSocket = zeromq.socket('sub'); - this.connectionString = `tcp://${host}:${port}`; - this.topics = options.topics || []; - this.maxRetryCount = options.maxRetryCount; - this.isConnected = false; - this.resetConnectionFailuresCount(); - } - - resetConnectionFailuresCount() { - this.connectionFailuresCount = 0; - } - - /** - * Starts listening to zmq messages - * @returns {Promise} - */ - start() { - return new Promise((resolve) => { - this.subscriberSocket.once('connect', () => resolve()); - this.subscriberSocket.once('connect', () => { - this.emit(ZmqClient.events.CONNECTED); - }); - this.subscriberSocket.on('connect', () => { - this.resetConnectionFailuresCount(); - }); - - this.initErrorHandlers(); - this.initMessageHandlers(); - this.startMonitor(); - this.subscriberSocket.connect(this.connectionString); - this.isConnected = true; - }); - } - - /** - * @private - * Starts connection monitor to monitor connection status - */ - startMonitor() { - this.subscriberSocket.monitor(500, 0); - } - - /** - * @private - */ - incrementErrorCount() { - this.connectionFailuresCount += 1; - if (this.connectionFailuresCount >= this.maxRetryCount) { - this.emit(ZmqClient.events.MAX_RETRIES_REACHED, `Failed to connect to ZMQ after ${this.maxRetryCount} tries`); - } - } - - /** - * Init connection error handlers. Requires connection monitor to be started - */ - initErrorHandlers() { - this.subscriberSocket.on('connect_delay', () => { - this.emit(ZmqClient.events.CONNECTION_DELAY, 'Dashcore ZMQ connection delay'); - this.incrementErrorCount(); - }); - this.subscriberSocket.on('disconnect', () => { - this.emit(ZmqClient.events.DISCONNECTED, 'Dashcore ZMQ connection is lost'); - this.incrementErrorCount(); - }); - this.subscriberSocket.on('monitor_error', (error) => { - this.emit(ZmqClient.events.MONITOR_ERROR, error); - this.incrementErrorCount(); - setTimeout(() => this.startMonitor(), 1000); - }); - } - - /** - * Subscribes to zmq messages - */ - initMessageHandlers() { - Object.keys(this.topics).forEach((key) => this.subscriberSocket.subscribe(this.topics[key])); - this.subscriberSocket.on('message', this.emit.bind(this)); - } - - subscribe(topicName, callback) { - const isAlreadySubscribed = Object.keys(this.topics).includes(topicName); - - if (!this.isConnected) { - throw new Error('Socket not connected. Wait until .start() resolves'); - } - - if (!isAlreadySubscribed) { - this.topics[topicName] = topicName; - this.subscriberSocket.subscribe(topicName); - } - - if (callback) { - this.on(topicName, callback); - } - } -} - -ZmqClient.events = { - CONNECTION_DELAY: 'CONNECTION_DELAY', - DISCONNECTED: 'DISCONNECTED', - MONITOR_ERROR: 'MONITOR_ERROR', - ERROR: 'ERROR', - MAX_RETRIES_REACHED: 'MAX_RETRIES_REACHED', - CONNECTED: 'CONNECTED', -}; - -ZmqClient.TOPICS = ZMQ_TOPICS; - -module.exports = ZmqClient; diff --git a/packages/js-drive/lib/core/ensureBlock.js b/packages/js-drive/lib/core/ensureBlock.js deleted file mode 100644 index 4b3091dcde1..00000000000 --- a/packages/js-drive/lib/core/ensureBlock.js +++ /dev/null @@ -1,35 +0,0 @@ -const ZMQClient = require('./ZmqClient'); - -/** - * - * @param {ZMQClient} zmqClient - * @param {RpcClient} rpcClient - * @param {string} hash - * @return {Promise} - */ -async function ensureBlock(zmqClient, rpcClient, hash) { - const eventPromise = new Promise((resolve) => { - const onHashBlock = (response) => { - if (hash.toString('hex') === response.toString('hex')) { - zmqClient.removeListener(ZMQClient.TOPICS.hashblock, onHashBlock); - - resolve(response); - } - }; - - zmqClient.on(ZMQClient.TOPICS.hashblock, onHashBlock); - }); - - try { - await rpcClient.getBlock(hash.toString('hex')); - } catch (e) { - // Block not found - if (e.code === -5) { - await eventPromise; - } else { - throw e; - } - } -} - -module.exports = ensureBlock; diff --git a/packages/js-drive/lib/core/errors/MissingChainLockError.js b/packages/js-drive/lib/core/errors/MissingChainLockError.js deleted file mode 100644 index ab3a2960e45..00000000000 --- a/packages/js-drive/lib/core/errors/MissingChainLockError.js +++ /dev/null @@ -1,11 +0,0 @@ -class MissingChainLockError extends Error { - constructor() { - super('ChainLock is required to obtain SML'); - - this.name = this.constructor.name; - - Error.captureStackTrace(this, this.constructor); - } -} - -module.exports = MissingChainLockError; diff --git a/packages/js-drive/lib/core/errors/NotEnoughBlocksForValidSMLError.js b/packages/js-drive/lib/core/errors/NotEnoughBlocksForValidSMLError.js deleted file mode 100644 index 9021506a9ef..00000000000 --- a/packages/js-drive/lib/core/errors/NotEnoughBlocksForValidSMLError.js +++ /dev/null @@ -1,23 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class NotEnoughBlocksForValidSMLError extends DriveError { - /** - * @param {number} blockHeight - */ - constructor(blockHeight) { - super(`${blockHeight} blocks are not enough to obtain comprehensive SML. Needs 16 block diffs minimum`); - - this.blockHeight = blockHeight; - } - - /** - * Get block height - * - * @return {number} - */ - getBlockHeight() { - return this.blockHeight; - } -} - -module.exports = NotEnoughBlocksForValidSMLError; diff --git a/packages/js-drive/lib/core/errors/QuorumsNotFoundError.js b/packages/js-drive/lib/core/errors/QuorumsNotFoundError.js deleted file mode 100644 index 6b3e12d0ead..00000000000 --- a/packages/js-drive/lib/core/errors/QuorumsNotFoundError.js +++ /dev/null @@ -1,31 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class QuorumsNotFoundError extends DriveError { - /** - * @param {SimplifiedMNList} simplifiedMNList - * @param {number} quorumType - */ - constructor(simplifiedMNList, quorumType) { - let message; - if (simplifiedMNList.quorumList.length === 0) { - message = `SML at block ${simplifiedMNList.blockHash} contains no quorums of any type`; - } else { - const otherQuorumTypes = [...new Set(simplifiedMNList.quorumList.map((quorumEntry) => quorumEntry.llmqType))].join(','); - message = `SML at block ${simplifiedMNList.blockHash} contains no quorums of type ${quorumType}, but contains entries for types ${otherQuorumTypes}. Please check the Drive configuration`; - } - super(message); - - this.simplifiedMNList = simplifiedMNList; - } - - /** - * Get block height - * - * @return {SimplifiedMNList} - */ - getSimplifiedMNList() { - return this.simplifiedMNList; - } -} - -module.exports = QuorumsNotFoundError; diff --git a/packages/js-drive/lib/core/fetchQuorumMembersFactory.js b/packages/js-drive/lib/core/fetchQuorumMembersFactory.js deleted file mode 100644 index bd175746c5d..00000000000 --- a/packages/js-drive/lib/core/fetchQuorumMembersFactory.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * @param {RpcClient} coreRpcClient - * @return {fetchQuorumMembers} - */ -function fetchQuorumMembersFactory(coreRpcClient) { - /** - * @typedef {fetchQuorumMembers} - * @param {number} quorumType - * @param {string} quorumHash - * @return {Promise} - */ - async function fetchQuorumMembers(quorumType, quorumHash) { - try { - const { - result: { - members: validators, - }, - } = await coreRpcClient.quorum( - 'info', - quorumType, - quorumHash, - ); - - return validators; - } catch (e) { - // RPC_INVALID_PARAMETER: quorum not found - if (e.code === -8) { - throw new Error(`The quorum of type ${quorumType} and quorumHash ${quorumHash} doesn't exist`); - } - - throw e; - } - } - - return fetchQuorumMembers; -} - -module.exports = fetchQuorumMembersFactory; diff --git a/packages/js-drive/lib/core/fetchSimplifiedMNListFactory.js b/packages/js-drive/lib/core/fetchSimplifiedMNListFactory.js deleted file mode 100644 index 52d9e360a8f..00000000000 --- a/packages/js-drive/lib/core/fetchSimplifiedMNListFactory.js +++ /dev/null @@ -1,23 +0,0 @@ -const { SimplifiedMNList } = require('@dashevo/dashcore-lib'); - -/** - * @param {RpcClient} coreRpcClient - * @returns {fetchSimplifiedMNList} - */ -function fetchSimplifiedMNListFactory(coreRpcClient) { - /** - * @typedef fetchSimplifiedMNList - * @param {number} fromBlockHeight - * @param {number} toBlockHeight - * @returns {Promise} - */ - async function fetchSimplifiedMNList(fromBlockHeight, toBlockHeight) { - const { result: rawDiff } = await coreRpcClient.protx('diff', fromBlockHeight, toBlockHeight, true); - - return new SimplifiedMNList(rawDiff); - } - - return fetchSimplifiedMNList; -} - -module.exports = fetchSimplifiedMNListFactory; diff --git a/packages/js-drive/lib/core/fetchTransactionFactory.js b/packages/js-drive/lib/core/fetchTransactionFactory.js deleted file mode 100644 index 2a770150429..00000000000 --- a/packages/js-drive/lib/core/fetchTransactionFactory.js +++ /dev/null @@ -1,33 +0,0 @@ -const { Transaction } = require('@dashevo/dashcore-lib'); - -/** - * @param {RpcClient} coreRpcClient - * @returns {fetchTransaction} - */ -function fetchTransactionFactory(coreRpcClient) { - /** - * @typedef {fetchTransaction} - * @param {string} id - * @returns {Transaction} - */ - async function fetchTransaction(id) { - let rawTransaction; - - try { - ({ result: rawTransaction } = await coreRpcClient.getRawTransaction(id, 1)); - } catch (e) { - // Invalid address or key error - if (e.code === -5) { - return null; - } - - throw e; - } - - return new Transaction(rawTransaction.hex); - } - - return fetchTransaction; -} - -module.exports = fetchTransactionFactory; diff --git a/packages/js-drive/lib/core/getRandomQuorumFactory.js b/packages/js-drive/lib/core/getRandomQuorumFactory.js deleted file mode 100644 index 94af18f98eb..00000000000 --- a/packages/js-drive/lib/core/getRandomQuorumFactory.js +++ /dev/null @@ -1,113 +0,0 @@ -const BufferWriter = require('@dashevo/dashcore-lib/lib/encoding/bufferwriter'); -const Hash = require('@dashevo/dashcore-lib/lib/crypto/hash'); -const { LLMQ_TYPES } = require('@dashevo/dashcore-lib/lib/constants'); -const QuorumsNotFoundError = require('./errors/QuorumsNotFoundError'); -const ValidatorSet = require('../validator/ValidatorSet'); - -const MIN_QUORUM_VALID_MEMBERS = 90; - -const LLMQ_TYPE_TO_NAME = Object - .fromEntries(Object - .entries(LLMQ_TYPES) - .map(([key, value]) => [value, key.toLowerCase().replace('type_', '')])); - -/** - * Calculates scores for validator quorum selection - * it calculates sha256(hash, modifier) per quorumHash - * Please note that this is not a double-sha256 but a single-sha256 - * - * @param {Buffer[]} quorumHashes - * @param {Buffer} modifier - * @return {Object[]} scores - */ -function calculateQuorumHashScores(quorumHashes, modifier) { - return quorumHashes.map((hash) => { - const bufferWriter = new BufferWriter(); - - bufferWriter.write(hash); - bufferWriter.write(modifier); - - return { score: Hash.sha256(bufferWriter.toBuffer()), hash }; - }); -} - -/** - * - * @param {RpcClient} coreRpcClient - * @return {getRandomQuorum} - */ -function getRandomQuorumFactory(coreRpcClient) { - /** - * Gets the current validator set quorum hash for a particular core height - * - * @typedef {getRandomQuorum} - * @param {SimplifiedMNList} sml - * @param {number} quorumType - * @param {Buffer} entropy - the entropy to select the quorum - * @param {number} coreHeight - * @return return {Promise} - the current validator set's quorumHash - */ - async function getRandomQuorum(sml, quorumType, entropy, coreHeight) { - const validatorQuorums = sml.getQuorumsOfType(quorumType); - - if (validatorQuorums.length === 0) { - throw new QuorumsNotFoundError(sml, quorumType); - } - - const { result: allValidatorQuorumsExtendedInfo } = await coreRpcClient.quorum('listextended', coreHeight); - - // convert to object - const validatorQuorumsInfo = allValidatorQuorumsExtendedInfo[LLMQ_TYPE_TO_NAME[quorumType]] - .reduce( - (obj, item) => ({ - ...obj, - ...item, - }), - {}, - ); - - const numberOfQuorums = validatorQuorums.length; - const minTtl = ValidatorSet.ROTATION_BLOCK_INTERVAL * 3; - const dkgInterval = 24; - - // filter quorum by the number of valid members to choose the most vital ones - let filteredValidatorQuorums = validatorQuorums - .filter( - (validatorQuorum) => validatorQuorum.validMembersCount >= MIN_QUORUM_VALID_MEMBERS, - ) - .filter((validatorQuorum) => { - const validatorQuorumInfo = validatorQuorumsInfo[validatorQuorum.quorumHash]; - - if (!validatorQuorumInfo) { - return false; - } - - const quorumRemoveHeight = validatorQuorumInfo.creationHeight - + (dkgInterval * numberOfQuorums); - const howMuchInRest = quorumRemoveHeight - coreHeight; - const quorumTtl = howMuchInRest * 2.5; - - return quorumTtl > minTtl; - }); - - if (filteredValidatorQuorums.length === 0) { - // if there is no "vital" quorums, we choose among others with default min quorum size - filteredValidatorQuorums = validatorQuorums; - } - - const validatorQuorumHashes = filteredValidatorQuorums - .map((quorum) => Buffer.from(quorum.quorumHash, 'hex')); - - const scoredHashes = calculateQuorumHashScores(validatorQuorumHashes, entropy); - - scoredHashes.sort((a, b) => Buffer.compare(a.score, b.score)); - - const quorumHash = scoredHashes[0].hash.toString('hex'); - - return sml.getQuorum(quorumType, quorumHash); - } - - return getRandomQuorum; -} - -module.exports = getRandomQuorumFactory; diff --git a/packages/js-drive/lib/core/updateSimplifiedMasternodeListFactory.js b/packages/js-drive/lib/core/updateSimplifiedMasternodeListFactory.js deleted file mode 100644 index e8f6d16073a..00000000000 --- a/packages/js-drive/lib/core/updateSimplifiedMasternodeListFactory.js +++ /dev/null @@ -1,113 +0,0 @@ -const SimplifiedMNListDiff = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListDiff'); - -const NotEnoughBlocksForValidSMLError = require('./errors/NotEnoughBlocksForValidSMLError'); - -/** - * Check that core is synced (factory) - * - * @param {RpcClient} coreRpcClient - * @param {SimplifiedMasternodeList} simplifiedMasternodeList - * @param {number} smlMaxListsLimit - * @param {string} network - * @param {BaseLogger} logger - * - * @returns {updateSimplifiedMasternodeList} - */ -function updateSimplifiedMasternodeListFactory( - coreRpcClient, - simplifiedMasternodeList, - smlMaxListsLimit, - network, - logger, -) { - // 1 means first block - let latestRequestedHeight = 1; - - /** - * @param {number} fromHeight - * @param {number} toHeight - * @return {Promise} - */ - async function fetchDiffsPerBlock(fromHeight, toHeight) { - const diffs = []; - - for (let height = fromHeight; height < toHeight; height += 1) { - const { result: rawDiff } = await coreRpcClient.protx('diff', height, height + 1, true); - - const diff = new SimplifiedMNListDiff(rawDiff, network); - - diffs.push(diff); - } - - return diffs; - } - - /** - * Check that core is synced - * - * @typedef updateSimplifiedMasternodeList - * @param {number} coreHeight - * @param {Object} [options] - * @param {BaseLogger} [options.logger] - * - * @returns {Promise} - */ - async function updateSimplifiedMasternodeList(coreHeight, options = {}) { - // either use a logger passed or use standard logger - const contextLogger = (options.logger || logger); - - // Should be enough to get 16 diffs - if (coreHeight < smlMaxListsLimit + 1) { - throw new NotEnoughBlocksForValidSMLError(coreHeight); - } - - // When we got more than 16 blocks of difference between last requested height - // and core height, we take only last 16 of them. - if (coreHeight - latestRequestedHeight > smlMaxListsLimit) { - latestRequestedHeight = 1; - simplifiedMasternodeList.reset(); - } - - if (latestRequestedHeight === 1) { - // Initialize SML with 16 diffs to have enough quorum information - // to be able to verify signatures - - const startHeight = coreHeight - smlMaxListsLimit; - - const { result: rawDiff } = await coreRpcClient.protx('diff', latestRequestedHeight, startHeight, true); - - const initialSmlDiffs = [ - new SimplifiedMNListDiff(rawDiff, network), - ...await fetchDiffsPerBlock(startHeight, coreHeight), - ]; - - simplifiedMasternodeList.applyDiffs(initialSmlDiffs); - - latestRequestedHeight = coreHeight; - - contextLogger.debug(`SML is initialized for core heights ${startHeight} to ${coreHeight}`); - - return true; - } - - if (latestRequestedHeight < coreHeight) { - // Update SML - - const smlDiffs = await fetchDiffsPerBlock(latestRequestedHeight, coreHeight); - - simplifiedMasternodeList.applyDiffs(smlDiffs); - - contextLogger.debug(`SML is updated for core heights ${latestRequestedHeight} to ${coreHeight}`); - - latestRequestedHeight = coreHeight; - - return true; - } - - return false; - } - - return updateSimplifiedMasternodeList; -} - -module.exports = updateSimplifiedMasternodeListFactory; diff --git a/packages/js-drive/lib/core/waitForChainLockedHeightFactory.js b/packages/js-drive/lib/core/waitForChainLockedHeightFactory.js deleted file mode 100644 index 8d01c2fdfcc..00000000000 --- a/packages/js-drive/lib/core/waitForChainLockedHeightFactory.js +++ /dev/null @@ -1,49 +0,0 @@ -const MissingChainLockError = require('./errors/MissingChainLockError'); -const LatestCoreChainLock = require('./LatestCoreChainLock'); - -/** - * - * @param {LatestCoreChainLock} latestCoreChainLock - - * @return {waitForChainLockedHeight} - */ -function waitForChainLockedHeightFactory( - latestCoreChainLock, -) { - /** - * @typedef waitForChainLockedHeight - * @param {number} coreHeight - * - * @return {Promise} - */ - async function waitForChainLockedHeight(coreHeight) { - // ChainLock is required to get finalized SML that won't be reorged - const existingChainLock = latestCoreChainLock.getChainLock(); - - if (!existingChainLock) { - throw new MissingChainLockError(); - } - - // Wait for core to be synced up to coreHeight - if (coreHeight > existingChainLock.height) { - await new Promise((resolve) => { - const listener = (chainLock) => { - // Skip if core height still not reached - if (coreHeight > chainLock.height) { - return; - } - - latestCoreChainLock.removeListener(LatestCoreChainLock.EVENTS.update, listener); - - resolve(); - }; - - latestCoreChainLock.on(LatestCoreChainLock.EVENTS.update, listener); - }); - } - } - - return waitForChainLockedHeight; -} - -module.exports = waitForChainLockedHeightFactory; diff --git a/packages/js-drive/lib/core/waitForCoreChainLockSyncFactory.js b/packages/js-drive/lib/core/waitForCoreChainLockSyncFactory.js deleted file mode 100644 index d2f05f26760..00000000000 --- a/packages/js-drive/lib/core/waitForCoreChainLockSyncFactory.js +++ /dev/null @@ -1,103 +0,0 @@ -const { ChainLock } = require('@dashevo/dashcore-lib'); - -const ChainLockSigMessage = require('@dashevo/dashcore-lib/lib/zmqMessages/ChainLockSigMessage'); -const ZMQClient = require('./ZmqClient'); - -const ensureBlock = require('./ensureBlock'); - -/** - * Wait and ensure that core chain lock stays synced (factory) - * - * @param {ZMQClient} coreZMQClient - * @param {RpcClient} coreRpcClient - * @param {LatestCoreChainLock} latestCoreChainLock - * @param {BaseLogger} logger - * - * @returns {waitForCoreSync} - */ -function waitForCoreChainLockSyncFactory( - coreZMQClient, - coreRpcClient, - latestCoreChainLock, - logger, -) { - /** - * Wait and ensure that core chain lock stays synced. - * On new ChainLock received, will also ensure that its block has been processed. - * - * @typedef waitForCoreChainLockSync - * - * @returns {Promise} - */ - async function waitForCoreChainLockSync() { - coreZMQClient.subscribe(ZMQClient.TOPICS.rawchainlocksig); - - let resolveFirstChainLockFromZMQPromise; - const firstChainLockFromZMQPromise = new Promise((resolve) => { - resolveFirstChainLockFromZMQPromise = resolve; - }); - - coreZMQClient.on(ZMQClient.TOPICS.rawchainlocksig, async (rawChainLockMessage) => { - let chainLock; - - try { - ({ chainLock } = new ChainLockSigMessage(rawChainLockMessage)); - } catch (e) { - logger.error( - { - err: e, - rawChainLockMessage: rawChainLockMessage.toString('hex'), - }, - 'Error on creating ChainLockSigMessage', - ); - - return; - } - - latestCoreChainLock.update(chainLock); - - logger.trace( - { - chainLock, - }, - `Updated latestCoreChainLock for core height ${chainLock.height}`, - ); - - if (resolveFirstChainLockFromZMQPromise) { - resolveFirstChainLockFromZMQPromise(); - resolveFirstChainLockFromZMQPromise = null; - } - }); - - // Because a ChainLock may happen before its block, we also subscribe to rawblock - coreZMQClient.subscribe(ZMQClient.TOPICS.hashblock); - - // We need to retrieve latest ChainLock from our fully synced Core instance - let rpcBestChainLockResponse; - try { - rpcBestChainLockResponse = await coreRpcClient.getBestChainLock(); - } catch (e) { - // Unable to find any ChainLock - if (e.code === -32603) { - logger.debug('There are no ChainLocks currently. Waiting for the first one...'); - - // We need to wait for a new ChainLock from ZMQ socket - await firstChainLockFromZMQPromise; - } else { - throw e; - } - } - - if (rpcBestChainLockResponse) { - const chainLock = new ChainLock(rpcBestChainLockResponse.result); - - await ensureBlock(coreZMQClient, coreRpcClient, chainLock.blockHash); - - latestCoreChainLock.update(chainLock); - } - } - - return waitForCoreChainLockSync; -} - -module.exports = waitForCoreChainLockSyncFactory; diff --git a/packages/js-drive/lib/core/waitForCoreSyncFactory.js b/packages/js-drive/lib/core/waitForCoreSyncFactory.js deleted file mode 100644 index 9a4b612101a..00000000000 --- a/packages/js-drive/lib/core/waitForCoreSyncFactory.js +++ /dev/null @@ -1,47 +0,0 @@ -const wait = require('../util/wait'); - -/** - * Check that core is synced (factory) - * - * @param {RpcClient} coreRpcClient - * - * @returns {waitForCoreSync} - */ -function waitForCoreSyncFactory(coreRpcClient) { - /** - * Check that core is synced - * - * @typedef waitForCoreSync - * - * @param {function(number, number)} progressCallback - * - * @returns {Promise} - */ - async function waitForCoreSync(progressCallback) { - let isBlockchainSynced = false; - while (!isBlockchainSynced) { - ({ - result: { - IsBlockchainSynced: isBlockchainSynced, - }, - } = await coreRpcClient.mnsync('status')); - - if (!isBlockchainSynced) { - const { - result: { - blocks: currentBlockHeight, - headers: currentHeadersNumber, - }, - } = await coreRpcClient.getBlockchainInfo(); - - progressCallback(currentBlockHeight, currentHeadersNumber); - - await wait(10000); - } - } - } - - return waitForCoreSync; -} - -module.exports = waitForCoreSyncFactory; diff --git a/packages/js-drive/lib/createDIContainer.js b/packages/js-drive/lib/createDIContainer.js deleted file mode 100644 index d87029bb822..00000000000 --- a/packages/js-drive/lib/createDIContainer.js +++ /dev/null @@ -1,894 +0,0 @@ -const { - createContainer: createAwilixContainer, - InjectionMode, - asClass, - asFunction, - asValue, -} = require('awilix'); - -const fs = require('fs'); - -const { AsyncLocalStorage } = require('node:async_hooks'); - -const Long = require('long'); - -const RSDrive = require('@dashevo/rs-drive'); - -const RpcClient = require('@dashevo/dashd-rpc/promise'); - -const { PublicKey } = require('@dashevo/dashcore-lib'); - -const DashPlatformProtocol = require('@dashevo/dpp'); - -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); - -const findMyWay = require('find-my-way'); - -const pino = require('pino'); -const pinoMultistream = require('pino-multi-stream'); - -const createABCIServer = require('@dashevo/abci'); - -const protocolVersion = require('@dashevo/dpp/lib/version/protocolVersion'); - -const calculateOperationFees = require('@dashevo/dpp/lib/stateTransition/fee/calculateOperationFees'); -const calculateStateTransitionFeeFactory = require('@dashevo/dpp/lib/stateTransition/fee/calculateStateTransitionFeeFactory'); - -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); -const featureFlagsSystemIds = require('@dashevo/feature-flags-contract/lib/systemIds'); - -const featureFlagsDocuments = require('@dashevo/feature-flags-contract/schema/feature-flags-documents.json'); -const dpnsSystemIds = require('@dashevo/dpns-contract/lib/systemIds'); - -const dpnsDocuments = require('@dashevo/dpns-contract/schema/dpns-contract-documents.json'); -const masternodeRewardsSystemIds = require('@dashevo/masternode-reward-shares-contract/lib/systemIds'); - -const masternodeRewardsDocuments = require('@dashevo/masternode-reward-shares-contract/schema/masternode-reward-shares-documents.json'); -const dashpaySystemIds = require('@dashevo/dashpay-contract/lib/systemIds'); - -const dashpayDocuments = require('@dashevo/dashpay-contract/schema/dashpay.schema.json'); - -const withdrawalsSystemIds = require('@dashevo/withdrawals-contract/lib/systemIds'); -const withdrawalsDocuments = require('@dashevo/withdrawals-contract/schema/withdrawals-documents.json'); -const calculateStateTransitionFeeFromOperationsFactory = require('@dashevo/dpp/lib/stateTransition/fee/calculateStateTransitionFeeFromOperationsFactory'); - -const packageJSON = require('../package.json'); - -const ZMQClient = require('./core/ZmqClient'); - -const sanitizeUrl = require('./util/sanitizeUrl'); -const LatestCoreChainLock = require('./core/LatestCoreChainLock'); - -const GroveDBStore = require('./storage/GroveDBStore'); - -const IdentityStoreRepository = require('./identity/IdentityStoreRepository'); - -const IdentityPublicKeyStoreRepository = require( - './identity/IdentityPublicKeyStoreRepository', -); -const DataContractStoreRepository = require('./dataContract/DataContractStoreRepository'); -const fetchDocumentsFactory = require('./document/fetchDocumentsFactory'); -const proveDocumentsFactory = require('./document/proveDocumentsFactory'); - -const fetchDataContractFactory = require('./document/fetchDataContractFactory'); -const BlockExecutionContext = require('./blockExecution/BlockExecutionContext'); - -const unserializeStateTransitionFactory = require( - './abci/handlers/stateTransition/unserializeStateTransitionFactory', -); -const DriveStateRepository = require('./dpp/DriveStateRepository'); -const CachedStateRepositoryDecorator = require('./dpp/CachedStateRepositoryDecorator'); -const LoggedStateRepositoryDecorator = require('./dpp/LoggedStateRepositoryDecorator'); -const dataContractQueryHandlerFactory = require('./abci/handlers/query/dataContractQueryHandlerFactory'); -const identityQueryHandlerFactory = require('./abci/handlers/query/identityQueryHandlerFactory'); - -const documentQueryHandlerFactory = require('./abci/handlers/query/documentQueryHandlerFactory'); - -const identitiesByPublicKeyHashesQueryHandlerFactory = require('./abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory'); -const getProofsQueryHandlerFactory = require('./abci/handlers/query/getProofsQueryHandlerFactory'); -const wrapInErrorHandlerFactory = require('./abci/errors/wrapInErrorHandlerFactory'); -const errorHandlerFactory = require('./errorHandlerFactory'); -const checkTxHandlerFactory = require('./abci/handlers/checkTxHandlerFactory'); -const initChainHandlerFactory = require('./abci/handlers/initChainHandlerFactory'); -const infoHandlerFactory = require('./abci/handlers/infoHandlerFactory'); -const extendVoteHandlerFactory = require('./abci/handlers/extendVoteHandlerFactory'); -const finalizeBlockHandlerFactory = require('./abci/handlers/finalizeBlockHandlerFactory'); -const prepareProposalHandlerFactory = require('./abci/handlers/prepareProposalHandlerFactory'); - -const processProposalHandlerFactory = require('./abci/handlers/processProposalHandlerFactory'); -const verifyVoteExtensionHandlerFactory = require('./abci/handlers/verifyVoteExtensionHandlerFactory'); -const beginBlockFactory = require('./abci/handlers/proposal/beginBlockFactory'); -const deliverTxFactory = require('./abci/handlers/proposal/deliverTxFactory'); -const endBlockFactory = require('./abci/handlers/proposal/endBlockFactory'); -const rotateAndCreateValidatorSetUpdateFactory = require('./abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory'); -const createConsensusParamUpdateFactory = require('./abci/handlers/proposal/createConsensusParamUpdateFactory'); - -const createCoreChainLockUpdateFactory = require('./abci/handlers/proposal/createCoreChainLockUpdateFactory'); -const verifyChainLockFactory = require('./abci/handlers/proposal/verifyChainLockFactory'); -const queryHandlerFactory = require('./abci/handlers/queryHandlerFactory'); -const waitForCoreSyncFactory = require('./core/waitForCoreSyncFactory'); -const waitForCoreChainLockSyncFactory = require('./core/waitForCoreChainLockSyncFactory'); -const updateSimplifiedMasternodeListFactory = require('./core/updateSimplifiedMasternodeListFactory'); - -const waitForChainLockedHeightFactory = require('./core/waitForChainLockedHeightFactory'); -const SimplifiedMasternodeList = require('./core/SimplifiedMasternodeList'); -const SpentAssetLockTransactionsRepository = require('./identity/SpentAssetLockTransactionsRepository'); -const enrichErrorWithConsensusErrorFactory = require('./abci/errors/enrichErrorWithContextLoggerFactory'); -const closeAbciServerFactory = require('./abci/closeAbciServerFactory'); -const getLatestFeatureFlagFactory = require('./featureFlag/getLatestFeatureFlagFactory'); -const getFeatureFlagForHeightFactory = require('./featureFlag/getFeatureFlagForHeightFactory'); -const ValidatorSet = require('./validator/ValidatorSet'); -const createValidatorSetUpdate = require('./abci/handlers/validator/createValidatorSetUpdate'); -const fetchQuorumMembersFactory = require('./core/fetchQuorumMembersFactory'); -const getRandomQuorumFactory = require('./core/getRandomQuorumFactory'); - -const createQueryResponseFactory = require('./abci/handlers/query/response/createQueryResponseFactory'); -const BlockExecutionContextRepository = require('./blockExecution/BlockExecutionContextRepository'); -const synchronizeMasternodeIdentitiesFactory = require('./identity/masternode/synchronizeMasternodeIdentitiesFactory'); -const createMasternodeIdentityFactory = require('./identity/masternode/createMasternodeIdentityFactory'); -const handleNewMasternodeFactory = require('./identity/masternode/handleNewMasternodeFactory'); -const handleUpdatedPubKeyOperatorFactory = require('./identity/masternode/handleUpdatedPubKeyOperatorFactory'); -const handleUpdatedVotingAddressFactory = require('./identity/masternode/handleUpdatedVotingAddressFactory'); -const createRewardShareDocumentFactory = require('./identity/masternode/createRewardShareDocumentFactory'); -const handleRemovedMasternodeFactory = require('./identity/masternode/handleRemovedMasternodeFactory'); -const handleUpdatedScriptPayoutFactory = require('./identity/masternode/handleUpdatedScriptPayoutFactory'); - -const getWithdrawPubKeyTypeFromPayoutScriptFactory = require('./identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory'); -const getPublicKeyFromPayoutScript = require('./identity/masternode/getPublicKeyFromPayoutScript'); -const updateWithdrawalTransactionIdAndStatusFactory = require('./identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory'); -const broadcastWithdrawalTransactionsFactory = require('./abci/handlers/proposal/broadcastWithdrawalTransactionsFactory'); - -const DocumentRepository = require('./document/DocumentRepository'); -const ExecutionTimer = require('./util/ExecutionTimer'); -const noopLoggerInstance = require('./util/noopLogger'); -const fetchTransactionFactory = require('./core/fetchTransactionFactory'); -const LastSyncedCoreHeightRepository = require('./identity/masternode/LastSyncedCoreHeightRepository'); -const fetchSimplifiedMNListFactory = require('./core/fetchSimplifiedMNListFactory'); -const processProposalFactory = require('./abci/handlers/proposal/processProposalFactory'); -const createContextLoggerFactory = require('./abci/errors/createContextLoggerFactory'); -const IdentityBalanceStoreRepository = require('./identity/IdentityBalanceStoreRepository'); - -/** - * - * @param {Object} options - * @param {string} options.ABCI_HOST - * @param {string} options.ABCI_PORT - * @param {string} options.DB_PATH - * @param {string} options.GROVEDB_LATEST_FILE - * @param {string} options.DATA_CONTRACTS_GLOBAL_CACHE_SIZE - * @param {string} options.DATA_CONTRACTS_BLOCK_CACHE_SIZE - * @param {string} options.CORE_JSON_RPC_HOST - * @param {string} options.CORE_JSON_RPC_PORT - * @param {string} options.CORE_JSON_RPC_USERNAME - * @param {string} options.CORE_JSON_RPC_PASSWORD - * @param {string} options.CORE_ZMQ_HOST - * @param {string} options.CORE_ZMQ_PORT - * @param {string} options.CORE_ZMQ_CONNECTION_RETRIES - * @param {string} options.NETWORK - * @param {string} options.DPNS_MASTER_PUBLIC_KEY - * @param {string} options.DPNS_SECOND_PUBLIC_KEY - * @param {string} options.DASHPAY_MASTER_PUBLIC_KEY - * @param {string} options.DASHPAY_SECOND_PUBLIC_KEY - * @param {string} options.FEATURE_FLAGS_MASTER_PUBLIC_KEY - * @param {string} options.FEATURE_FLAGS_SECOND_PUBLIC_KEY - * @param {string} options.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY - * @param {string} options.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY - * @param {string} options.WITHDRAWALS_MASTER_PUBLIC_KEY - * @param {string} options.WITHDRAWALS_SECOND_PUBLIC_KEY - * @param {string} options.INITIAL_CORE_CHAINLOCKED_HEIGHT - * @param {string} options.VALIDATOR_SET_LLMQ_TYPE - * @param {string} options.TENDERDASH_P2P_PORT - * @param {string} options.LOG_STDOUT_LEVEL - * @param {string} options.LOG_PRETTY_FILE_LEVEL - * @param {string} options.LOG_PRETTY_FILE_PATH - * @param {string} options.LOG_JSON_FILE_LEVEL - * @param {string} options.LOG_JSON_FILE_PATH - * @param {string} options.LOG_STATE_REPOSITORY - * @param {string} options.NODE_ENV - * - * @return {AwilixContainer} - */ -function createDIContainer(options) { - if (!options.DPNS_MASTER_PUBLIC_KEY) { - throw new Error('DPNS_MASTER_PUBLIC_KEY must be set'); - } - if (!options.DPNS_SECOND_PUBLIC_KEY) { - throw new Error('DPNS_SECOND_PUBLIC_KEY must be set'); - } - - if (!options.DASHPAY_MASTER_PUBLIC_KEY) { - throw new Error('DASHPAY_MASTER_PUBLIC_KEY must be set'); - } - - if (!options.DASHPAY_SECOND_PUBLIC_KEY) { - throw new Error('DASHPAY_SECOND_PUBLIC_KEY must be set'); - } - - if (!options.FEATURE_FLAGS_MASTER_PUBLIC_KEY) { - throw new Error('FEATURE_FLAGS_MASTER_PUBLIC_KEY must be set'); - } - - if (!options.FEATURE_FLAGS_SECOND_PUBLIC_KEY) { - throw new Error('FEATURE_FLAGS_SECOND_PUBLIC_KEY must be set'); - } - - if (!options.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY) { - throw new Error('MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY must be set'); - } - - if (!options.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY) { - throw new Error('MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY must be set'); - } - - if (!options.WITHDRAWALS_MASTER_PUBLIC_KEY) { - throw new Error('WITHDRAWALS_MASTER_PUBLIC_KEY must be set'); - } - - if (!options.WITHDRAWALS_SECOND_PUBLIC_KEY) { - throw new Error('WITHDRAWALS_SECOND_PUBLIC_KEY must be set'); - } - - const container = createAwilixContainer({ - injectionMode: InjectionMode.CLASSIC, - }); - - /** - * Register itself (usually to solve recursive dependencies) - */ - container.register({ - container: asValue(container), - }); - - /** - * Register latest protocol version - * Define highest supported protocol version - */ - container.register({ - latestProtocolVersion: asValue(Long.fromInt(protocolVersion.latestVersion)), - }); - - /** - * Register environment variables - */ - container.register({ - abciHost: asValue(options.ABCI_HOST), - abciPort: asValue(options.ABCI_PORT), - - dbPath: asValue(options.DB_PATH), - - groveDBLatestFile: asValue(options.GROVEDB_LATEST_FILE), - - dataContractsGlobalCacheSize: asValue( - parseInt(options.DATA_CONTRACTS_GLOBAL_CACHE_SIZE, 10), - ), - dataContractsBlockCacheSize: asValue( - parseInt(options.DATA_CONTRACTS_BLOCK_CACHE_SIZE, 10), - ), - - coreJsonRpcHost: asValue(options.CORE_JSON_RPC_HOST), - coreJsonRpcPort: asValue(options.CORE_JSON_RPC_PORT), - coreJsonRpcUsername: asValue(options.CORE_JSON_RPC_USERNAME), - coreJsonRpcPassword: asValue(options.CORE_JSON_RPC_PASSWORD), - coreZMQHost: asValue(options.CORE_ZMQ_HOST), - coreZMQPort: asValue(options.CORE_ZMQ_PORT), - coreZMQConnectionRetries: asValue( - parseInt(options.CORE_ZMQ_CONNECTION_RETRIES, 10), - ), - network: asValue(options.NETWORK), - logStdoutLevel: asValue(options.LOG_STDOUT_LEVEL), - logPrettyFileLevel: asValue(options.LOG_PRETTY_FILE_LEVEL), - logPrettyFilePath: asValue(options.LOG_PRETTY_FILE_PATH), - logJsonFileLevel: asValue(options.LOG_JSON_FILE_LEVEL), - logJsonFilePath: asValue(options.LOG_JSON_FILE_PATH), - logStateRepository: asValue(options.LOG_STATE_REPOSITORY === 'true'), - isProductionEnvironment: asValue(options.NODE_ENV === 'production'), - maxIdentitiesPerRequest: asValue(25), - smlMaxListsLimit: asValue(16), - initialCoreChainLockedHeight: asValue( - parseInt(options.INITIAL_CORE_CHAINLOCKED_HEIGHT, 10), - ), - validatorSetLLMQType: asValue( - parseInt(options.VALIDATOR_SET_LLMQ_TYPE, 10), - ), - masternodeRewardSharesContractId: asValue( - Identifier.from(masternodeRewardsSystemIds.contractId), - ), - masternodeRewardSharesOwnerId: asValue( - Identifier.from(masternodeRewardsSystemIds.ownerId), - ), - masternodeRewardSharesOwnerMasterPublicKey: asValue( - PublicKey.fromString( - options.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY, - ), - ), - masternodeRewardSharesOwnerSecondPublicKey: asValue( - PublicKey.fromString( - options.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY, - ), - ), - masternodeRewardSharesDocuments: asValue( - masternodeRewardsDocuments, - ), - featureFlagsContractId: asValue( - Identifier.from(featureFlagsSystemIds.contractId), - ), - featureFlagsOwnerId: asValue( - Identifier.from(featureFlagsSystemIds.ownerId), - ), - featureFlagsOwnerMasterPublicKey: asValue( - PublicKey.fromString( - options.FEATURE_FLAGS_MASTER_PUBLIC_KEY, - ), - ), - featureFlagsOwnerSecondPublicKey: asValue( - PublicKey.fromString( - options.FEATURE_FLAGS_SECOND_PUBLIC_KEY, - ), - ), - featureFlagsDocuments: asValue(featureFlagsDocuments), - dpnsContractId: asValue(Identifier.from(dpnsSystemIds.contractId)), - dpnsOwnerId: asValue(Identifier.from(dpnsSystemIds.ownerId)), - dpnsOwnerMasterPublicKey: asValue( - PublicKey.fromString( - options.DPNS_MASTER_PUBLIC_KEY, - ), - ), - dpnsOwnerSecondPublicKey: asValue( - PublicKey.fromString( - options.DPNS_SECOND_PUBLIC_KEY, - ), - ), - dpnsDocuments: asValue(dpnsDocuments), - dashpayContractId: asValue(Identifier.from(dashpaySystemIds.contractId)), - dashpayOwnerId: asValue(Identifier.from(dashpaySystemIds.ownerId)), - dashpayOwnerMasterPublicKey: asValue( - PublicKey.fromString( - options.DASHPAY_MASTER_PUBLIC_KEY, - ), - ), - dashpayOwnerSecondPublicKey: asValue( - PublicKey.fromString( - options.DASHPAY_SECOND_PUBLIC_KEY, - ), - ), - dashpayDocuments: asValue(dashpayDocuments), - withdrawalsContractId: asValue(Identifier.from(withdrawalsSystemIds.contractId)), - withdrawalsOwnerId: asValue(Identifier.from(withdrawalsSystemIds.ownerId)), - withdrawalsOwnerMasterPublicKey: asValue( - PublicKey.fromString( - options.WITHDRAWALS_MASTER_PUBLIC_KEY, - ), - ), - withdrawalsOwnerSecondPublicKey: asValue( - PublicKey.fromString( - options.WITHDRAWALS_SECOND_PUBLIC_KEY, - ), - ), - withdrawalsDocuments: asValue(withdrawalsDocuments), - tenderdashP2pPort: asValue(options.TENDERDASH_P2P_PORT), - }); - - /** - * Register global DPP options - */ - container.register({ - dppOptions: asValue({}), - }); - - /** - * Register Core related - */ - container.register({ - latestCoreChainLock: asValue(new LatestCoreChainLock()), - simplifiedMasternodeList: asClass(SimplifiedMasternodeList).proxy().singleton(), - fetchQuorumMembers: asFunction(fetchQuorumMembersFactory), - fetchSimplifiedMNList: asFunction(fetchSimplifiedMNListFactory), - getRandomQuorum: asFunction(getRandomQuorumFactory), - coreZMQClient: asFunction(( - coreZMQHost, - coreZMQPort, - coreZMQConnectionRetries, - ) => ( - new ZMQClient(coreZMQHost, coreZMQPort, { - maxRetryCount: coreZMQConnectionRetries, - }) - )).singleton(), - - coreRpcClient: asFunction(( - coreJsonRpcHost, - coreJsonRpcPort, - coreJsonRpcUsername, - coreJsonRpcPassword, - ) => ( - new RpcClient({ - protocol: 'http', - host: coreJsonRpcHost, - port: coreJsonRpcPort, - user: coreJsonRpcUsername, - pass: coreJsonRpcPassword, - }) - )).singleton(), - }); - - /** - * Register common services - */ - container.register({ - loggerPrettyfierOptions: asValue({ - translateTime: true, - }), - - logStdoutStream: asFunction((loggerPrettyfierOptions) => pinoMultistream.prettyStream({ - prettyPrint: loggerPrettyfierOptions, - })).singleton(), - - logPrettyFileStream: asFunction(( - logPrettyFilePath, - loggerPrettyfierOptions, - ) => pinoMultistream.prettyStream({ - prettyPrint: loggerPrettyfierOptions, - dest: fs.createWriteStream(logPrettyFilePath, { flags: 'a' }), - })).singleton(), - - logJsonFileStream: asFunction((logJsonFilePath) => fs.createWriteStream(logJsonFilePath, { flags: 'a' })) - .disposer(async (stream) => new Promise((resolve) => stream.end(resolve))).singleton(), - - loggerStreams: asFunction(( - logStdoutLevel, - logStdoutStream, - logPrettyFileLevel, - logPrettyFileStream, - logJsonFileLevel, - logJsonFileStream, - ) => [ - { - level: logStdoutLevel, - stream: logStdoutStream, - }, - { - level: logPrettyFileLevel, - stream: logPrettyFileStream, - }, - { - level: logJsonFileLevel, - stream: logJsonFileStream, - }, - ]), - - logger: asFunction( - (loggerStreams) => pino({ - level: 'trace', - }, pinoMultistream.multistream(loggerStreams)) - .child({ driveVersion: packageJSON.version }), - ).singleton(), - - noopLogger: asValue(noopLoggerInstance), - - sanitizeUrl: asValue(sanitizeUrl), - - executionTimer: asClass(ExecutionTimer).singleton(), - }); - - /** - * RS Drive and GroveDB - */ - - container.register({ - rsDrive: asFunction(( - groveDBLatestFile, - dataContractsGlobalCacheSize, - dataContractsBlockCacheSize, - coreJsonRpcHost, - coreJsonRpcPort, - coreJsonRpcUsername, - coreJsonRpcPassword, - ) => new RSDrive(groveDBLatestFile, { - drive: { - dataContractsGlobalCacheSize, - dataContractsBlockCacheSize, - }, - core: { - rpc: { - url: `${coreJsonRpcHost}:${coreJsonRpcPort}`, - username: coreJsonRpcUsername, - password: coreJsonRpcPassword, - }, - }, - })) - .disposer(async (rsDrive) => { - // Flush data on disk - await rsDrive.getGroveDB().flush(); - - await rsDrive.close(); - - if (process.env.NODE_ENV === 'test') { - fs.rmSync(options.GROVEDB_LATEST_FILE, { recursive: true }); - } - }).singleton(), - - groveDB: asFunction((rsDrive) => rsDrive.getGroveDB()).singleton(), - - rsAbci: asFunction((rsDrive) => rsDrive.getAbci()).singleton(), - - groveDBStore: asFunction((rsDrive) => new GroveDBStore(rsDrive)).singleton(), - }); - - /** - * Register Identity - */ - container.register({ - identityRepository: asClass(IdentityStoreRepository).singleton(), - - identityBalanceRepository: asClass(IdentityBalanceStoreRepository).singleton(), - - identityPublicKeyRepository: asClass(IdentityPublicKeyStoreRepository).singleton(), - - synchronizeMasternodeIdentities: asFunction(synchronizeMasternodeIdentitiesFactory).singleton(), - - lastSyncedCoreHeightRepository: asClass(LastSyncedCoreHeightRepository).singleton(), - - createMasternodeIdentity: asFunction(createMasternodeIdentityFactory).singleton(), - - createRewardShareDocument: asFunction(createRewardShareDocumentFactory).singleton(), - - handleNewMasternode: asFunction(handleNewMasternodeFactory).singleton(), - - handleUpdatedPubKeyOperator: asFunction(handleUpdatedPubKeyOperatorFactory).singleton(), - - handleUpdatedVotingAddress: asFunction(handleUpdatedVotingAddressFactory).singleton(), - - handleRemovedMasternode: asFunction(handleRemovedMasternodeFactory).singleton(), - - handleUpdatedScriptPayout: asFunction(handleUpdatedScriptPayoutFactory).singleton(), - - getWithdrawPubKeyTypeFromPayoutScript: asFunction(getWithdrawPubKeyTypeFromPayoutScriptFactory) - .singleton(), - - getPublicKeyFromPayoutScript: asValue(getPublicKeyFromPayoutScript), - - systemIdentityPublicKeys: asFunction(( - masternodeRewardSharesOwnerMasterPublicKey, - masternodeRewardSharesOwnerSecondPublicKey, - featureFlagsOwnerMasterPublicKey, - featureFlagsOwnerSecondPublicKey, - dpnsOwnerMasterPublicKey, - dpnsOwnerSecondPublicKey, - dashpayOwnerMasterPublicKey, - dashpayOwnerSecondPublicKey, - withdrawalsOwnerMasterPublicKey, - withdrawalsOwnerSecondPublicKey, - ) => ({ - masternodeRewardSharesContractOwner: { - master: masternodeRewardSharesOwnerMasterPublicKey.toBuffer(), - high: masternodeRewardSharesOwnerSecondPublicKey.toBuffer(), - }, - featureFlagsContractOwner: { - master: featureFlagsOwnerMasterPublicKey.toBuffer(), - high: featureFlagsOwnerSecondPublicKey.toBuffer(), - }, - dpnsContractOwner: { - master: dpnsOwnerMasterPublicKey.toBuffer(), - high: dpnsOwnerSecondPublicKey.toBuffer(), - }, - withdrawalsContractOwner: { - master: dashpayOwnerMasterPublicKey.toBuffer(), - high: dashpayOwnerSecondPublicKey.toBuffer(), - }, - dashpayContractOwner: { - master: withdrawalsOwnerMasterPublicKey.toBuffer(), - high: withdrawalsOwnerSecondPublicKey.toBuffer(), - }, - })), - }); - - /** - * Register asset lock transactions - */ - container.register({ - spentAssetLockTransactionsRepository: asClass(SpentAssetLockTransactionsRepository).singleton(), - }); - - /** - * Register Data Contract - */ - container.register({ - dataContractRepository: asFunction(( - groveDBStore, - decodeProtocolEntity, - ) => new DataContractStoreRepository(groveDBStore, decodeProtocolEntity)).singleton(), - }); - - /** - * Register Document - */ - container.register({ - documentRepository: asFunction(( - groveDBStore, - ) => new DocumentRepository(groveDBStore)).singleton(), - - fetchDocuments: asFunction(fetchDocumentsFactory).singleton(), - fetchDataContract: asFunction(fetchDataContractFactory).singleton(), - proveDocuments: asFunction(proveDocumentsFactory).singleton(), - }); - - /** - * Register block execution context - */ - container.register({ - latestBlockExecutionContext: asClass(BlockExecutionContext).singleton(), - proposalBlockExecutionContext: asClass(BlockExecutionContext).singleton(), - blockExecutionContextRepository: asClass(BlockExecutionContextRepository).singleton(), - }); - - /** - * Register DPP - */ - container.register({ - decodeProtocolEntity: asFunction(decodeProtocolEntityFactory), - - calculateOperationFees: asValue(calculateOperationFees), - - calculateStateTransitionFeeFromOperations: - asFunction(calculateStateTransitionFeeFromOperationsFactory), - - calculateStateTransitionFee: asFunction(calculateStateTransitionFeeFactory), - - stateRepository: asFunction(( - identityRepository, - identityBalanceRepository, - identityPublicKeyRepository, - dataContractRepository, - fetchDocuments, - documentRepository, - spentAssetLockTransactionsRepository, - coreRpcClient, - latestBlockExecutionContext, - simplifiedMasternodeList, - rsDrive, - ) => { - const stateRepository = new DriveStateRepository( - identityRepository, - identityBalanceRepository, - identityPublicKeyRepository, - dataContractRepository, - fetchDocuments, - documentRepository, - spentAssetLockTransactionsRepository, - coreRpcClient, - latestBlockExecutionContext, - simplifiedMasternodeList, - rsDrive, - ); - - return new CachedStateRepositoryDecorator( - stateRepository, - ); - }).singleton(), - - transactionalStateRepository: asFunction(( - identityRepository, - identityBalanceRepository, - identityPublicKeyRepository, - dataContractRepository, - fetchDocuments, - documentRepository, - spentAssetLockTransactionsRepository, - coreRpcClient, - proposalBlockExecutionContext, - simplifiedMasternodeList, - logStateRepository, - rsDrive, - ) => { - const stateRepository = new DriveStateRepository( - identityRepository, - identityBalanceRepository, - identityPublicKeyRepository, - dataContractRepository, - fetchDocuments, - documentRepository, - spentAssetLockTransactionsRepository, - coreRpcClient, - proposalBlockExecutionContext, - simplifiedMasternodeList, - rsDrive, - { - useTransaction: true, - }, - ); - - const cachedRepository = new CachedStateRepositoryDecorator( - stateRepository, - ); - - if (!logStateRepository) { - return cachedRepository; - } - - return new LoggedStateRepositoryDecorator( - cachedRepository, - proposalBlockExecutionContext, - ); - }).singleton(), - - unserializeStateTransition: asFunction(( - dpp, - noopLogger, - ) => unserializeStateTransitionFactory(dpp, noopLogger)).singleton(), - - transactionalUnserializeStateTransition: asFunction(( - transactionalDpp, - noopLogger, - ) => unserializeStateTransitionFactory(transactionalDpp, noopLogger)).singleton(), - - dpp: asFunction((stateRepository, dppOptions) => ( - new DashPlatformProtocol({ - ...dppOptions, - stateRepository, - }) - )).singleton(), - - transactionalDpp: asFunction((transactionalStateRepository, dppOptions) => ( - new DashPlatformProtocol({ - ...dppOptions, - stateRepository: transactionalStateRepository, - }) - )).singleton(), - }); - - /** - * Register validator quorums - */ - container.register({ - validatorSet: asClass(ValidatorSet), - }); - - /** - * Register withrawals stuff - */ - container.register({ - updateWithdrawalTransactionIdAndStatus: asFunction( - updateWithdrawalTransactionIdAndStatusFactory, - ), - broadcastWithdrawalTransactions: asFunction(broadcastWithdrawalTransactionsFactory), - }); - - /** - * Register feature flags stuff - */ - container.register({ - getLatestFeatureFlag: asFunction(getLatestFeatureFlagFactory), - getFeatureFlagForHeight: asFunction(getFeatureFlagForHeightFactory), - }); - - /** - * Register Core stuff - */ - container.register({ - waitForCoreSync: asFunction(waitForCoreSyncFactory).singleton(), - - updateSimplifiedMasternodeList: asFunction(updateSimplifiedMasternodeListFactory).singleton(), - - waitForChainLockedHeight: asFunction(waitForChainLockedHeightFactory).singleton(), - - waitForCoreChainLockSync: asFunction(waitForCoreChainLockSyncFactory).singleton(), - - fetchTransaction: asFunction(fetchTransactionFactory).singleton(), - }); - - /** - * Register ABCI handlers - */ - container.register({ - createContextLogger: asFunction(createContextLoggerFactory), - abciAsyncLocalStorage: asValue(new AsyncLocalStorage()), - createQueryResponse: asFunction(createQueryResponseFactory).singleton(), - createValidatorSetUpdate: asValue(createValidatorSetUpdate), - identityQueryHandler: asFunction(identityQueryHandlerFactory).singleton(), - dataContractQueryHandler: asFunction(dataContractQueryHandlerFactory).singleton(), - documentQueryHandler: asFunction(documentQueryHandlerFactory).singleton(), - getProofsQueryHandler: asFunction(getProofsQueryHandlerFactory).singleton(), - identitiesByPublicKeyHashesQueryHandler: - asFunction(identitiesByPublicKeyHashesQueryHandlerFactory).singleton(), - - queryHandlerRouter: asFunction(( - identityQueryHandler, - dataContractQueryHandler, - documentQueryHandler, - identitiesByPublicKeyHashesQueryHandler, - getProofsQueryHandler, - ) => { - const router = findMyWay({ - ignoreTrailingSlash: true, - }); - - router.on('GET', '/identities', identityQueryHandler); - router.on('GET', '/dataContracts', dataContractQueryHandler); - router.on('GET', '/dataContracts/documents', documentQueryHandler); - router.on('GET', '/proofs', getProofsQueryHandler); - router.on('GET', '/identities/by-public-key-hash', identitiesByPublicKeyHashesQueryHandler); - - return router; - }).singleton(), - - beginBlock: asFunction(beginBlockFactory).singleton(), - - processProposal: asFunction(processProposalFactory), - - deliverTx: asFunction(deliverTxFactory).singleton(), - - wrappedDeliverTx: asFunction(( - wrapInErrorHandler, - enrichErrorWithContextError, - deliverTx, - ) => wrapInErrorHandler( - enrichErrorWithContextError(deliverTx), - )).singleton(), - - endBlock: asFunction(endBlockFactory).singleton(), - - verifyChainLock: asFunction(verifyChainLockFactory).singleton(), - - rotateAndCreateValidatorSetUpdate: asFunction( - rotateAndCreateValidatorSetUpdateFactory, - ).singleton(), - - createConsensusParamUpdate: asFunction(createConsensusParamUpdateFactory).singleton(), - - createCoreChainLockUpdate: asFunction(createCoreChainLockUpdateFactory).singleton(), - - infoHandler: asFunction(infoHandlerFactory).singleton(), - - checkTxHandler: asFunction(checkTxHandlerFactory).singleton(), - - initChainHandler: asFunction(initChainHandlerFactory).singleton(), - - queryHandler: asFunction(queryHandlerFactory).singleton(), - - extendVoteHandler: asFunction(extendVoteHandlerFactory).singleton(), - - finalizeBlockHandler: asFunction(finalizeBlockHandlerFactory).singleton(), - - prepareProposalHandler: asFunction(prepareProposalHandlerFactory).singleton(), - - processProposalHandler: asFunction(processProposalHandlerFactory).singleton(), - - verifyVoteExtensionHandler: asFunction(verifyVoteExtensionHandlerFactory).singleton(), - - wrapInErrorHandler: asFunction(wrapInErrorHandlerFactory).singleton(), - enrichErrorWithContextError: asFunction(enrichErrorWithConsensusErrorFactory).singleton(), - errorHandler: asFunction(errorHandlerFactory).singleton(), - - abciHandlers: asFunction(( - infoHandler, - checkTxHandler, - initChainHandler, - wrapInErrorHandler, - enrichErrorWithContextError, - queryHandler, - extendVoteHandler, - finalizeBlockHandler, - prepareProposalHandler, - processProposalHandler, - verifyVoteExtensionHandler, - ) => ({ - info: enrichErrorWithContextError(infoHandler), - checkTx: wrapInErrorHandler(enrichErrorWithContextError(checkTxHandler)), - initChain: enrichErrorWithContextError(initChainHandler), - query: wrapInErrorHandler(enrichErrorWithContextError(queryHandler)), - extendVote: enrichErrorWithContextError(extendVoteHandler), - finalizeBlock: enrichErrorWithContextError(finalizeBlockHandler), - prepareProposal: enrichErrorWithContextError(prepareProposalHandler), - processProposal: enrichErrorWithContextError(processProposalHandler), - verifyVoteExtension: enrichErrorWithContextError(verifyVoteExtensionHandler), - })).singleton(), - - closeAbciServer: asFunction(closeAbciServerFactory).singleton(), - - abciServer: asFunction((abciHandlers) => createABCIServer(abciHandlers)) - .singleton(), - }); - - return container; -} - -module.exports = createDIContainer; diff --git a/packages/js-drive/lib/dataContract/DataContractStoreRepository.js b/packages/js-drive/lib/dataContract/DataContractStoreRepository.js deleted file mode 100644 index 0b8c33925d5..00000000000 --- a/packages/js-drive/lib/dataContract/DataContractStoreRepository.js +++ /dev/null @@ -1,181 +0,0 @@ -const { createHash } = require('crypto'); - -const PreCalculatedOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/PreCalculatedOperation'); -const StorageResult = require('../storage/StorageResult'); - -class DataContractStoreRepository { - /** - * - * @param {GroveDBStore} groveDBStore - * @param {decodeProtocolEntity} decodeProtocolEntity - * @param {BaseLogger} [logger] - */ - constructor(groveDBStore, decodeProtocolEntity, logger = undefined) { - this.storage = groveDBStore; - this.decodeProtocolEntity = decodeProtocolEntity; - this.logger = logger; - } - - /** - * Create Data Contract in database - * - * @param {DataContract} dataContract - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async create(dataContract, blockInfo, options = {}) { - try { - const feeResult = await this.storage.getDrive().createContract( - dataContract, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - dataContract: dataContract.toBuffer().toString('hex'), - dataContractHash: createHash('sha256') - .update( - dataContract.toBuffer(), - ).digest('hex'), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'createContract'); - } - } - } - - /** - * Update Data Contract in database - * - * @param {DataContract} dataContract - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async update(dataContract, blockInfo, options = {}) { - try { - const feeResult = await this.storage.getDrive().updateContract( - dataContract, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - dataContract: dataContract.toBuffer().toString('hex'), - dataContractHash: createHash('sha256') - .update( - dataContract.toBuffer(), - ).digest('hex'), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'updateContract'); - } - } - } - - /** - * Fetch Data Contract by ID from database - * - * @param {Identifier} id - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @param {BlockInfo} [options.blockInfo] - * - * @return {Promise>} - */ - async fetch(id, options = {}) { - if (options.dryRun) { - return new StorageResult( - null, - [], - ); - } - - const [dataContract, feeResult] = await this.storage.getDrive().fetchContract( - id, - options && options.blockInfo ? options.blockInfo.epoch : undefined, - Boolean(options.useTransaction), - ); - - const operations = []; - if (feeResult) { - operations.push(new PreCalculatedOperation(feeResult)); - } - - return new StorageResult( - dataContract, - operations, - ); - } - - /** - * Prove Data Contract by ID from database - * - * @param {Identifier} id - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - * */ - async prove(id, options) { - return this.proveMany([id], options); - } - - /** - * Prove Data Contract by IDs from database - * - * @param {Identifier[]} ids - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - * */ - async proveMany(ids, options) { - const items = ids.map((id) => ({ - type: 'key', - key: id.toBuffer(), - })); - - return this.storage.proveQuery({ - path: DataContractStoreRepository.TREE_PATH, - query: { - query: { - items, - subqueryPath: [ - DataContractStoreRepository.DATA_CONTRACT_KEY, - ], - }, - }, - }, options); - } -} - -DataContractStoreRepository.TREE_PATH = [Buffer.from([64])]; -DataContractStoreRepository.DATA_CONTRACT_KEY = Buffer.from([0]); -DataContractStoreRepository.DOCUMENTS_TREE_KEY = Buffer.from([0]); - -module.exports = DataContractStoreRepository; diff --git a/packages/js-drive/lib/document/DocumentRepository.js b/packages/js-drive/lib/document/DocumentRepository.js deleted file mode 100644 index 0e2c7fa6183..00000000000 --- a/packages/js-drive/lib/document/DocumentRepository.js +++ /dev/null @@ -1,330 +0,0 @@ -const { createHash } = require('crypto'); - -const lodashCloneDeep = require('lodash/cloneDeep'); - -const PreCalculatedOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/PreCalculatedOperation'); -const DummyFeeResult = require('@dashevo/dpp/lib/stateTransition/fee/DummyFeeResult'); -const InvalidQueryError = require('./errors/InvalidQueryError'); -const StorageResult = require('../storage/StorageResult'); -const DataContractStoreRepository = require('../dataContract/DataContractStoreRepository'); - -class DocumentRepository { - /** - * - * @param {GroveDBStore} groveDBStore - * @param {BaseLogger} [logger] - */ - constructor( - groveDBStore, - logger = undefined, - ) { - this.storage = groveDBStore; - this.logger = logger; - } - - /** - * Create document - * - * @param {Document} document - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async create(document, blockInfo, options = {}) { - let feeResult; - - try { - (feeResult = await this.storage.getDrive() - .createDocument( - document, - blockInfo, - Boolean(options.useTransaction), - Boolean(options.dryRun), - )); - } finally { - if (this.logger) { - this.logger.info({ - document: document.toBuffer().toString('hex'), - documentHash: createHash('sha256') - .update( - document.toBuffer(), - ).digest('hex'), - useTransaction: Boolean(options.useTransaction), - dryRun: Boolean(options.dryRun), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'createDocument'); - } - } - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } - - /** - * Update document - * - * @param {Document} document - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async update(document, blockInfo, options = {}) { - let feeResult; - - try { - (feeResult = await this.storage.getDrive() - .updateDocument( - document, - blockInfo, - Boolean(options.useTransaction), - Boolean(options.dryRun), - )); - } finally { - if (this.logger) { - this.logger.info({ - document: document.toBuffer().toString('hex'), - documentHash: createHash('sha256') - .update( - document.toBuffer(), - ).digest('hex'), - useTransaction: Boolean(options.useTransaction), - dryRun: Boolean(options.dryRun), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'updateDocument'); - } - } - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } - - /** - * Find documents with query - * - * @param {DataContract} dataContract - * @param {string} documentType - * @param {Object} [options] - * @param {Array} [options.where] - * @param {number} [options.limit] - * @param {Buffer} [options.startAt] - * @param {Buffer} [options.startAfter] - * @param {Array} [options.orderBy] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @param {BlockInfo} [options.blockInfo] - * - * @throws InvalidQueryError - * - * @returns {Promise>} - */ - async find(dataContract, documentType, options = {}) { - const query = lodashCloneDeep(options); - let useTransaction = false; - - if (typeof query === 'object' && !Array.isArray(query) && query !== null) { - ({ useTransaction } = query); - delete query.useTransaction; - delete query.dryRun; - delete query.blockInfo; - - // Remove undefined options before we pass them to RS Drive - Object.keys(query) - .forEach((queryOption) => { - if (query[queryOption] === undefined) { - // eslint-disable-next-line no-param-reassign - delete query[queryOption]; - } - }); - } - - try { - let epochIndex; - - if (options && options.blockInfo) { - epochIndex = options.blockInfo.epoch; - } - - const [documents, processingCost] = await this.storage.getDrive() - .queryDocuments( - dataContract, - documentType, - epochIndex, - query, - useTransaction, - ); - - return new StorageResult( - documents, - [ - new PreCalculatedOperation(new DummyFeeResult(0, processingCost, [])), - ], - ); - } catch (e) { - if (e.message.startsWith('query: ')) { - throw new InvalidQueryError(e.message.substring(7, e.message.length)); - } - - if (e.message.startsWith('structure: ')) { - throw new InvalidQueryError(e.message.substring(11, e.message.length)); - } - - if (e.message.startsWith('contract: ')) { - throw new InvalidQueryError(e.message.substring(10, e.message.length)); - } - - if (e.message.startsWith('protocol: ')) { - throw new InvalidQueryError(e.message.substring(10, e.message.length)); - } - - throw e; - } - } - - /** - * @param {DataContract} dataContract - * @param {string} documentType - * @param {Identifier} id - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @return {Promise>} - */ - async delete(dataContract, documentType, id, blockInfo, options = { }) { - try { - const feeResult = await this.storage.getDrive() - .deleteDocument( - dataContract.getId(), - documentType, - id, - blockInfo, - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.info({ - dataContractId: dataContract.getId().toString(), - documentType, - id: id.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'deleteDocument'); - } - } - } - - /** - * @param {DataContract} dataContract - * @param {string} documentType - * @param {Object} options - * @param {boolean} [options.useTransaction=false] - * @return {Promise} - */ - async prove(dataContract, documentType, options = {}) { - const query = lodashCloneDeep(options); - let useTransaction = false; - - if (typeof query === 'object' && !Array.isArray(query) && query !== null) { - ({ useTransaction } = query); - delete query.useTransaction; - delete query.dryRun; - - // Remove undefined options before we pass them to RS Drive - Object.keys(query) - .forEach((queryOption) => { - if (query[queryOption] === undefined) { - // eslint-disable-next-line no-param-reassign - delete query[queryOption]; - } - }); - } - - try { - const [prove, processingCost] = await this.storage.getDrive() - .proveDocumentsQuery( - dataContract, - documentType, - query, - useTransaction, - ); - - return new StorageResult( - prove, - [ - new PreCalculatedOperation(new DummyFeeResult(0, processingCost, [])), - ], - ); - } catch (e) { - if (e.message.startsWith('query: ')) { - throw new InvalidQueryError(e.message.substring(7, e.message.length)); - } - - if (e.message.startsWith('structure: ')) { - throw new InvalidQueryError(e.message.substring(11, e.message.length)); - } - - if (e.message.startsWith('contract: ')) { - throw new InvalidQueryError(e.message.substring(10, e.message.length)); - } - - throw e; - } - } - - /** - * Prove documents from different contracts - * - * @param {{ dataContractId: Buffer, documentId: Buffer, type: string }[]} documents - * @return {Promise>} - */ - async proveManyDocumentsFromDifferentContracts(documents) { - const queries = documents.map(({ dataContractId, documentId, type }) => { - const dataContractsDocumentsPath = [ - dataContractId, - Buffer.from([1]), - Buffer.from(type), - Buffer.from([0]), - ]; - - return { - path: DataContractStoreRepository.TREE_PATH.concat(dataContractsDocumentsPath), - query: { - query: { - items: [ - { - type: 'key', - key: documentId, - }, - ], - }, - }, - }; - }); - - return this.storage.proveQueryMany(queries); - } -} - -module.exports = DocumentRepository; diff --git a/packages/js-drive/lib/document/errors/InvalidQueryError.js b/packages/js-drive/lib/document/errors/InvalidQueryError.js deleted file mode 100644 index 899eae1a1f6..00000000000 --- a/packages/js-drive/lib/document/errors/InvalidQueryError.js +++ /dev/null @@ -1,7 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class InvalidQueryError extends DriveError { - -} - -module.exports = InvalidQueryError; diff --git a/packages/js-drive/lib/document/fetchDataContractFactory.js b/packages/js-drive/lib/document/fetchDataContractFactory.js deleted file mode 100644 index b81b04deeee..00000000000 --- a/packages/js-drive/lib/document/fetchDataContractFactory.js +++ /dev/null @@ -1,44 +0,0 @@ -const IdentifierError = require('@dashevo/dpp/lib/identifier/errors/IdentifierError'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); - -const InvalidQueryError = require('./errors/InvalidQueryError'); - -/** - * @param {DataContractStoreRepository} dataContractRepository - * @returns {fetchDocuments} - */ -function fetchDataContractFactory( - dataContractRepository, -) { - /** - * Fetch Data Contract by Contract ID and type - * - * @typedef {Promise} fetchDataContract - * @param {Buffer|Identifier} contractId - * @returns {Promise>} - */ - async function fetchDataContract(contractId) { - let contractIdIdentifier; - try { - contractIdIdentifier = new Identifier(contractId); - } catch (e) { - if (e instanceof IdentifierError) { - throw new InvalidQueryError(`invalid data contract ID: ${e.message}`); - } - - throw e; - } - - const dataContractResult = await dataContractRepository.fetch(contractIdIdentifier); - - if (dataContractResult.isNull()) { - throw new InvalidQueryError(`data contract ${contractIdIdentifier} not found`); - } - - return dataContractResult; - } - - return fetchDataContract; -} - -module.exports = fetchDataContractFactory; diff --git a/packages/js-drive/lib/document/fetchDocumentsFactory.js b/packages/js-drive/lib/document/fetchDocumentsFactory.js deleted file mode 100644 index 31f4cda35d3..00000000000 --- a/packages/js-drive/lib/document/fetchDocumentsFactory.js +++ /dev/null @@ -1,46 +0,0 @@ -const InvalidQueryError = require('./errors/InvalidQueryError'); - -/** - * @param {DocumentRepository} documentRepository - * @param {fetchDataContract} fetchDataContract - * @returns {fetchDocuments} - */ -function fetchDocumentsFactory( - documentRepository, - fetchDataContract, -) { - /** - * Fetch original Documents by Contract ID and type - * - * @typedef {Promise} fetchDocuments - * @param {Buffer|Identifier} dataContractId - * @param {string} type - * @param {Object} [options] options - * @param {boolean} [options.useTransaction=false] - * @returns {Promise} - */ - async function fetchDocuments(dataContractId, type, options) { - const dataContractResult = await fetchDataContract(dataContractId); - - const dataContract = dataContractResult.getValue(); - const operations = dataContractResult.getOperations(); - - if (!dataContract.isDocumentDefined(type)) { - throw new InvalidQueryError(`document type ${type} is not defined in the data contract`); - } - - const result = await documentRepository.find( - dataContract, - type, - options, - ); - - result.addOperation(...operations); - - return result; - } - - return fetchDocuments; -} - -module.exports = fetchDocumentsFactory; diff --git a/packages/js-drive/lib/document/groveDB/createDocumentTreePath.js b/packages/js-drive/lib/document/groveDB/createDocumentTreePath.js deleted file mode 100644 index b2dc1625d57..00000000000 --- a/packages/js-drive/lib/document/groveDB/createDocumentTreePath.js +++ /dev/null @@ -1,15 +0,0 @@ -const DataContractStoreRepository = require('../../dataContract/DataContractStoreRepository'); -/** - * @param {DataContract} dataContract - * @param {string} documentType - * @return {Buffer[]} - */ -function createDocumentTypeTreePath(dataContract, documentType) { - return DataContractStoreRepository.TREE_PATH.concat([ - dataContract.getId().toBuffer(), - Buffer.from([1]), - Buffer.from(documentType), - ]); -} - -module.exports = createDocumentTypeTreePath; diff --git a/packages/js-drive/lib/document/proveDocumentsFactory.js b/packages/js-drive/lib/document/proveDocumentsFactory.js deleted file mode 100644 index 3da870652a0..00000000000 --- a/packages/js-drive/lib/document/proveDocumentsFactory.js +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @param {DocumentRepository} documentRepository - * @param {fetchDataContract} fetchDataContract - * @returns {fetchDocuments} - */ -function proveDocumentsFactory( - documentRepository, - fetchDataContract, -) { - /** - * - * @typedef {Promise} proveDocuments - * @param {Buffer|Identifier} dataContractId - * @param {string} type - * @param {Object} [options] options - * @param {boolean} [options.useTransaction=false] - * @returns {Promise} - */ - async function proveDocuments(dataContractId, type, options) { - const dataContractResult = await fetchDataContract(dataContractId); - - const dataContract = dataContractResult.getValue(); - const operations = dataContractResult.getOperations(); - - const result = await documentRepository.prove( - dataContract, - type, - options, - ); - - result.addOperation(...operations); - - return result; - } - - return proveDocuments; -} - -module.exports = proveDocumentsFactory; diff --git a/packages/js-drive/lib/dpp/CachedStateRepositoryDecorator.js b/packages/js-drive/lib/dpp/CachedStateRepositoryDecorator.js deleted file mode 100644 index 7313dcbb84a..00000000000 --- a/packages/js-drive/lib/dpp/CachedStateRepositoryDecorator.js +++ /dev/null @@ -1,344 +0,0 @@ -/** - * @implements StateRepository - */ -class CachedStateRepositoryDecorator { - /** - * @param {DriveStateRepository} stateRepository - */ - constructor( - stateRepository, - ) { - this.stateRepository = stateRepository; - } - - /** - * Fetch Identity by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async fetchIdentity(id, executionContext = undefined) { - return this.stateRepository.fetchIdentity(id, executionContext); - } - - /** - * Create identity - * - * @param {Identity} identity - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createIdentity(identity, executionContext = undefined) { - return this.stateRepository.createIdentity(identity, executionContext); - } - - /** - * Add keys to identity - * - * @param {Identifier} identityId - * @param {IdentityPublicKey[]} keys - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addKeysToIdentity(identityId, keys, executionContext = undefined) { - return this.stateRepository.addKeysToIdentity(identityId, keys, executionContext); - } - - /** - * Fetch identity balance - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async fetchIdentityBalance(identityId, executionContext = undefined) { - return this.stateRepository.fetchIdentityBalance( - identityId, - executionContext, - ); - } - - /** - * Fetch identity balance with debt - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - Balance can be negative in case of debt - */ - async fetchIdentityBalanceWithDebt(identityId, executionContext = undefined) { - return this.stateRepository.fetchIdentityBalanceWithDebt( - identityId, - executionContext, - ); - } - - /** - * Add to identity balance - * - * @param {Identifier} identityId - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToIdentityBalance(identityId, amount, executionContext = undefined) { - return this.stateRepository.addToIdentityBalance( - identityId, - amount, - executionContext, - ); - } - - /** - * Add to system credits - * - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToSystemCredits(amount, executionContext = undefined) { - return this.stateRepository.addToSystemCredits( - amount, - executionContext, - ); - } - - /** - * Disable identity keys - * - * @param {Identifier} identityId - * @param {number[]} keyIds - * @param {number} disableAt - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async disableIdentityKeys(identityId, keyIds, disableAt, executionContext = undefined) { - return this.stateRepository.disableIdentityKeys( - identityId, - keyIds, - disableAt, - executionContext, - ); - } - - /** - * Update identity revision - * - * @param {Identifier} identityId - * @param {number} revision - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async updateIdentityRevision(identityId, revision, executionContext = undefined) { - return this.stateRepository.updateIdentityRevision(identityId, revision, executionContext); - } - - /** - * Store spent asset lock transaction - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async markAssetLockTransactionOutPointAsUsed(outPointBuffer, executionContext = undefined) { - return this.stateRepository.markAssetLockTransactionOutPointAsUsed( - outPointBuffer, - executionContext, - ); - } - - /** - * Check if spent asset lock transaction is stored - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async isAssetLockTransactionOutPointAlreadyUsed(outPointBuffer, executionContext = undefined) { - return this.stateRepository.isAssetLockTransactionOutPointAlreadyUsed( - outPointBuffer, - executionContext, - ); - } - - /** - * Fetch Data Contract by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDataContract(id, executionContext = undefined) { - return this.stateRepository.fetchDataContract( - id, - executionContext, - ); - } - - /** - * Create Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDataContract(dataContract, executionContext = undefined) { - return this.stateRepository.createDataContract(dataContract, executionContext); - } - - /** - * Update Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDataContract(dataContract, executionContext = undefined) { - return this.stateRepository.updateDataContract(dataContract, executionContext); - } - - /** - * Fetch Documents by contract ID and type - * - * @param {Identifier} contractId - * @param {string} type - * @param {{ where: Object }} [options] - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDocuments(contractId, type, options = {}, executionContext = undefined) { - return this.stateRepository.fetchDocuments(contractId, type, options, executionContext); - } - - /** - * Create document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDocument(document, executionContext = undefined) { - return this.stateRepository.createDocument(document, executionContext); - } - - /** - * Update document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDocument(document, executionContext = undefined) { - return this.stateRepository.updateDocument(document, executionContext); - } - - /** - * Remove document - * - * @param {DataContract} dataContract - * @param {string} type - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async removeDocument(dataContract, type, id, executionContext = undefined) { - return this.stateRepository.removeDocument(dataContract, type, id, executionContext); - } - - /** - * Fetch transaction by ID - * - * @param {string} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchTransaction(id, executionContext = undefined) { - return this.stateRepository.fetchTransaction(id, executionContext); - } - - /** - * Fetch the latest platform block height - * - * @return {Promise} - */ - async fetchLatestPlatformBlockHeight() { - return this.stateRepository.fetchLatestPlatformBlockHeight(); - } - - /** - * Fetch the latest platform core chainlocked height - * - * @return {Promise} - */ - async fetchLatestPlatformCoreChainLockedHeight() { - return this.stateRepository.fetchLatestPlatformCoreChainLockedHeight(); - } - - /** - * Verify instant lock - * - * @param {InstantLock} instantLock - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async verifyInstantLock(instantLock, executionContext = undefined) { - return this.stateRepository.verifyInstantLock(instantLock, executionContext); - } - - /** - * Fetch Simplified Masternode List Store - * - * @return {Promise} - */ - async fetchSMLStore() { - return this.stateRepository.fetchSMLStore(); - } - - /** - * Fetch the latest withdrawal transaction index - * - * @returns {Promise} - */ - async fetchLatestWithdrawalTransactionIndex() { - return this.stateRepository.fetchLatestWithdrawalTransactionIndex(); - } - - /** - * Enqueue withdrawal transaction bytes into the queue - * - * @param {number} index - * @param {Buffer} transactionBytes - * - * @returns {Promise} - */ - async enqueueWithdrawalTransaction(index, transactionBytes) { - return this.stateRepository.enqueueWithdrawalTransaction( - index, - transactionBytes, - ); - } - - /** - * Returns block time - * - * @returns {Promise} - */ - async fetchLatestPlatformBlockTime() { - return this.stateRepository.fetchLatestPlatformBlockTime(); - } -} - -module.exports = CachedStateRepositoryDecorator; diff --git a/packages/js-drive/lib/dpp/DriveStateRepository.js b/packages/js-drive/lib/dpp/DriveStateRepository.js deleted file mode 100644 index 173c9f92efa..00000000000 --- a/packages/js-drive/lib/dpp/DriveStateRepository.js +++ /dev/null @@ -1,660 +0,0 @@ -const { TYPES } = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); - -const ReadOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/ReadOperation'); -const SignatureVerificationOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/SignatureVerificationOperation'); -const BlockInfo = require('../blockExecution/BlockInfo'); - -/** - * @implements StateRepository - */ -class DriveStateRepository { - #options = {}; - - /** - * @param {IdentityStoreRepository} identityRepository - * @param {IdentityBalanceStoreRepository} identityBalanceRepository - * @param {IdentityPublicKeyStoreRepository} publicKeyToToIdentitiesRepository - * @param {DataContractStoreRepository} dataContractRepository - * @param {fetchDocuments} fetchDocuments - * @param {DocumentRepository} documentRepository - * @param {SpentAssetLockTransactionsRepository} spentAssetLockTransactionsRepository - * @param {RpcClient} coreRpcClient - * @param {BlockExecutionContext} blockExecutionContext - * @param {SimplifiedMasternodeList} simplifiedMasternodeList - * @param {Drive} rsDrive - * @param {Object} [options] - * @param {Object} [options.useTransaction=false] - */ - constructor( - identityRepository, - identityBalanceRepository, - publicKeyToToIdentitiesRepository, - dataContractRepository, - fetchDocuments, - documentRepository, - spentAssetLockTransactionsRepository, - coreRpcClient, - blockExecutionContext, - simplifiedMasternodeList, - rsDrive, - options = {}, - ) { - this.identityRepository = identityRepository; - this.identityBalanceRepository = identityBalanceRepository; - this.identityPublicKeyRepository = publicKeyToToIdentitiesRepository; - this.dataContractRepository = dataContractRepository; - this.fetchDocumentsFunction = fetchDocuments; - this.documentRepository = documentRepository; - this.spentAssetLockTransactionsRepository = spentAssetLockTransactionsRepository; - this.coreRpcClient = coreRpcClient; - this.blockExecutionContext = blockExecutionContext; - this.simplifiedMasternodeList = simplifiedMasternodeList; - this.rsDrive = rsDrive; - this.#options = options; - } - - /** - * Fetch Identity by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async fetchIdentity(id, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityRepository.fetch( - id, - { - blockInfo, - ...this.#createRepositoryOptions(executionContext), - }, - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return result.getValue(); - } - - /** - * Create identity - * - * @param {Identity} identity - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createIdentity(identity, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityRepository.create( - identity, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Add keys to identity - * - * @param {Identifier} identityId - * @param {IdentityPublicKey[]} keys - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addKeysToIdentity(identityId, keys, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityPublicKeyRepository.add( - identityId, - keys, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Fetch identity balance - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async fetchIdentityBalance(identityId, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityBalanceRepository.fetch( - identityId, - { - blockInfo, - ...this.#createRepositoryOptions(executionContext), - }, - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return result.getValue(); - } - - /** - * Fetch identity balance with debt - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - Balance can be negative in case of debt - */ - async fetchIdentityBalanceWithDebt(identityId, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityBalanceRepository.fetchWithDebt( - identityId, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return result.getValue(); - } - - /** - * Add to identity balance - * - * @param {Identifier} identityId - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToIdentityBalance(identityId, amount, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityBalanceRepository.add( - identityId, - amount, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Add to system credits - * - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToSystemCredits(amount, executionContext = undefined) { - if (executionContext.isDryRun()) { - return; - } - - await this.rsDrive.addToSystemCredits( - amount, - this.#options.useTransaction || false, - ); - } - - /** - * Disable identity keys - * - * @param {Identifier} identityId - * @param {number[]} keyIds - * @param {number} disableAt - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async disableIdentityKeys(identityId, keyIds, disableAt, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityPublicKeyRepository.disable( - identityId, - keyIds, - disableAt, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Update identity revision - * - * @param {Identifier} identityId - * @param {number} revision - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async updateIdentityRevision(identityId, revision, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.identityRepository.updateRevision( - identityId, - revision, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Store spent asset lock transaction - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async markAssetLockTransactionOutPointAsUsed(outPointBuffer, executionContext = undefined) { - const result = await this.spentAssetLockTransactionsRepository.store( - outPointBuffer, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Check if spent asset lock transaction is stored - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async isAssetLockTransactionOutPointAlreadyUsed(outPointBuffer, executionContext = undefined) { - const result = await this.spentAssetLockTransactionsRepository.fetch( - outPointBuffer, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return !result.isNull(); - } - - /** - * Fetch Data Contract by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDataContract(id, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.dataContractRepository.fetch( - id, - { - ...this.#createRepositoryOptions(executionContext), - // This method doesn't implement dry run because we need a contract - // to proceed dry run validation and collect further operations - dryRun: false, - blockInfo, - }, - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return result.getValue(); - } - - /** - * Create Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDataContract(dataContract, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.dataContractRepository.create( - dataContract, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Update Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDataContract(dataContract, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.dataContractRepository.update( - dataContract, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Fetch Documents by contract ID and type - * - * @param {Identifier} contractId - * @param {string} type - * @param {{ where: Object }} [options] - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDocuments(contractId, type, options = {}, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.fetchDocumentsFunction( - contractId, - type, - { - blockInfo, - ...options, - ...this.#createRepositoryOptions(executionContext), - }, - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - - return result.getValue(); - } - - /** - * Create document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDocument(document, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.documentRepository.create( - document, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Update document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDocument(document, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.documentRepository.update( - document, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Remove document - * - * @param {DataContract} dataContract - * @param {string} type - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async removeDocument(dataContract, type, id, executionContext = undefined) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - const result = await this.documentRepository.delete( - dataContract, - type, - id, - blockInfo, - this.#createRepositoryOptions(executionContext), - ); - - if (executionContext) { - executionContext.addOperation(...result.getOperations()); - } - } - - /** - * Fetch Core transaction by ID - * - * @param {string} id - Transaction ID hex - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchTransaction(id, executionContext = undefined) { - if (executionContext && executionContext.isDryRun()) { - executionContext.addOperation( - // TODO: Revisit this value - new ReadOperation(512), - ); - - return { - data: Buffer.alloc(0), - height: 1, - }; - } - - try { - const { result: transaction } = await this.coreRpcClient.getRawTransaction(id, 1); - - const data = Buffer.from(transaction.hex, 'hex'); - - if (executionContext) { - executionContext.addOperation( - new ReadOperation(data.length), - ); - } - - return { - data, - height: transaction.height, - }; - } catch (e) { - // Invalid address or key error - if (e.code === -5) { - return null; - } - - throw e; - } - } - - /** - * Fetch the latest platform block height - * - * @return {Promise} - */ - async fetchLatestPlatformBlockHeight() { - return this.blockExecutionContext.getHeight(); - } - - /** - * Fetch the latest platform block time - * - * @return {Promise} - */ - async fetchLatestPlatformBlockTime() { - const timeMs = this.blockExecutionContext.getTimeMs(); - - if (!timeMs) { - throw new Error('Time is not set'); - } - - return timeMs; - } - - /** - * Fetch the latest platform core chainlocked height - * - * @return {Promise} - */ - async fetchLatestPlatformCoreChainLockedHeight() { - return this.blockExecutionContext.getCoreChainLockedHeight(); - } - - /** - * Verify instant lock - * - * @param {InstantLock} instantLock - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - // eslint-disable-next-line no-unused-vars - async verifyInstantLock(instantLock, executionContext = undefined) { - const coreChainLockedHeight = this.blockExecutionContext.getCoreChainLockedHeight(); - - if (coreChainLockedHeight === null) { - return false; - } - - if (executionContext) { - executionContext.addOperation( - new SignatureVerificationOperation(TYPES.ECDSA_SECP256K1), - ); - - if (executionContext.isDryRun()) { - return true; - } - } - - try { - const { result: isVerified } = await this.coreRpcClient.verifyIsLock( - instantLock.getRequestId().toString('hex'), - instantLock.txid, - instantLock.signature, - coreChainLockedHeight, - ); - - return isVerified; - } catch (e) { - // Invalid address or key error or - // Invalid, missing or duplicate parameter - // Parse error - if ([-8, -5, -32700].includes(e.code)) { - return false; - } - - throw e; - } - } - - /** - * Fetch Simplified Masternode List Store - * - * @return {Promise} - */ - async fetchSMLStore() { - return this.simplifiedMasternodeList.getStore(); - } - - /** - * Fetch the latest withdrawal transaction index - * - * @returns {Promise} - */ - async fetchLatestWithdrawalTransactionIndex() { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - return this.rsDrive.fetchLatestWithdrawalTransactionIndex( - blockInfo, - this.#options.useTransaction, - this.#options.dryRun, - ); - } - - /** - * Enqueue withdrawal transaction bytes into the queue - * - * @param {number} index - * @param {Buffer} transactionBytes - * - * @returns {Promise} - */ - async enqueueWithdrawalTransaction(index, transactionBytes) { - const blockInfo = BlockInfo.createFromBlockExecutionContext(this.blockExecutionContext); - - // TODO: handle dry run via passing state transition execution context - return this.rsDrive.enqueueWithdrawalTransaction( - index, - transactionBytes, - blockInfo, - this.#options.useTransaction, - ); - } - - /** - * @private - * @param {StateTransitionExecutionContext} [executionContext] - * @return {{dryRun: boolean, useTransaction: boolean}} - */ - #createRepositoryOptions(executionContext) { - return { - useTransaction: this.#options.useTransaction || false, - dryRun: executionContext ? executionContext.isDryRun() : false, - }; - } -} - -module.exports = DriveStateRepository; diff --git a/packages/js-drive/lib/dpp/LoggedStateRepositoryDecorator.js b/packages/js-drive/lib/dpp/LoggedStateRepositoryDecorator.js deleted file mode 100644 index c75e9b9e00b..00000000000 --- a/packages/js-drive/lib/dpp/LoggedStateRepositoryDecorator.js +++ /dev/null @@ -1,676 +0,0 @@ -/** - * @implements StateRepository - */ -class LoggedStateRepositoryDecorator { - /** - * @param {DriveStateRepository|CachedStateRepositoryDecorator} stateRepository - * @param {BlockExecutionContext} blockExecutionContext - */ - constructor( - stateRepository, - blockExecutionContext, - ) { - this.stateRepository = stateRepository; - this.blockExecutionContext = blockExecutionContext; - } - - /** - * @private - * @param {string} method - state repository method name - * @param {object} parameters - parameters of the state repository call - * @param {object} response - response of the state repository call - */ - log(method, parameters, response) { - const logger = this.blockExecutionContext.getContextLogger(); - - logger.trace({ - stateRepository: { - method, - parameters, - response, - }, - }, `StateRepository#${method}`); - } - - /** - * Fetch Identity by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async fetchIdentity(id, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchIdentity(id, executionContext); - } finally { - this.log( - 'fetchIdentity', - { - id, - }, - response, - ); - } - - return response; - } - - /** - * Create identity - * - * @param {Identity} identity - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createIdentity(identity, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.createIdentity(identity, executionContext); - } finally { - this.log( - 'createIdentity', - { - identity, - }, - response, - ); - } - - return response; - } - - /** - * Add keys to identity - * - * @param {Identifier} identityId - * @param {IdentityPublicKey[]} keys - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addKeysToIdentity(identityId, keys, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.addKeysToIdentity(identityId, keys, executionContext); - } finally { - this.log( - 'addKeysToIdentity', - { - identityId, - keys, - }, - response, - ); - } - - return response; - } - - /** - * Fetch identity balance - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async fetchIdentityBalance(identityId, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchIdentityBalance( - identityId, - executionContext, - ); - } finally { - this.log( - 'fetchIdentityBalance', - { - identityId, - }, - response, - ); - } - - return response; - } - - /** - * Fetch identity balance with debt - * - * @param {Identifier} identityId - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - Balance can be negative in case of debt - */ - async fetchIdentityBalanceWithDebt(identityId, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchIdentityBalanceWithDebt( - identityId, - executionContext, - ); - } finally { - this.log( - 'fetchIdentityBalanceWithDebt', - { - identityId, - }, - response, - ); - } - - return response; - } - - /** - * Add to identity balance - * - * @param {Identifier} identityId - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToIdentityBalance(identityId, amount, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.addToIdentityBalance( - identityId, - amount, - executionContext, - ); - } finally { - this.log( - 'addToIdentityBalance', - { - identityId, - amount, - }, - response, - ); - } - - return response; - } - - /** - * Add to system credits - * - * @param {number} amount - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async addToSystemCredits(amount, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.addToSystemCredits( - amount, - executionContext, - ); - } finally { - this.log( - 'addToSystemCredits', - { - amount, - }, - response, - ); - } - - return response; - } - - /** - * Disable identity keys - * - * @param {Identifier} identityId - * @param {number[]} keyIds - * @param {number} disableAt - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async disableIdentityKeys(identityId, keyIds, disableAt, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.disableIdentityKeys( - identityId, - keyIds, - disableAt, - executionContext, - ); - } finally { - this.log( - 'disableIdentityKeys', - { - identityId, - keyIds, - disableAt, - }, - response, - ); - } - - return response; - } - - /** - * Update identity revision - * - * @param {Identifier} identityId - * @param {number} revision - * @param {StateTransitionExecutionContext} [executionContext] - * @returns {Promise} - */ - async updateIdentityRevision(identityId, revision, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.updateIdentityRevision( - identityId, - revision, - executionContext, - ); - } finally { - this.log( - 'updateIdentityRevision', - { - identityId, - revision, - }, - response, - ); - } - - return response; - } - - /** - * Store spent asset lock transaction - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async markAssetLockTransactionOutPointAsUsed(outPointBuffer, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.markAssetLockTransactionOutPointAsUsed( - outPointBuffer, - executionContext, - ); - } finally { - this.log( - 'markAssetLockTransactionOutPointAsUsed', - { - outPointBuffer: outPointBuffer.toString('base64'), - }, - response, - ); - } - - return response; - } - - /** - * Check if spent asset lock transaction is stored - * - * @param {Buffer} outPointBuffer - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async isAssetLockTransactionOutPointAlreadyUsed(outPointBuffer, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.isAssetLockTransactionOutPointAlreadyUsed( - outPointBuffer, - executionContext, - ); - } finally { - this.log( - 'isAssetLockTransactionOutPointAlreadyUsed', - { - outPointBuffer: outPointBuffer.toString('base64'), - }, - response, - ); - } - - return response; - } - - /** - * Fetch Data Contract by ID - * - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDataContract(id, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchDataContract(id, executionContext); - } finally { - this.log( - 'fetchDataContract', - { - id, - }, - response, - ); - } - - return response; - } - - /** - * Store Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDataContract(dataContract, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.createDataContract(dataContract, executionContext); - } finally { - this.log('createDataContract', { dataContract }, response); - } - - return response; - } - - /** - * Store Data Contract - * - * @param {DataContract} dataContract - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDataContract(dataContract, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.updateDataContract(dataContract, executionContext); - } finally { - this.log('updateDataContract', { dataContract }, response); - } - - return response; - } - - /** - * Fetch Documents by contract ID and type - * - * @param {Identifier} contractId - * @param {string} type - * @param {{ where: Object }} [options] - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchDocuments(contractId, type, options = {}, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchDocuments( - contractId, - type, - options, - executionContext, - ); - } finally { - this.log( - 'fetchDocuments', - { - contractId, - type, - options, - }, - response, - ); - } - - return response; - } - - /** - * Create document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async createDocument(document, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.createDocument(document, executionContext); - } finally { - this.log( - 'createDocument', - { - document, - }, - response, - ); - } - - return response; - } - - /** - * Update document - * - * @param {Document} document - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async updateDocument(document, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.updateDocument(document, executionContext); - } finally { - this.log( - 'updateDocument', - { - document, - }, - response, - ); - } - - return response; - } - - /** - * Remove document - * - * @param {DataContract} dataContract - * @param {string} type - * @param {Identifier} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async removeDocument(dataContract, type, id, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.removeDocument( - dataContract, - type, - id, - executionContext, - ); - } finally { - this.log( - 'removeDocument', - { - dataContract, - type, - id, - }, - response, - ); - } - - return response; - } - - /** - * Fetch transaction by ID - * - * @param {string} id - * @param {StateTransitionExecutionContext} [executionContext] - * - * @returns {Promise} - */ - async fetchTransaction(id, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.fetchTransaction(id, executionContext); - } finally { - this.log( - 'fetchTransaction', - { - id, - }, - response, - ); - } - - return response; - } - - /** - * Fetch the latest platform block height - * - * @return {Promise} - */ - async fetchLatestPlatformBlockHeight() { - let response; - - try { - response = await this.stateRepository.fetchLatestPlatformBlockHeight(); - } finally { - this.log('fetchLatestPlatformBlockHeight', {}, response); - } - - return response; - } - - /** - * Fetch the latest platform core chainlocked height - * - * @return {Promise} - */ - async fetchLatestPlatformCoreChainLockedHeight() { - let response; - - try { - response = await this.stateRepository.fetchLatestPlatformCoreChainLockedHeight(); - } finally { - this.log('fetchLatestPlatformCoreChainLockedHeight', {}, response); - } - - return response; - } - - /** - * Verify instant lock - * - * @param {InstantLock} instantLock - * @param {StateTransitionExecutionContext} [executionContext] - * - * @return {Promise} - */ - async verifyInstantLock(instantLock, executionContext = undefined) { - let response; - - try { - response = await this.stateRepository.verifyInstantLock(instantLock, executionContext); - } finally { - this.log('verifyInstantLock', { instantLock }, response); - } - - return response; - } - - /** - * Returns block time - * - * @returns {Promise} - */ - async fetchLatestPlatformBlockTime() { - let response; - - try { - response = await this.stateRepository.fetchLatestPlatformBlockTime(); - } finally { - this.log('fetchLatestPlatformBlockTime', { }, response); - } - - return response; - } - - /** - * Fetch the latest withdrawal transaction index - * - * @returns {Promise} - */ - async fetchLatestWithdrawalTransactionIndex() { - let response; - - try { - response = await this.stateRepository.fetchLatestWithdrawalTransactionIndex(); - } finally { - this.log('fetchLatestWithdrawalTransactionIndex', {}, response); - } - - return response; - } - - /** - * Enqueue withdrawal transaction bytes into the queue - * - * @param {number} index - * @param {Buffer} transactionBytes - * - * @returns {Promise} - */ - async enqueueWithdrawalTransaction(index, transactionBytes) { - let response; - - try { - response = await this.stateRepository.enqueueWithdrawalTransaction( - index, - transactionBytes, - ); - } finally { - this.log('enqueueWithdrawalTransaction', { index, transactionBytes }, response); - } - } -} - -module.exports = LoggedStateRepositoryDecorator; diff --git a/packages/js-drive/lib/errorHandlerFactory.js b/packages/js-drive/lib/errorHandlerFactory.js deleted file mode 100644 index 7172646507a..00000000000 --- a/packages/js-drive/lib/errorHandlerFactory.js +++ /dev/null @@ -1,59 +0,0 @@ -const printErrorFace = require('./util/printErrorFace'); - -/** - * @param {BaseLogger} logger - * @param {AwilixContainer} container - * @param {closeAbciServer} closeAbciServer - */ -function errorHandlerFactory(logger, container, closeAbciServer) { - let isCalledAlready = false; - const errors = []; - - /** - * Error handler - * - * @param {Error} error - */ - async function errorHandler(error) { - // Collect all thrown errors - errors.push(error); - - // Gracefully shutdown only once - if (isCalledAlready) { - return; - } - - isCalledAlready = true; - - try { - try { - // Close all ABCI server connections - await closeAbciServer(); - - // Add further code to the end of event loop (the same as process.nextTick) - await Promise.resolve(); - - // eslint-disable-next-line no-console - console.log(printErrorFace()); - - errors.forEach((e) => { - const preferredLogger = e.contextLogger || logger; - delete e.contextLogger; - - preferredLogger.fatal({ err: e }, e.message); - }); - } finally { - await container.dispose(); - } - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } finally { - process.exit(1); - } - } - - return errorHandler; -} - -module.exports = errorHandlerFactory; diff --git a/packages/js-drive/lib/errors/DriveError.js b/packages/js-drive/lib/errors/DriveError.js deleted file mode 100644 index ba5dc360532..00000000000 --- a/packages/js-drive/lib/errors/DriveError.js +++ /dev/null @@ -1,23 +0,0 @@ -class DriveError extends Error { - /** - * @param {string} message - */ - constructor(message) { - super(message); - - this.name = this.constructor.name; - - Error.captureStackTrace(this, this.constructor); - } - - /** - * Get message - * - * @return {string} - */ - getMessage() { - return this.message; - } -} - -module.exports = DriveError; diff --git a/packages/js-drive/lib/featureFlag/getFeatureFlagForHeightFactory.js b/packages/js-drive/lib/featureFlag/getFeatureFlagForHeightFactory.js deleted file mode 100644 index c15175c48da..00000000000 --- a/packages/js-drive/lib/featureFlag/getFeatureFlagForHeightFactory.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @param {Identifier} featureFlagsContractId - * @param {fetchDocuments} fetchDocuments - * - * @return {getFeatureFlagForHeight} - */ -function getFeatureFlagForHeightFactory( - featureFlagsContractId, - fetchDocuments, -) { - /** - * @typedef getFeatureFlagForHeight - * - * @param {string} flagType - * @param {Long} blockHeight - * @param {boolean} [useTransaction=false] - * - * @return {Promise} - */ - async function getFeatureFlagForHeight(flagType, blockHeight, useTransaction = false) { - if (!featureFlagsContractId) { - return null; - } - - const query = { - where: [ - ['enableAtHeight', '==', blockHeight.toNumber()], - ], - }; - - const result = await fetchDocuments( - featureFlagsContractId, - flagType, - { - ...query, - useTransaction, - }, - ); - - const [document] = result.getValue(); - - return document; - } - - return getFeatureFlagForHeight; -} - -module.exports = getFeatureFlagForHeightFactory; diff --git a/packages/js-drive/lib/featureFlag/getLatestFeatureFlagFactory.js b/packages/js-drive/lib/featureFlag/getLatestFeatureFlagFactory.js deleted file mode 100644 index 56e1dfcd885..00000000000 --- a/packages/js-drive/lib/featureFlag/getLatestFeatureFlagFactory.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @param {Identifier} featureFlagsContractId - * @param {fetchDocuments} fetchDocuments - * - * @return {getLatestFeatureFlag} - */ -function getLatestFeatureFlagFactory( - featureFlagsContractId, - fetchDocuments, -) { - /** - * @typedef getLatestFeatureFlag - * - * @param {string} flagType - * @param {Long} blockHeight - * @param {boolean} [useTransaction=false] - * - * @return {Promise} - */ - async function getLatestFeatureFlag(flagType, blockHeight, useTransaction = false) { - if (!featureFlagsContractId) { - return null; - } - - const query = { - where: [ - ['enableAtHeight', '<=', blockHeight.toNumber()], - ], - orderBy: [ - ['enableAtHeight', 'desc'], - ], - limit: 1, - }; - - const result = await fetchDocuments( - featureFlagsContractId, - flagType, - { - ...query, - useTransaction, - }, - ); - - const [document] = result.getValue(); - - return document; - } - - return getLatestFeatureFlag; -} - -module.exports = getLatestFeatureFlagFactory; diff --git a/packages/js-drive/lib/identity/IdentityBalanceStoreRepository.js b/packages/js-drive/lib/identity/IdentityBalanceStoreRepository.js deleted file mode 100644 index 7c745a4fb06..00000000000 --- a/packages/js-drive/lib/identity/IdentityBalanceStoreRepository.js +++ /dev/null @@ -1,200 +0,0 @@ -const PreCalculatedOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/PreCalculatedOperation'); -const StorageResult = require('../storage/StorageResult'); - -class IdentityBalanceStoreRepository { - /** - * - * @param {GroveDBStore} groveDBStore - * @param {decodeProtocolEntity} decodeProtocolEntity - */ - constructor(groveDBStore, decodeProtocolEntity) { - this.storage = groveDBStore; - this.decodeProtocolEntity = decodeProtocolEntity; - } - - /** - * Fetch balance by id from database - * - * @param {Identifier} id - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {BlockInfo} [options.blockInfo] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async fetch(id, options = { }) { - if (options && options.blockInfo) { - const [balance, feeResult] = await this.storage.getDrive().fetchIdentityBalanceWithCosts( - id, - options.blockInfo.toObject(), - Boolean(options.useTransaction), - ); - - return new StorageResult( - balance, - [new PreCalculatedOperation(feeResult)], - ); - } - - const balance = await this.storage.getDrive().fetchIdentityBalance( - id, - Boolean(options.useTransaction), - ); - - return new StorageResult( - balance, - [], - ); - } - - /** - * Fetch identity by id from database - * - * @param {Identifier} id - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async fetchWithDebt(id, blockInfo, options = {}) { - const [ - balance, - feeResult, - ] = await this.storage.getDrive().fetchIdentityBalanceIncludeDebtWithCosts( - id, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - balance, - [new PreCalculatedOperation(feeResult)], - ); - } - - /** - * Add to identity balance in database - * - * @param {Identifier} identityId - * @param {number} amount - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async add(identityId, amount, blockInfo, options = {}) { - try { - const feeResult = await this.storage.getDrive().addToIdentityBalance( - identityId, - amount, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'add'); - } - } - } - - /** - * Apply fees to identity balance in database - * - * @param {Identifier} identityId - * @param {FeeResult} fees - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>} - */ - async applyFees( - identityId, - fees, - options = {}, - ) { - try { - const feeResult = await this.storage.getDrive().applyFeesToIdentityBalance( - identityId, - fees, - Boolean(options.useTransaction), - ); - - return new StorageResult( - feeResult, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'applyFees'); - } - } - } - - /** - * Remove balance from identity in database - * - * @param {Identifier} identityId - * @param {number} amount - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async remove( - identityId, - amount, - blockInfo, - options = {}, - ) { - try { - const feeResult = await this.storage.getDrive().removeFromIdentityBalance( - identityId, - amount, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'remove'); - } - } - } -} - -module.exports = IdentityBalanceStoreRepository; diff --git a/packages/js-drive/lib/identity/IdentityPublicKeyStoreRepository.js b/packages/js-drive/lib/identity/IdentityPublicKeyStoreRepository.js deleted file mode 100644 index 52f7131c43d..00000000000 --- a/packages/js-drive/lib/identity/IdentityPublicKeyStoreRepository.js +++ /dev/null @@ -1,109 +0,0 @@ -const PreCalculatedOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/PreCalculatedOperation'); -const StorageResult = require('../storage/StorageResult'); - -class IdentityPublicKeyStoreRepository { - /** - * - * @param {GroveDBStore} groveDBStore - * @param {decodeProtocolEntity} decodeProtocolEntity - */ - constructor(groveDBStore, decodeProtocolEntity) { - this.storage = groveDBStore; - this.decodeProtocolEntity = decodeProtocolEntity; - } - - /** - * Add keys to an already existing Identity - * - * @param {Identifier} identityId - * @param {IdentityPublicKey[]} keys - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async add( - identityId, - keys, - blockInfo, - options = {}, - ) { - try { - const feeResult = await this.storage.getDrive().addKeysToIdentity( - identityId, - keys, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'add'); - } - } - } - - /** - * Disable keys in already existing Identity - * - * @param {Identifier} identityId - * @param {number[]} keyIds - * @param {number} disabledAt - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async disable( - identityId, - keyIds, - disabledAt, - blockInfo, - options = {}, - ) { - try { - const feeResult = await this.storage.getDrive().disableIdentityKeys( - identityId, - keyIds, - disabledAt, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'disable'); - } - } - } -} - -IdentityPublicKeyStoreRepository.TREE_PATH = [Buffer.from([2])]; - -module.exports = IdentityPublicKeyStoreRepository; diff --git a/packages/js-drive/lib/identity/IdentityStoreRepository.js b/packages/js-drive/lib/identity/IdentityStoreRepository.js deleted file mode 100644 index 2bb339ee4e5..00000000000 --- a/packages/js-drive/lib/identity/IdentityStoreRepository.js +++ /dev/null @@ -1,295 +0,0 @@ -const PreCalculatedOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/PreCalculatedOperation'); -const StorageResult = require('../storage/StorageResult'); - -class IdentityStoreRepository { - /** - * - * @param {GroveDBStore} groveDBStore - * @param {decodeProtocolEntity} decodeProtocolEntity - */ - constructor(groveDBStore, decodeProtocolEntity) { - this.storage = groveDBStore; - this.decodeProtocolEntity = decodeProtocolEntity; - } - - /** - * Fetch identity by id from database - * - * @param {Identifier} id - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {BlockInfo} [options.blockInfo] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async fetch(id, options = { }) { - if (options.dryRun) { - return new StorageResult( - null, - [], - ); - } - - if (options && options.blockInfo) { - const [identity, feeResult] = await this.storage.getDrive().fetchIdentityWithCosts( - id, - options.blockInfo.epoch, - Boolean(options.useTransaction), - ); - - return new StorageResult( - identity, - [new PreCalculatedOperation(feeResult)], - ); - } - - const identity = await this.storage.getDrive().fetchIdentity( - id, - Boolean(options.useTransaction), - ); - - return new StorageResult( - identity, - [], - ); - } - - /** - * Fetch identity by public key hash - * - * @param {Buffer} hash - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>} - */ - async fetchByPublicKeyHash(hash, options = {}) { - try { - const [identity] = await this.storage.getDrive().fetchIdentitiesByPublicKeyHashes( - [hash], - Boolean(options.useTransaction), - ); - - return new StorageResult( - identity, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - hash, - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'fetchManyByPublicKeyHashes'); - } - } - } - - /** - * Fetch many identities by public key hashes - * - * @param {Buffer[]} hashes - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>>} - */ - async fetchManyByPublicKeyHashes(hashes, options = {}) { - try { - const identities = await this.storage.getDrive().fetchIdentitiesByPublicKeyHashes( - hashes, - Boolean(options.useTransaction), - ); - - return new StorageResult( - identities, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - hashes, - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'fetchManyByPublicKeyHashes'); - } - } - } - - /** - * Prove identities by multiple public key hashes - * - * @param {Buffer[]} hashes - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>} - */ - async proveManyByPublicKeyHashes(hashes, options = {}) { - try { - const proof = await this.storage.getDrive().proveIdentitiesByPublicKeyHashes( - hashes, - Boolean(options.useTransaction), - ); - - return new StorageResult( - proof, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - hashes, - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'proveManyByPublicKeyHashes'); - } - } - } - - /** - * Create Identity in database - * - * @param {Identity} identity - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async create(identity, blockInfo, options = {}) { - try { - const feeResult = await this.storage.getDrive().insertIdentity( - identity, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identity.id.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'create'); - } - } - } - - /** - * Update identity revision in database - * - * @param {Identifier} identityId - * @param {number} revision - * @param {BlockInfo} blockInfo - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async updateRevision( - identityId, - revision, - blockInfo, - options = {}, - ) { - try { - const feeResult = await this.storage.getDrive().updateIdentityRevision( - identityId, - revision, - blockInfo.toObject(), - Boolean(options.useTransaction), - Boolean(options.dryRun), - ); - - return new StorageResult( - undefined, - [ - new PreCalculatedOperation(feeResult), - ], - ); - } finally { - if (this.logger) { - this.logger.trace({ - identity_id: identityId.toString(), - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'updateRevision'); - } - } - } - - /** - * Prove identity by id - * - * @param {Identifier} id - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>} - * */ - async prove(id, options = {}) { - try { - const proof = await this.storage.getDrive().proveIdentity( - id, - Boolean(options.useTransaction), - ); - - return new StorageResult( - proof, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - id, - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'prove'); - } - } - } - - /** - * Prove identity by ids - * - * @param {Identifier[]} ids - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * - * @return {Promise>} - * */ - async proveMany(ids, options = {}) { - try { - const proof = await this.storage.getDrive().proveManyIdentities( - ids, - Boolean(options.useTransaction), - ); - - return new StorageResult( - proof, - [], - ); - } finally { - if (this.logger) { - this.logger.trace({ - ids, - useTransaction: Boolean(options.useTransaction), - appHash: (await this.storage.getRootHash(options)).toString('hex'), - }, 'proveMany'); - } - } - } -} - -module.exports = IdentityStoreRepository; diff --git a/packages/js-drive/lib/identity/SpentAssetLockTransactionsRepository.js b/packages/js-drive/lib/identity/SpentAssetLockTransactionsRepository.js deleted file mode 100644 index 081954da391..00000000000 --- a/packages/js-drive/lib/identity/SpentAssetLockTransactionsRepository.js +++ /dev/null @@ -1,73 +0,0 @@ -const StorageResult = require('../storage/StorageResult'); - -class SpentAssetLockTransactionsRepository { - /** - * @param {GroveDBStore} groveDBStore - */ - constructor(groveDBStore) { - this.storage = groveDBStore; - } - - /** - * Store the outPoint - * - * @param {Buffer} outPointBuffer - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async store(outPointBuffer, options = {}) { - if (options.dryRun) { - return new StorageResult(undefined, []); - } - - const emptyValue = Buffer.from([0]); - - const result = await this.storage.put( - SpentAssetLockTransactionsRepository.TREE_PATH, - outPointBuffer, - emptyValue, - options, - ); - - return new StorageResult( - undefined, - result.getOperations(), - ); - } - - /** - * Fetch the outPoint - * - * @param {Buffer} outPointBuffer - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * - * @return {Promise>} - */ - async fetch(outPointBuffer, options = {}) { - if (options.dryRun) { - return new StorageResult(null, []); - } - - const result = await this.storage.get( - SpentAssetLockTransactionsRepository.TREE_PATH, - outPointBuffer, - options, - ); - - return new StorageResult( - result.getValue(), - result.getOperations(), - ); - } -} - -SpentAssetLockTransactionsRepository.TREE_PATH = [ - Buffer.from([72]), -]; - -module.exports = SpentAssetLockTransactionsRepository; diff --git a/packages/js-drive/lib/identity/masternode/LastSyncedCoreHeightRepository.js b/packages/js-drive/lib/identity/masternode/LastSyncedCoreHeightRepository.js deleted file mode 100644 index 13ad4d4d140..00000000000 --- a/packages/js-drive/lib/identity/masternode/LastSyncedCoreHeightRepository.js +++ /dev/null @@ -1,68 +0,0 @@ -const StorageResult = require('../../storage/StorageResult'); - -class LastSyncedCoreHeightRepository { - /** - * - * @param {GroveDBStore} groveDBStore - */ - constructor(groveDBStore) { - this.storage = groveDBStore; - } - - /** - * Store last synced core height - * - * @param {number} height - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @return {Promise>} - */ - async store(height, options = {}) { - const value = Buffer.alloc(4); - - value.writeUInt32BE(height); - - return this.storage.put( - LastSyncedCoreHeightRepository.TREE_PATH, - LastSyncedCoreHeightRepository.KEY, - value, - options, - ); - } - - /** - * Fetch last synced core height - * - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @return {Promise>} - */ - async fetch(options = {}) { - const encodedHeightResult = await this.storage.get( - LastSyncedCoreHeightRepository.TREE_PATH, - LastSyncedCoreHeightRepository.KEY, - { - ...options, - predictedValueSize: 4, - }, - ); - - if (encodedHeightResult.isNull()) { - return encodedHeightResult; - } - - const encodedHeight = encodedHeightResult.getValue(); - - return new StorageResult( - encodedHeight.readUInt32BE(), - encodedHeightResult.getOperations(), - ); - } -} - -LastSyncedCoreHeightRepository.TREE_PATH = [Buffer.from([112])]; -LastSyncedCoreHeightRepository.KEY = Buffer.from('lastSyncedCoreHeight'); - -module.exports = LastSyncedCoreHeightRepository; diff --git a/packages/js-drive/lib/identity/masternode/createMasternodeIdentityFactory.js b/packages/js-drive/lib/identity/masternode/createMasternodeIdentityFactory.js deleted file mode 100644 index 9a8b006618b..00000000000 --- a/packages/js-drive/lib/identity/masternode/createMasternodeIdentityFactory.js +++ /dev/null @@ -1,83 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const InvalidMasternodeIdentityError = require('./errors/InvalidMasternodeIdentityError'); - -/** - * @param {DashPlatformProtocol} dpp - * @param {IdentityStoreRepository} identityRepository - * @param {getWithdrawPubKeyTypeFromPayoutScript} getWithdrawPubKeyTypeFromPayoutScript - * @param {getPublicKeyFromPayoutScript} getPublicKeyFromPayoutScript - * @return {createMasternodeIdentity} - */ -function createMasternodeIdentityFactory( - dpp, - identityRepository, - // getWithdrawPubKeyTypeFromPayoutScript, - // getPublicKeyFromPayoutScript, -) { - /** - * @typedef createMasternodeIdentity - * @param {BlockInfo} blockInfo - * @param {Identifier} identifier - * @param {Buffer} pubKeyData - * @param {number} pubKeyType - * @param {Script} [payoutScript] - * @return {Promise} - */ - async function createMasternodeIdentity( - blockInfo, - identifier, - pubKeyData, - pubKeyType, - // payoutScript, - ) { - const publicKeys = [{ - id: 0, - type: pubKeyType, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: true, - // Copy data buffer - data: Buffer.from(pubKeyData), - }]; - - // TODO: Enable keys when we have support of non unique keys in DPP - // if (payoutScript) { - // const withdrawPubKeyType = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - // - // publicKeys.push({ - // id: 1, - // type: withdrawPubKeyType, - // purpose: IdentityPublicKey.PURPOSES.WITHDRAW, - // securityLevel: IdentityPublicKey.SECURITY_LEVELS.CRITICAL, - // readOnly: false, - // data: getPublicKeyFromPayoutScript(payoutScript, withdrawPubKeyType), - // }); - // } - - const identity = new Identity({ - protocolVersion: dpp.getProtocolVersion(), - id: identifier.toBuffer(), - publicKeys, - balance: 0, - revision: 0, - }); - - const validationResult = await dpp.identity.validate(identity); - if (!validationResult.isValid()) { - const validationError = validationResult.getFirstError(); - - throw new InvalidMasternodeIdentityError(validationError); - } - - await identityRepository.create(identity, blockInfo, { - useTransaction: true, - }); - - return identity; - } - - return createMasternodeIdentity; -} - -module.exports = createMasternodeIdentityFactory; diff --git a/packages/js-drive/lib/identity/masternode/createOperatorIdentifier.js b/packages/js-drive/lib/identity/masternode/createOperatorIdentifier.js deleted file mode 100644 index 4effefbf931..00000000000 --- a/packages/js-drive/lib/identity/masternode/createOperatorIdentifier.js +++ /dev/null @@ -1,20 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const { hash } = require('@dashevo/dpp/lib/util/hash'); - -/** - * @param {SimplifiedMNListEntry} smlEntry - */ -function createOperatorIdentifier(smlEntry) { - const operatorPubKey = Buffer.from(smlEntry.pubKeyOperator, 'hex'); - - return Identifier.from( - hash( - Buffer.concat([ - Buffer.from(smlEntry.proRegTxHash, 'hex'), - operatorPubKey, - ]), - ), - ); -} - -module.exports = createOperatorIdentifier; diff --git a/packages/js-drive/lib/identity/masternode/createRewardShareDocumentFactory.js b/packages/js-drive/lib/identity/masternode/createRewardShareDocumentFactory.js deleted file mode 100644 index d1462448dcc..00000000000 --- a/packages/js-drive/lib/identity/masternode/createRewardShareDocumentFactory.js +++ /dev/null @@ -1,88 +0,0 @@ -const { hash } = require('@dashevo/dpp/lib/util/hash'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); - -const MAX_DOCUMENTS = 16; - -/** - * @param {DashPlatformProtocol} dpp - * @param {DocumentRepository} documentRepository - * @return {createRewardShareDocument} - */ -function createRewardShareDocumentFactory( - dpp, - documentRepository, -) { - /** - * @typedef {createRewardShareDocument} - * @param {DataContract} dataContract - * @param {Identifier} masternodeIdentifier - * @param {Identifier} operatorIdentifier - * @param {number} percentage - * @param {BlockInfo} blockInfo - * @returns {Promise} - */ - async function createRewardShareDocument( - dataContract, - masternodeIdentifier, - operatorIdentifier, - percentage, - blockInfo, - ) { - const documentsResult = await documentRepository.find( - dataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', masternodeIdentifier.toBuffer()], - ], - useTransaction: true, - }, - ); - - // Do not create a share if it's exist already - // or max shares limit is reached - if (!documentsResult.isEmpty()) { - if (documentsResult.getValue().length > MAX_DOCUMENTS) { - return null; - } - - const operatorShare = documentsResult.getValue().find((shareDocument) => ( - shareDocument.get('payToId').equals(operatorIdentifier) - )); - - if (operatorShare) { - return null; - } - } - - const rewardShareDocument = dpp.document.create( - dataContract, - masternodeIdentifier, - 'rewardShare', - { - payToId: operatorIdentifier, - percentage, - }, - ); - - // Create an identity for operator - const rewardShareDocumentIdSeed = hash( - Buffer.concat([ - masternodeIdentifier.toBuffer(), - operatorIdentifier.toBuffer(), - ]), - ); - - rewardShareDocument.id = Identifier.from(rewardShareDocumentIdSeed); - - await documentRepository.create(rewardShareDocument, blockInfo, { - useTransaction: true, - }); - - return rewardShareDocument; - } - - return createRewardShareDocument; -} - -module.exports = createRewardShareDocumentFactory; diff --git a/packages/js-drive/lib/identity/masternode/createVotingIdentifier.js b/packages/js-drive/lib/identity/masternode/createVotingIdentifier.js deleted file mode 100644 index 69e61c89d2f..00000000000 --- a/packages/js-drive/lib/identity/masternode/createVotingIdentifier.js +++ /dev/null @@ -1,21 +0,0 @@ -const { hash } = require('@dashevo/dpp/lib/util/hash'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const Address = require('@dashevo/dashcore-lib/lib/address'); - -/** - * @param {SimplifiedMNListEntry} smlEntry - */ -function createVotingIdentifier(smlEntry) { - const votingPubKeyHash = Address.fromString(smlEntry.votingAddress).hashBuffer; - - return Identifier.from( - hash( - Buffer.concat([ - Buffer.from(smlEntry.proRegTxHash, 'hex'), - votingPubKeyHash, - ]), - ), - ); -} - -module.exports = createVotingIdentifier; diff --git a/packages/js-drive/lib/identity/masternode/errors/InvalidIdentityPublicKeyTypeError.js b/packages/js-drive/lib/identity/masternode/errors/InvalidIdentityPublicKeyTypeError.js deleted file mode 100644 index 59b2a671f58..00000000000 --- a/packages/js-drive/lib/identity/masternode/errors/InvalidIdentityPublicKeyTypeError.js +++ /dev/null @@ -1,22 +0,0 @@ -const DriveError = require('../../../errors/DriveError'); - -class InvalidIdentityPublicKeyTypeError extends DriveError { - /** - * @param {number} type - */ - constructor(type) { - super('Invalid Identity Public Key type'); - - this.type = type; - } - - /** - * - * @return {number} - */ - getType() { - return this.type; - } -} - -module.exports = InvalidIdentityPublicKeyTypeError; diff --git a/packages/js-drive/lib/identity/masternode/errors/InvalidMasternodeIdentityError.js b/packages/js-drive/lib/identity/masternode/errors/InvalidMasternodeIdentityError.js deleted file mode 100644 index ad1a8fe7ba7..00000000000 --- a/packages/js-drive/lib/identity/masternode/errors/InvalidMasternodeIdentityError.js +++ /dev/null @@ -1,23 +0,0 @@ -const DriveError = require('../../../errors/DriveError'); - -class InvalidMasternodeIdentityError extends DriveError { - /** - * @param {Error} validationError - */ - constructor(validationError) { - super('Invalid masternode identity'); - - this.validationError = validationError; - } - - /** - * Get validation error - * - * @return {Error} - */ - getValidationError() { - return this.validationError; - } -} - -module.exports = InvalidMasternodeIdentityError; diff --git a/packages/js-drive/lib/identity/masternode/errors/InvalidPayoutScriptError.js b/packages/js-drive/lib/identity/masternode/errors/InvalidPayoutScriptError.js deleted file mode 100644 index 2a224ff0661..00000000000 --- a/packages/js-drive/lib/identity/masternode/errors/InvalidPayoutScriptError.js +++ /dev/null @@ -1,22 +0,0 @@ -const DriveError = require('../../../errors/DriveError'); - -class InvalidPayoutScriptError extends DriveError { - /** - * @param {Buffer} payoutScript - */ - constructor(payoutScript) { - super('Invalid payout script'); - - this.payoutScript = payoutScript; - } - - /** - * - * @return {Buffer} - */ - getPayoutScript() { - return this.payoutScript; - } -} - -module.exports = InvalidPayoutScriptError; diff --git a/packages/js-drive/lib/identity/masternode/getPublicKeyFromPayoutScript.js b/packages/js-drive/lib/identity/masternode/getPublicKeyFromPayoutScript.js deleted file mode 100644 index e6dc34d4bd1..00000000000 --- a/packages/js-drive/lib/identity/masternode/getPublicKeyFromPayoutScript.js +++ /dev/null @@ -1,21 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const InvalidIdentityPublicKeyTypeError = require('@dashevo/dpp/lib/stateTransition/errors/InvalidIdentityPublicKeyTypeError'); - -/** - * @typedef getPublicKeyFromPayoutScript - * @param {Script} payoutScript - * @param {number} type - * @returns {Buffer} - */ -function getPublicKeyFromPayoutScript(payoutScript, type) { - switch (type) { - case IdentityPublicKey.TYPES.ECDSA_HASH160: - return payoutScript.toBuffer().slice(3, 23); - case IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH: - return payoutScript.toBuffer().slice(2, 22); - default: - throw new InvalidIdentityPublicKeyTypeError(type); - } -} - -module.exports = getPublicKeyFromPayoutScript; diff --git a/packages/js-drive/lib/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.js b/packages/js-drive/lib/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.js deleted file mode 100644 index 402fd45f45f..00000000000 --- a/packages/js-drive/lib/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.js +++ /dev/null @@ -1,38 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); - -const InvalidPayoutScriptError = require('./errors/InvalidPayoutScriptError'); - -/** - * - * @param {string} network - * @returns {getWithdrawPubKeyTypeFromPayoutScript} - */ -function getWithdrawPubKeyTypeFromPayoutScriptFactory(network) { - /** - * @typedef getWithdrawPubKeyTypeFromPayoutScript - * @param {Script} payoutScript - * @returns {number} - */ - function getWithdrawPubKeyTypeFromPayoutScript(payoutScript) { - const address = payoutScript.toAddress(network); - - if (address === false) { - throw new InvalidPayoutScriptError(payoutScript); - } - - let withdrawPubKeyType; - if (address.isPayToScriptHash()) { - withdrawPubKeyType = IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH; - } else if (address.isPayToPublicKeyHash()) { - withdrawPubKeyType = IdentityPublicKey.TYPES.ECDSA_HASH160; - } else { - throw new InvalidPayoutScriptError(payoutScript); - } - - return withdrawPubKeyType; - } - - return getWithdrawPubKeyTypeFromPayoutScript; -} - -module.exports = getWithdrawPubKeyTypeFromPayoutScriptFactory; diff --git a/packages/js-drive/lib/identity/masternode/handleNewMasternodeFactory.js b/packages/js-drive/lib/identity/masternode/handleNewMasternodeFactory.js deleted file mode 100644 index 8303b2ab78a..00000000000 --- a/packages/js-drive/lib/identity/masternode/handleNewMasternodeFactory.js +++ /dev/null @@ -1,128 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const createOperatorIdentifier = require('./createOperatorIdentifier'); -const createVotingIdentifier = require('./createVotingIdentifier'); - -/** - * - * @param {DashPlatformProtocol} transactionalDpp - * @param {createMasternodeIdentity} createMasternodeIdentity - * @param {createRewardShareDocument} createRewardShareDocument - * @param {fetchTransaction} fetchTransaction - * @return {handleNewMasternode} - */ -function handleNewMasternodeFactory( - transactionalDpp, - createMasternodeIdentity, - createRewardShareDocument, - fetchTransaction, -) { - /** - * @typedef handleNewMasternode - * @param {SimplifiedMNListEntry} masternodeEntry - * @param {DataContract} dataContract - * @param {BlockInfo} blockInfo - * @return {Promise<{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }>} - */ - async function handleNewMasternode(masternodeEntry, dataContract, blockInfo) { - const createdEntities = []; - - const { extraPayload: proRegTxPayload } = await fetchTransaction(masternodeEntry.proRegTxHash); - - const proRegTxHash = Buffer.from(masternodeEntry.proRegTxHash, 'hex'); - - let payoutScript; - - if (masternodeEntry.payoutAddress) { - const payoutAddress = Address.fromString(masternodeEntry.payoutAddress); - payoutScript = new Script(payoutAddress); - } - - // Create a masternode identity - const masternodeIdentifier = Identifier.from( - proRegTxHash, - ); - - const ownerPublicKeyHash = Buffer.from(proRegTxPayload.keyIDOwner, 'hex').reverse(); - - createdEntities.push( - await createMasternodeIdentity( - blockInfo, - masternodeIdentifier, - ownerPublicKeyHash, - IdentityPublicKey.TYPES.ECDSA_HASH160, - payoutScript, - ), - ); - - // we need to crate reward shares only if it's enabled in proRegTx - - if (proRegTxPayload.operatorReward > 0) { - const operatorPubKey = Buffer.from(masternodeEntry.pubKeyOperator, 'hex'); - - let operatorPayoutScript; - if (masternodeEntry.operatorPayoutAddress) { - const operatorPayoutAddress = Address.fromString(masternodeEntry.operatorPayoutAddress); - operatorPayoutScript = new Script(operatorPayoutAddress); - } - - const operatorIdentifier = createOperatorIdentifier(masternodeEntry); - - createdEntities.push( - await createMasternodeIdentity( - blockInfo, - operatorIdentifier, - operatorPubKey, - IdentityPublicKey.TYPES.BLS12_381, - operatorPayoutScript, - ), - ); - - // Create a document in rewards data contract with percentage - const rewardShareDocument = await createRewardShareDocument( - dataContract, - masternodeIdentifier, - operatorIdentifier, - proRegTxPayload.operatorReward, - blockInfo, - ); - - if (rewardShareDocument) { - createdEntities.push(rewardShareDocument); - } - } - - const votingPubKeyHash = Buffer.from(proRegTxPayload.keyIDVoting, 'hex').reverse(); - - // don't need to create a separate Identity in case we don't have - // voting public key (keyIDVoting === keyIDOwner) - if (!votingPubKeyHash.equals(ownerPublicKeyHash)) { - const votingIdentifier = createVotingIdentifier(masternodeEntry); - - createdEntities.push( - await createMasternodeIdentity( - blockInfo, - votingIdentifier, - votingPubKeyHash, - IdentityPublicKey.TYPES.ECDSA_HASH160, - ), - ); - } - - return { - createdEntities, - updatedEntities: [], - removedEntities: [], - }; - } - - return handleNewMasternode; -} - -module.exports = handleNewMasternodeFactory; diff --git a/packages/js-drive/lib/identity/masternode/handleRemovedMasternodeFactory.js b/packages/js-drive/lib/identity/masternode/handleRemovedMasternodeFactory.js deleted file mode 100644 index 97f298451a6..00000000000 --- a/packages/js-drive/lib/identity/masternode/handleRemovedMasternodeFactory.js +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @param {DocumentRepository} documentRepository - * - * @returns {handleRemovedMasternode} - */ -function handleRemovedMasternodeFactory( - documentRepository, -) { - /** - * @typedef {handleRemovedMasternode} - * - * @param {Identifier} masternodeIdentifier - * @param {DataContract} dataContract - * @param {BlockInfo} blockInfo - * @return {Promise<{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }>} - */ - async function handleRemovedMasternode(masternodeIdentifier, dataContract, blockInfo) { - // Delete documents belongs to masternode identity (ownerId) from rewards contract - // since max amount is 16, we can fetch all of them in one request - const removedEntities = []; - - const fetchedDocumentsResult = await documentRepository.find( - dataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', masternodeIdentifier], - ], - useTransaction: true, - }, - ); - - const documentsToDelete = fetchedDocumentsResult.getValue(); - - for (const document of documentsToDelete) { - await documentRepository.delete( - dataContract, - 'rewardShare', - document.getId(), - blockInfo, - { useTransaction: true }, - ); - - removedEntities.push( - document, - ); - } - - return { - createdEntities: [], - updatedEntities: [], - removedEntities, - }; - } - - return handleRemovedMasternode; -} - -module.exports = handleRemovedMasternodeFactory; diff --git a/packages/js-drive/lib/identity/masternode/handleUpdatedPubKeyOperatorFactory.js b/packages/js-drive/lib/identity/masternode/handleUpdatedPubKeyOperatorFactory.js deleted file mode 100644 index 663e990662b..00000000000 --- a/packages/js-drive/lib/identity/masternode/handleUpdatedPubKeyOperatorFactory.js +++ /dev/null @@ -1,145 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const createOperatorIdentifier = require('./createOperatorIdentifier'); - -/** - * - * @param {DashPlatformProtocol} transactionalDpp - * @param {createMasternodeIdentity} createMasternodeIdentity - * @param {Identifier} masternodeRewardSharesContractId - * @param {createRewardShareDocument} createRewardShareDocument - * @param {DocumentRepository} documentRepository - * @param {IdentityStoreRepository} identityRepository - * @param {fetchTransaction} fetchTransaction - * @return {handleUpdatedPubKeyOperator} - */ -function handleUpdatedPubKeyOperatorFactory( - transactionalDpp, - createMasternodeIdentity, - masternodeRewardSharesContractId, - createRewardShareDocument, - documentRepository, - identityRepository, - fetchTransaction, -) { - /** - * @typedef handleUpdatedPubKeyOperator - * @param {SimplifiedMNListEntry} masternodeEntry - * @param {SimplifiedMNListEntry} previousMasternodeEntry - * @param {DataContract} dataContract - * @param {BlockInfo} blockInfo - * @return Promise<{ - * createdEntities: Array, - * removedEntities: Array, - * }> - */ - async function handleUpdatedPubKeyOperator( - masternodeEntry, - previousMasternodeEntry, - dataContract, - blockInfo, - ) { - const createdEntities = []; - const removedEntities = []; - - const { extraPayload: proRegTxPayload } = await fetchTransaction(masternodeEntry.proRegTxHash); - - // we need to crate reward shares only if it's enabled in proRegTx - if (proRegTxPayload.operatorReward === 0) { - return { - createdEntities, - removedEntities, - }; - } - - const proRegTxHash = Buffer.from(masternodeEntry.proRegTxHash, 'hex'); - const operatorPublicKey = Buffer.from(masternodeEntry.pubKeyOperator, 'hex'); - - const operatorIdentifier = createOperatorIdentifier(masternodeEntry); - - const operatorIdentityResult = await identityRepository.fetch( - operatorIdentifier, - { useTransaction: true }, - ); - - let operatorPayoutPubKey; - if (masternodeEntry.operatorPayoutAddress) { - const operatorPayoutAddress = Address.fromString(masternodeEntry.operatorPayoutAddress); - operatorPayoutPubKey = new Script(operatorPayoutAddress); - } - - // Create an identity for operator if there is no identity exist with the same ID - if (operatorIdentityResult.isNull()) { - createdEntities.push( - await createMasternodeIdentity( - blockInfo, - operatorIdentifier, - operatorPublicKey, - IdentityPublicKey.TYPES.BLS12_381, - operatorPayoutPubKey, - ), - ); - } - - // Create a document in rewards data contract with percentage defined - // in corresponding ProRegTx - - const masternodeIdentifier = Identifier.from( - proRegTxHash, - ); - - const rewardShareDocument = await createRewardShareDocument( - dataContract, - masternodeIdentifier, - operatorIdentifier, - proRegTxPayload.operatorReward, - blockInfo, - ); - - if (rewardShareDocument) { - createdEntities.push(rewardShareDocument); - } - - // Delete document from reward shares data contract with ID corresponding to the - // masternode identity (ownerId) and previous operator identity (payToId) - - const previousOperatorIdentifier = createOperatorIdentifier(previousMasternodeEntry); - - const previousDocumentsResult = await documentRepository.find( - dataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', masternodeIdentifier], - ['payToId', '==', previousOperatorIdentifier], - ], - useTransaction: true, - }, - ); - - if (!previousDocumentsResult.isEmpty()) { - const [previousDocument] = previousDocumentsResult.getValue(); - - await documentRepository.delete( - dataContract, - 'rewardShare', - previousDocument.getId(), - blockInfo, - { useTransaction: true }, - ); - - removedEntities.push(previousDocument); - } - - return { - createdEntities, - removedEntities, - }; - } - - return handleUpdatedPubKeyOperator; -} - -module.exports = handleUpdatedPubKeyOperatorFactory; diff --git a/packages/js-drive/lib/identity/masternode/handleUpdatedScriptPayoutFactory.js b/packages/js-drive/lib/identity/masternode/handleUpdatedScriptPayoutFactory.js deleted file mode 100644 index 2d2fd03a103..00000000000 --- a/packages/js-drive/lib/identity/masternode/handleUpdatedScriptPayoutFactory.js +++ /dev/null @@ -1,117 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const identitySchema = require('@dashevo/dpp/schema/identity/identity.json'); - -/** - * - * @param {IdentityStoreRepository} identityRepository - * @param {IdentityPublicKeyStoreRepository} identityPublicKeyRepository - * @param {getWithdrawPubKeyTypeFromPayoutScript} getWithdrawPubKeyTypeFromPayoutScript - * @param {getPublicKeyFromPayoutScript} getPublicKeyFromPayoutScript - * @returns {handleUpdatedScriptPayout} - */ -function handleUpdatedScriptPayoutFactory( - identityRepository, - identityPublicKeyRepository, - getWithdrawPubKeyTypeFromPayoutScript, - getPublicKeyFromPayoutScript, -) { - /** - * @typedef handleUpdatedScriptPayout - * @param {Identifier} identityId - * @param {Script} newPayoutScript - * @param {BlockInfo} blockInfo - * @param {Script} [previousPayoutScript] - * @return {Promise<{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }>} - */ - async function handleUpdatedScriptPayout( - identityId, - newPayoutScript, - blockInfo, - previousPayoutScript, - ) { - const result = { - createdEntities: [], - updatedEntities: [], - removedEntities: [], - }; - - const identityResult = await identityRepository.fetch(identityId, { useTransaction: true }); - - const identity = identityResult.getValue(); - - const identityPublicKeys = identity - .getPublicKeys(); - - if (identityPublicKeys.length === identitySchema.properties.publicKeys.maxItems) { - // do not add new public key - return result; - } - - // disable previous - if (previousPayoutScript) { - const previousPubKeyType = getWithdrawPubKeyTypeFromPayoutScript(previousPayoutScript); - const previousPubKeyData = getPublicKeyFromPayoutScript( - previousPayoutScript, - previousPubKeyType, - ); - - const keyIds = identityPublicKeys - .filter((pk) => pk.getData().equals(previousPubKeyData)) - .map((pk) => pk.getId()); - - if (keyIds.length > 0) { - await identityPublicKeyRepository.disable( - identityId, - keyIds, - blockInfo.timeMs, - blockInfo, - { useTransaction: true }, - ); - - result.updatedEntities.push({ disabledKeys: keyIds }); - } - } - - // add new - const withdrawPubKeyType = getWithdrawPubKeyTypeFromPayoutScript(newPayoutScript); - const pubKeyData = getPublicKeyFromPayoutScript(newPayoutScript, withdrawPubKeyType); - - const newWithdrawalIdentityPublicKey = new IdentityPublicKey() - .setId(identity.getPublicKeyMaxId() + 1) - .setType(withdrawPubKeyType) - .setData(pubKeyData) - .setPurpose(IdentityPublicKey.PURPOSES.WITHDRAW) - .setReadOnly(true) - .setSecurityLevel(IdentityPublicKey.SECURITY_LEVELS.MASTER); - - await identityPublicKeyRepository.add( - identityId, - [newWithdrawalIdentityPublicKey], - blockInfo, - { useTransaction: true }, - ); - - result.createdEntities.push(newWithdrawalIdentityPublicKey); - - identity.setRevision(identity.getRevision() + 1); - - await identityRepository.updateRevision( - identityId, - identity.getRevision(), - blockInfo, - { useTransaction: true }, - ); - - result.updatedEntities.push(identity); - - return result; - } - - return handleUpdatedScriptPayout; -} - -module.exports = handleUpdatedScriptPayoutFactory; diff --git a/packages/js-drive/lib/identity/masternode/handleUpdatedVotingAddressFactory.js b/packages/js-drive/lib/identity/masternode/handleUpdatedVotingAddressFactory.js deleted file mode 100644 index b86e45db12e..00000000000 --- a/packages/js-drive/lib/identity/masternode/handleUpdatedVotingAddressFactory.js +++ /dev/null @@ -1,77 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const createVotingIdentifier = require('./createVotingIdentifier'); - -/** - * - * @param {IdentityStoreRepository} identityRepository - * @param {createMasternodeIdentity} createMasternodeIdentity - * @param {fetchTransaction} fetchTransaction - * @return {handleUpdatedVotingAddress} - */ -function handleUpdatedVotingAddressFactory( - identityRepository, - createMasternodeIdentity, - fetchTransaction, -) { - /** - * @typedef handleUpdatedVotingAddress - * @param {SimplifiedMNListEntry} masternodeEntry - * @param {BlockInfo} blockInfo - * @return {Promise<{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }>} - */ - async function handleUpdatedVotingAddress( - masternodeEntry, - blockInfo, - ) { - const result = { - createdEntities: [], - updatedEntities: [], - removedEntities: [], - }; - - const { extraPayload: proRegTxPayload } = await fetchTransaction(masternodeEntry.proRegTxHash); - - const ownerPublicKeyHash = Buffer.from(proRegTxPayload.keyIDOwner, 'hex').reverse(); - const votingPubKeyHash = Buffer.from(proRegTxPayload.keyIDVoting, 'hex').reverse(); - - // don't need to create a separate Identity in case we don't have - // public key used for proposal voting (keyIDVoting === keyIDOwner) - if (ownerPublicKeyHash.equals(votingPubKeyHash)) { - return result; - } - - // Create a voting identity if there is no identity exist with the same ID - const votingIdentifier = createVotingIdentifier(masternodeEntry); - - const votingIdentityResult = await identityRepository.fetch( - votingIdentifier, - { useTransaction: true }, - ); - - // Create an identity for operator if there is no identity exist with the same ID - if (votingIdentityResult.isNull()) { - const votingAddress = Address.fromString(masternodeEntry.votingAddress); - const votingPublicKeyHash = votingAddress.hashBuffer; - - result.createdEntities.push( - await createMasternodeIdentity( - blockInfo, - votingIdentifier, - votingPublicKeyHash, - IdentityPublicKey.TYPES.ECDSA_HASH160, - ), - ); - } - - return result; - } - - return handleUpdatedVotingAddress; -} - -module.exports = handleUpdatedVotingAddressFactory; diff --git a/packages/js-drive/lib/identity/masternode/synchronizeMasternodeIdentitiesFactory.js b/packages/js-drive/lib/identity/masternode/synchronizeMasternodeIdentitiesFactory.js deleted file mode 100644 index 0e288f59fe0..00000000000 --- a/packages/js-drive/lib/identity/masternode/synchronizeMasternodeIdentitiesFactory.js +++ /dev/null @@ -1,258 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const createOperatorIdentifier = require('./createOperatorIdentifier'); - -/** - * - * @param result {{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }} - * @param newData {{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }} - * @return {{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * }} - */ -function mergeEntities(result, newData) { - return { - ...result, - createdEntities: result.createdEntities.concat(newData.createdEntities), - updatedEntities: result.updatedEntities.concat(newData.updatedEntities), - removedEntities: result.removedEntities.concat(newData.removedEntities), - }; -} - -/** - * - * @param {DataContractStoreRepository} dataContractRepository - * @param {SimplifiedMasternodeList} simplifiedMasternodeList - * @param {Identifier} masternodeRewardSharesContractId - * @param {handleNewMasternode} handleNewMasternode - * @param {handleUpdatedPubKeyOperator} handleUpdatedPubKeyOperator - * @param {handleRemovedMasternode} handleRemovedMasternode - * @param {handleUpdatedScriptPayout} handleUpdatedScriptPayout - * @param {handleUpdatedVotingAddress} handleUpdatedVotingAddress - * @param {number} smlMaxListsLimit - * @param {LastSyncedCoreHeightRepository} lastSyncedCoreHeightRepository - * @param {fetchSimplifiedMNList} fetchSimplifiedMNList - * @return {synchronizeMasternodeIdentities} - */ -function synchronizeMasternodeIdentitiesFactory( - dataContractRepository, - simplifiedMasternodeList, - masternodeRewardSharesContractId, - handleNewMasternode, - handleUpdatedPubKeyOperator, - handleRemovedMasternode, - handleUpdatedScriptPayout, - handleUpdatedVotingAddress, - smlMaxListsLimit, - lastSyncedCoreHeightRepository, - fetchSimplifiedMNList, -) { - let lastSyncedCoreHeight = 0; - - /** - * @typedef synchronizeMasternodeIdentities - * @param {number} coreHeight - * @param {BlockInfo} blockInfo - * @return {Promise<{ - * createdEntities: Array, - * updatedEntities: Array, - * removedEntities: Array, - * fromHeight: number, - * toHeight: number, - * }>} - */ - async function synchronizeMasternodeIdentities(coreHeight, blockInfo) { - let result = { - createdEntities: [], - updatedEntities: [], - removedEntities: [], - }; - - if (!lastSyncedCoreHeight) { - const lastSyncedHeightResult = await lastSyncedCoreHeightRepository.fetch({ - useTransaction: true, - }); - - lastSyncedCoreHeight = lastSyncedHeightResult.getValue() || 0; - } - - let newMasternodes; - let previousMNList = []; - - const currentMNList = simplifiedMasternodeList.getStore() - .getSMLbyHeight(coreHeight) - .mnList; - - const dataContractResult = await dataContractRepository.fetch( - masternodeRewardSharesContractId, - { - useTransaction: true, - }, - ); - - const dataContract = dataContractResult.getValue(); - - if (lastSyncedCoreHeight === 0) { - // Create identities for all masternodes on the first sync - newMasternodes = currentMNList; - } else { - // simplifiedMasternodeList contains sml only for the last `smlMaxListsLimit` number of blocks - if (coreHeight - lastSyncedCoreHeight >= smlMaxListsLimit) { - // get diff directly from core - ({ mnList: previousMNList } = await fetchSimplifiedMNList(1, lastSyncedCoreHeight)); - } else { - previousMNList = simplifiedMasternodeList.getStore() - .getSMLbyHeight(lastSyncedCoreHeight) - .mnList; - } - - // Get the difference between last sync and requested core height - newMasternodes = currentMNList.filter((currentMnListEntry) => ( - !previousMNList.find((previousMnListEntry) => ( - previousMnListEntry.proRegTxHash === currentMnListEntry.proRegTxHash - )) - )); - - // Update operator identities (PubKeyOperator is changed) - for (const mnEntry of currentMNList) { - const previousMnEntry = previousMNList.find((previousMnListEntry) => ( - previousMnListEntry.proRegTxHash === mnEntry.proRegTxHash - && previousMnListEntry.pubKeyOperator !== mnEntry.pubKeyOperator - )); - - if (previousMnEntry) { - const affectedEntities = await handleUpdatedPubKeyOperator( - mnEntry, - previousMnEntry, - dataContract, - blockInfo, - ); - - result = mergeEntities(result, affectedEntities); - } - - const previousVotingMnEntry = previousMNList.find((previousMnListEntry) => ( - previousMnListEntry.proRegTxHash === mnEntry.proRegTxHash - && previousMnListEntry.votingAddress !== mnEntry.votingAddress - )); - - if (previousVotingMnEntry) { - const affectedEntities = await handleUpdatedVotingAddress( - mnEntry, - blockInfo, - ); - - result = mergeEntities(result, affectedEntities); - } - - if (mnEntry.payoutAddress) { - const mnEntryWithChangedPayoutAddress = previousMNList.find((previousMnListEntry) => ( - previousMnListEntry.proRegTxHash === mnEntry.proRegTxHash - && previousMnListEntry.payoutAddress !== mnEntry.payoutAddress - )); - - if (mnEntryWithChangedPayoutAddress) { - const newPayoutScript = new Script(Address.fromString(mnEntry.payoutAddress)); - const previousPayoutScript = mnEntryWithChangedPayoutAddress.payoutAddress - ? new Script(Address.fromString(mnEntryWithChangedPayoutAddress.payoutAddress)) - : undefined; - - const affectedEntities = await handleUpdatedScriptPayout( - Identifier.from(Buffer.from(mnEntry.proRegTxHash, 'hex')), - newPayoutScript, - blockInfo, - previousPayoutScript, - ); - - result = mergeEntities(result, affectedEntities); - } - } - - if (mnEntry.operatorPayoutAddress) { - const mnEntryWithChangedOperatorPayoutAddress = previousMNList - .find((previousMnListEntry) => ( - previousMnListEntry.proRegTxHash === mnEntry.proRegTxHash - && previousMnListEntry.operatorPayoutAddress !== mnEntry.operatorPayoutAddress - )); - - if (mnEntryWithChangedOperatorPayoutAddress) { - const newOperatorPayoutAddress = Address.fromString(mnEntry.operatorPayoutAddress); - - const { operatorPayoutAddress } = mnEntryWithChangedOperatorPayoutAddress; - - const previousOperatorPayoutScript = operatorPayoutAddress - ? new Script(Address.fromString(operatorPayoutAddress)) - : undefined; - - const affectedEntities = await handleUpdatedScriptPayout( - createOperatorIdentifier(mnEntry), - new Script(newOperatorPayoutAddress), - blockInfo, - previousOperatorPayoutScript, - ); - - result = mergeEntities(result, affectedEntities); - } - } - } - } - - // Create identities and shares for new masternodes - - for (const newMasternodeEntry of newMasternodes) { - const affectedEntities = await handleNewMasternode( - newMasternodeEntry, - dataContract, - blockInfo, - ); - - result = mergeEntities(result, affectedEntities); - } - - // Remove masternode reward shares for invalid/removed masternodes - - const disappearedOrInvalidMasterNodes = previousMNList - .filter((previousMnListEntry) => - // eslint-disable-next-line max-len,implicit-arrow-linebreak - (!currentMNList.find((currentMnListEntry) => currentMnListEntry.proRegTxHash === previousMnListEntry.proRegTxHash))) - .concat(currentMNList.filter((currentMnListEntry) => !currentMnListEntry.isValid)); - - for (const masternodeEntry of disappearedOrInvalidMasterNodes) { - const masternodeIdentifier = Identifier.from( - Buffer.from(masternodeEntry.proRegTxHash, 'hex'), - ); - - const affectedEntities = await handleRemovedMasternode( - masternodeIdentifier, - dataContract, - blockInfo, - ); - - result = mergeEntities(result, affectedEntities); - } - - result.fromHeight = lastSyncedCoreHeight; - result.toHeight = coreHeight; - - await lastSyncedCoreHeightRepository.store(coreHeight, { - useTransaction: true, - }); - - return result; - } - - return synchronizeMasternodeIdentities; -} - -module.exports = synchronizeMasternodeIdentitiesFactory; diff --git a/packages/js-drive/lib/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.js b/packages/js-drive/lib/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.js deleted file mode 100644 index abd8b2c562e..00000000000 --- a/packages/js-drive/lib/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.js +++ /dev/null @@ -1,76 +0,0 @@ -const WITHDRAWALS_DOCUMENT_TYPE = 'withdrawal'; - -const WITHDRAWALS_STATUS_POOLED = 1; -const WITHDRAWALS_STATUS_BROADCASTED = 2; - -/** - * @param {DocumentRepository} documentRepository - * @param {fetchDocuments} fetchDocuments - * @param {Identifier} withdrawalsContractId - * - * @returns {updateWithdrawalTransactionIdAndStatus} - */ -function updateWithdrawalTransactionIdAndStatusFactory( - documentRepository, - fetchDocuments, - withdrawalsContractId, -) { - /** - * Update withdrawal transactionId and set status to BROADCASTED - * - * @typedef updateWithdrawalTransactionIdAndStatus - * - * @param {BlockInfo} blockInfo - * @param {number} coreChainLockedHeight - * @param {Object} transactionIdMap - * @param {Object} options - * - * @returns {Promise} - */ - async function updateWithdrawalTransactionIdAndStatus( - blockInfo, - coreChainLockedHeight, - transactionIdMap, - options, - ) { - const originalTransactionIds = Object.keys(transactionIdMap).map((key) => Buffer.from(key, 'hex')); - - if (originalTransactionIds.length === 0) { - return; - } - - const fetchOptions = { - where: [ - ['status', '==', WITHDRAWALS_STATUS_POOLED], - ['transactionId', 'in', originalTransactionIds], - ], - orderBy: [ - ['transactionId', 'asc'], - ], - ...options, - }; - - const documents = await fetchDocuments( - withdrawalsContractId, - WITHDRAWALS_DOCUMENT_TYPE, - fetchOptions, - ); - - for (const document of documents) { - const originalTransactionIdHex = document.get('transactionId').toString('hex'); - - const updatedTransactionId = transactionIdMap[originalTransactionIdHex]; - - document.set('transactionId', updatedTransactionId); - document.set('transactionSignHeight', coreChainLockedHeight); - document.set('status', WITHDRAWALS_STATUS_BROADCASTED); - document.setRevision(document.getRevision() + 1); - - await documentRepository.update(document, blockInfo, options); - } - } - - return updateWithdrawalTransactionIdAndStatus; -} - -module.exports = updateWithdrawalTransactionIdAndStatusFactory; diff --git a/packages/js-drive/lib/storage/GroveDBStore.js b/packages/js-drive/lib/storage/GroveDBStore.js deleted file mode 100644 index 35a1eb474d9..00000000000 --- a/packages/js-drive/lib/storage/GroveDBStore.js +++ /dev/null @@ -1,519 +0,0 @@ -const { createHash } = require('crypto'); -const StorageResult = require('./StorageResult'); - -class GroveDBStore { - /** - * @param {Drive} rsDrive - * @param {Object} [logger] - */ - constructor(rsDrive, logger = undefined) { - this.rsDrive = rsDrive; - this.db = rsDrive.getGroveDB(); - this.logger = logger; - } - - /** - * Store a key - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Buffer} value - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.skipIfExists=false] - * - * @return {Promise>} - */ - async put(path, key, value, options = {}) { - const method = options.skipIfExists ? 'insertIfNotExists' : 'insert'; - - try { - await this.db[method]( - path, - key, - { - type: 'item', - value, - }, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - path: path.map((segment) => segment.toString('hex')), - pathHash: createHash('sha256') - .update( - path.reduce((segment, buffer) => Buffer.concat([segment, buffer]), Buffer.alloc(0)), - ).digest('hex'), - key: key.toString('hex'), - value: value.toString('hex'), - valueHash: createHash('sha256') - .update(value) - .digest('hex'), - useTransaction: Boolean(options.useTransaction), - type: 'item', - method, - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'put'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Store a reference to the specified key - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Buffer[]} referencePath - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.skipIfExists=false] - * @return {Promise>} - */ - async putReference(path, key, referencePath, options = {}) { - const method = options.skipIfExists ? 'insertIfNotExists' : 'insert'; - - try { - await this.db[method]( - path, - key, - { - type: 'reference', - value: { - type: 'absolutePathReference', - path: referencePath, - }, - }, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - path: path.map((segment) => segment.toString('hex')), - pathHash: createHash('sha256') - .update( - path.reduce((segment, buffer) => Buffer.concat([segment, buffer]), Buffer.alloc(0)), - ) - .digest('hex'), - key: key.toString('hex'), - value: referencePath.map((segment) => segment.toString('hex')), - valueHash: createHash('sha256') - .update( - referencePath.reduce((segment, buffer) => ( - Buffer.concat([segment, buffer]) - ), Buffer.alloc(0)), - ) - .digest('hex'), - useTransaction: Boolean(options.useTransaction), - type: 'reference', - method, - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'putReference'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Create empty key - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.skipIfExists=false] - * @return {Promise>} - */ - async createTree(path, key, options = { }) { - const method = options.skipIfExists ? 'insertIfNotExists' : 'insert'; - - try { - await this.db[method]( - path, - key, - { - type: 'tree', - }, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - path: path.map((segment) => segment.toString('hex')), - pathHash: createHash('sha256') - .update( - path.reduce((segment, buffer) => Buffer.concat([segment, buffer]), Buffer.alloc(0)), - ).digest('hex'), - key: key.toString('hex'), - value: Buffer.alloc(32).toString('hex'), - valueHash: createHash('sha256') - .update(Buffer.alloc(32)) - .digest('hex'), - useTransaction: Boolean(options.useTransaction), - type: 'tree', - method, - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'createTree'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Get a value by key - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {number} [options.predictedValueSize] - * @return {Promise>} - */ - async get(path, key, options = { }) { - let type; - let value; - - try { - ({ - type, - value, - } = await this.db.get( - path, - key, - options.useTransaction || false, - )); - } catch (e) { - if ( - e.message.startsWith('grovedb: path key not found') - || e.message.startsWith('grovedb: path not found') - ) { - return new StorageResult( - null, - [], - ); - } - - throw e; - } - - if (type === undefined) { - return new StorageResult( - null, - [], - ); - } - - if (type !== 'item') { - throw new Error('Key should point to item element type'); - } - - return new StorageResult( - value, - [], - ); - } - - /** - * Query keys and values - * - * @param {PathQuery} query - * @param {Object} [options] - * @param {boolean} [options.skipCache=false] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - */ - async query(query, options = { }) { - let items; - - try { - [items] = await this.db.query( - query, - options.skipCache || false, - options.useTransaction || false, - ); - } catch (e) { - if ( - e.message.startsWith('grovedb: path key not found') - || e.message.startsWith('grovedb: path not found') - ) { - return new StorageResult( - null, - [], - ); - } - - throw e; - } - - return new StorageResult( - items, - [], - ); - } - - /** - * Prove query - * - * @param {PathQuery} query - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - * */ - async proveQuery(query, options = {}) { - const proof = await this.db.proveQuery( - query, - options.useTransaction || false, - ); - - return new StorageResult( - proof, - [], - ); - } - - /** - * Prove many queries - * - * @param {PathQuery[]} queries - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - * */ - async proveQueryMany(queries, options = {}) { - const proof = await this.db.proveQueryMany( - queries, - options.useTransaction || false, - ); - - return new StorageResult( - proof, - [], - ); - } - - /** - * Delete value by key - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Promise>} - */ - async delete(path, key, options = {}) { - try { - await this.db.delete( - path, - key, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - path: path.map((segment) => segment.toString('hex')), - pathHash: createHash('sha256') - .update( - path.reduce((segment, buffer) => Buffer.concat([segment, buffer]), Buffer.alloc(0)), - ).digest('hex'), - key: key.toString('hex'), - useTransaction: Boolean(options.useTransaction), - method: 'delete', - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'delete'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Get auxiliary value by key - * - * @param {Buffer} key - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.predictedValueSize] - * @return {Promise>} - */ - async getAux(key, options = {}) { - let result = null; - - try { - result = await this.db.getAux( - key, - options.useTransaction || false, - ); - } catch (e) { - if (e.message.startsWith('grovedb: path key not found')) { - return new StorageResult( - null, - [], - ); - } - - throw e; - } - - return new StorageResult( - result, - [], - ); - } - - /** - * Store auxiliary value by key - * - * @param {Buffer} key - * @param {Buffer} value - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @return {Promise>} - */ - async putAux(key, value, options = {}) { - try { - await this.db.putAux( - key, - value, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - key: key.toString('hex'), - value: value.toString('hex'), - valueHash: createHash('sha256') - .update(value) - .digest('hex'), - useTransaction: Boolean(options.useTransaction), - method: 'putAux', - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'putAux'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Delete auxiliary value by key - * - * @param {Buffer} key - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @param {boolean} [options.dryRun=false] - * @return {Promise>} - */ - async deleteAux(key, options = {}) { - try { - await this.db.deleteAux( - key, - options.useTransaction || false, - ); - } finally { - if (this.logger) { - this.logger.info({ - key: key.toString('hex'), - useTransaction: Boolean(options.useTransaction), - method: 'deleteAux', - appHash: (await this.getRootHash(options)).toString('hex'), - }, 'deleteAux'); - } - } - - return new StorageResult( - undefined, - [], - ); - } - - /** - * Get tree root hash - * - * @param {Object} [options] - * @param {boolean} [options.useTransaction=false] - * @return {Buffer} - */ - async getRootHash(options = {}) { - return this.db.getRootHash(options.useTransaction || false); - } - - /** - * @return {Promise} - */ - async startTransaction() { - return this.db.startTransaction(); - } - - /** - * @return {Promise} - */ - async isTransactionStarted() { - return this.db.isTransactionStarted(); - } - - /** - * Rollback transaction to this initial state when it was created - * - * @returns {Promise} - */ - async rollbackTransaction() { - return this.db.rollbackTransaction(); - } - - /** - * @return {Promise} - */ - async commitTransaction() { - return this.db.commitTransaction(); - } - - /** - * @return {Promise} - */ - async abortTransaction() { - return this.db.abortTransaction(); - } - - /** - * @return {Drive} - */ - getDrive() { - return this.rsDrive; - } - - /** - * @returns {GroveDB} - */ - getDB() { - return this.db; - } - - /** - * @param {GroveDB} db - */ - setDB(db) { - this.db = db; - } -} - -module.exports = GroveDBStore; diff --git a/packages/js-drive/lib/storage/StorageResult.js b/packages/js-drive/lib/storage/StorageResult.js deleted file mode 100644 index fb548802ef5..00000000000 --- a/packages/js-drive/lib/storage/StorageResult.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @template T - */ -class StorageResult { - /** - * @type {T} - */ - #value; - - /** - * @type {AbstractOperation[]} - */ - #operations; - - /** - * @template T - * @param {T} value - * @param {AbstractOperation[]} operations - */ - constructor(value, operations = []) { - this.#value = value; - this.#operations = operations; - } - - /** - * @return {T} - */ - getValue() { - return this.#value; - } - - /** - * @param {T} value - */ - setValue(value) { - this.#value = value; - } - - /** - * @return {AbstractOperation[]} - */ - getOperations() { - return this.#operations; - } - - /** - * @return {boolean} - */ - isNull() { - return this.#value === null || this.#value === undefined; - } - - /** - * @return {boolean} - */ - isEmpty() { - return this.isNull() || (Array.isArray(this.#value) && this.#value.length === 0); - } - - /** - * @param {AbstractOperation} operation - */ - addOperation(...operation) { - this.#operations.push(...operation); - } -} - -module.exports = StorageResult; diff --git a/packages/js-drive/lib/test/.eslintrc b/packages/js-drive/lib/test/.eslintrc deleted file mode 100644 index 4c2b11fe817..00000000000 --- a/packages/js-drive/lib/test/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "env": { - "node": true, - "mocha": true - }, - "rules": { - "import/no-extraneous-dependencies": "off" - } -} diff --git a/packages/js-drive/lib/test/bootstrap.js b/packages/js-drive/lib/test/bootstrap.js deleted file mode 100644 index 2393794a2de..00000000000 --- a/packages/js-drive/lib/test/bootstrap.js +++ /dev/null @@ -1,78 +0,0 @@ -const path = require('path'); -const dotenvSafe = require('dotenv-safe'); -const dotenvExpand = require('dotenv-expand'); -const { expect, use } = require('chai'); -const sinon = require('sinon'); -const sinonChai = require('sinon-chai'); -const dirtyChai = require('dirty-chai'); -const chaiAsPromised = require('chai-as-promised'); -const chaiString = require('chai-string'); -const DashCoreOptions = require('@dashevo/dp-services-ctl/lib/services/dashCore/DashCoreOptions'); - -use(sinonChai); -use(chaiAsPromised); -use(chaiString); -use(dirtyChai); - -process.env.NODE_ENV = 'test'; - -// Workaround for dotenv-safe -if (process.env.INITIAL_CORE_CHAINLOCKED_HEIGHT === undefined) { - process.env.INITIAL_CORE_CHAINLOCKED_HEIGHT = 0; -} -if (process.env.DPNS_MASTER_PUBLIC_KEY === undefined) { - process.env.DPNS_MASTER_PUBLIC_KEY = '037d074eb00aa286c438b5d12b7c6ca25104d61b03e6601b6ace7d5eb036fbbc23'; -} -if (process.env.DPNS_SECOND_PUBLIC_KEY === undefined) { - process.env.DPNS_SECOND_PUBLIC_KEY = '025852df611a228b0e7fbccff4eaa117500ead84622809ea7fc05dcf6d2dbbc1d4'; -} -if (process.env.DASHPAY_MASTER_PUBLIC_KEY === undefined) { - process.env.DASHPAY_MASTER_PUBLIC_KEY = '02c571ff0cdb72634de4fd23f40c4ed530b3d31defc987a55479d65e7e8c1e249a'; -} -if (process.env.DASHPAY_SECOND_PUBLIC_KEY === undefined) { - process.env.DASHPAY_SECOND_PUBLIC_KEY = '03834f92a2132e55273cb713e855a6fbf2179704830c19094470720d6434ce4547'; -} -if (process.env.FEATURE_FLAGS_MASTER_PUBLIC_KEY === undefined) { - process.env.FEATURE_FLAGS_MASTER_PUBLIC_KEY = '022393486382a5bb262856c49f869827a1c79a3a3c38747f3cb8c32dd7bd191797'; -} -if (process.env.FEATURE_FLAGS_SECOND_PUBLIC_KEY === undefined) { - process.env.FEATURE_FLAGS_SECOND_PUBLIC_KEY = '03c10ac08a77dfdfcdc706ea43d9651ac0866181b835411587eca4d2d5477f39f7'; -} -if (process.env.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY === undefined) { - process.env.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY = '0333a42c628e8c93ce0386856f8f2239c84bf816cf8590716c7891fdc981a4df0b'; -} -if (process.env.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY === undefined) { - process.env.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY = '03a3002856ad91662dc34b6650a2c7f8b2726c947a419e0b880fb3acc38763a271'; -} -if (process.env.WITHDRAWALS_MASTER_PUBLIC_KEY === undefined) { - process.env.WITHDRAWALS_MASTER_PUBLIC_KEY = '02ee6d9b15ed1c310535297739e69973406dbd1a679be7fad2bdd2e08685033077'; -} -if (process.env.WITHDRAWALS_SECOND_PUBLIC_KEY === undefined) { - process.env.WITHDRAWALS_SECOND_PUBLIC_KEY = '02711ce1fedafde67694d771950c474fe300e464d4f67c2a6447f9b61e90fa01f3'; -} - -const dotenvConfig = dotenvSafe.config({ - path: path.resolve(__dirname, '..', '..', '.env'), -}); - -dotenvExpand(dotenvConfig); - -DashCoreOptions.setDefaultCustomOptions({ - container: { - image: 'dashpay/dashd:18.1.0-rc.1', - }, -}); - -beforeEach(function beforeEach() { - if (!this.sinon) { - this.sinon = sinon.createSandbox(); - } else { - this.sinon.restore(); - } -}); - -afterEach(function afterEach() { - this.sinon.restore(); -}); - -global.expect = expect; diff --git a/packages/js-drive/lib/test/createTestDIContainer.js b/packages/js-drive/lib/test/createTestDIContainer.js deleted file mode 100644 index ade6458f5e3..00000000000 --- a/packages/js-drive/lib/test/createTestDIContainer.js +++ /dev/null @@ -1,30 +0,0 @@ -const createDIContainer = require('../createDIContainer'); - -async function createTestDIContainer(dashCore = undefined) { - let coreOptions = {}; - if (dashCore) { - coreOptions = { - CORE_JSON_RPC_HOST: '127.0.0.1', - CORE_JSON_RPC_PORT: dashCore.options.getRpcPort(), - CORE_JSON_RPC_USERNAME: dashCore.options.getRpcUser(), - CORE_JSON_RPC_PASSWORD: dashCore.options.getRpcPassword(), - }; - } - - const container = createDIContainer({ - ...process.env, - GROVEDB_LATEST_FILE: './db/latest_state_test', - EXTERNAL_STORE_LEVEL_DB_FILE: './db/external_leveldb_test', - ...coreOptions, - }); - - const dpp = container.resolve('dpp'); - const transactionalDpp = container.resolve('transactionalDpp'); - - await dpp.initialize(); - await transactionalDpp.initialize(); - - return container; -} - -module.exports = createTestDIContainer; diff --git a/packages/js-drive/lib/test/fixtures/createDataContractDocuments.js b/packages/js-drive/lib/test/fixtures/createDataContractDocuments.js deleted file mode 100644 index 42aa2c7976c..00000000000 --- a/packages/js-drive/lib/test/fixtures/createDataContractDocuments.js +++ /dev/null @@ -1,28 +0,0 @@ -const dataContractMetaSchema = require('@dashevo/dpp/schema/dataContract/dataContractMeta.json'); -const createIndices = require('./createIndices'); -const createProperties = require('./createProperties'); - -/** - * - * @param {number} count - * @returns {Object} - */ -function createDataContractDocuments(count = 2) { - const documents = {}; - - for (let i = 0; i < count; i++) { - documents[`doc${i}`] = { - type: 'object', - indices: createIndices(dataContractMetaSchema.$defs.documentProperties.maxProperties, true), - properties: createProperties(dataContractMetaSchema.$defs.documentProperties.maxProperties, { - type: 'string', - maxLength: 63, - }), - additionalProperties: false, - }; - } - - return documents; -} - -module.exports = createDataContractDocuments; diff --git a/packages/js-drive/lib/test/fixtures/createIndices.js b/packages/js-drive/lib/test/fixtures/createIndices.js deleted file mode 100644 index 9cca689b728..00000000000 --- a/packages/js-drive/lib/test/fixtures/createIndices.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @param {number} count - * @param {boolean} [unique=false] - */ -function createIndices(count, unique = false) { - const indices = []; - - const indexCount = (count < 10 ? count : 10); - - let propertyIndex = 0; - - const basePropertyCount = Math.floor(count / indexCount); - const propertyLeftovers = count % indexCount; - - for (let i = 0; i < indexCount; i++) { - const properties = []; - - for (let x = 0; x < basePropertyCount + ((i < propertyLeftovers) ? 1 : 0); x++) { - const name = `property${propertyIndex}`; - - propertyIndex++; - - properties.push({ [name]: 'asc' }); - } - - indices.push({ - name: `index${i}`, - properties, - unique: unique && i < 3, - }); - } - - return indices; -} - -module.exports = createIndices; diff --git a/packages/js-drive/lib/test/fixtures/createProperties.js b/packages/js-drive/lib/test/fixtures/createProperties.js deleted file mode 100644 index 11ba4876908..00000000000 --- a/packages/js-drive/lib/test/fixtures/createProperties.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * @param {number} count - * @param {Object} subSchema - */ -function createProperties(count, subSchema) { - const properties = {}; - - for (let i = 0; i < count; i++) { - const name = `property${i}`; - - properties[name] = subSchema; - } - - return properties; -} - -module.exports = createProperties; diff --git a/packages/js-drive/lib/test/fixtures/getBlockExecutionContextObjectFixture.js b/packages/js-drive/lib/test/fixtures/getBlockExecutionContextObjectFixture.js deleted file mode 100644 index ada7cbc0d35..00000000000 --- a/packages/js-drive/lib/test/fixtures/getBlockExecutionContextObjectFixture.js +++ /dev/null @@ -1,90 +0,0 @@ -const { - tendermint: { - abci: { - CommitInfo, - ValidatorSetUpdate, - }, - types: { - ConsensusParams, - }, - }, -} = require('@dashevo/abci/types'); - -const pino = require('pino'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const { hash } = require('@dashevo/dpp/lib/util/hash'); - -/** - * @param {DataContract} [dataContract] - * @return {{ - * dataContracts: Object[], - * lastCommitInfo, - * coreChainLockedHeight: number, - * height: number, - * version: number, - * timeMs: number, - * validTxs: number, - * contextLogger: Logger, - * withdrawalTransactionsMap: Object, - * round: number, - * }} - */ -function getBlockExecutionContextObjectFixture(dataContract = getDataContractFixture()) { - const lastCommitInfo = new CommitInfo({ - quorumHash: Buffer.from('000003c60ecd9576a05a7e15d93baae18729cb4477d44246093bd2cf8d4f53d8', 'hex'), - blockSignature: Buffer.from('003657bb44d74c371d14485117de43313ca5c2848f3622d691c2b1bf3576a64bdc2538efab24854eb82ae7db38482dbd15a1cb3bc98e55173817c9d05c86e47a5d67614a501414aae6dd1565e59422d1d77c41ae9b38de34ecf1e9f778b2a97b', 'hex'), - }); - - const version = { - app: '1', - block: '2', - }; - - const [txOneBytes, txTwoBytes] = [ - Buffer.alloc(32, 0), - Buffer.alloc(32, 1), - ]; - - return { - dataContracts: [dataContract.toObject()], - lastCommitInfo: CommitInfo.toObject(lastCommitInfo), - height: 10, - proposedAppVersion: 42, - coreChainLockedHeight: 10, - version, - contextLogger: pino(), - epochInfo: { - height: 1, - timeMs: 100, - epoch: 0, - }, - timeMs: Date.now(), - withdrawalTransactionsMap: { - [hash(txOneBytes).toString('hex')]: txOneBytes, - [hash(txTwoBytes).toString('hex')]: txTwoBytes, - }, - round: 42, - prepareProposalResult: { - appHash: Buffer.alloc(32, 3), - txResults: new Array(3).fill({ code: 0 }), - consensusParamUpdates: new ConsensusParams({ - block: { - maxBytes: 1, - maxGas: 2, - }, - evidence: { - maxAgeDuration: null, - maxAgeNumBlocks: 1, - maxBytes: 2, - }, - version: { - appVersion: 1, - }, - }), - validatorSetUpdate: new ValidatorSetUpdate(), - }, - }; -} - -module.exports = getBlockExecutionContextObjectFixture; diff --git a/packages/js-drive/lib/test/fixtures/getSmlFixture.js b/packages/js-drive/lib/test/fixtures/getSmlFixture.js deleted file mode 100644 index 8fed978d62e..00000000000 --- a/packages/js-drive/lib/test/fixtures/getSmlFixture.js +++ /dev/null @@ -1,87 +0,0 @@ -module.exports = function getSmlFixture() { - return [ - { - baseBlockHash: '36d8cdedb8b2a0a8e893a26cbfd2234fb7eb3deee722f12f9f22605fba5bca91', - blockHash: '12d4bffbb6323da88ac6d35d742e33dec01d7f324dd44a5c5758cbf64d3ef024', - cbTxMerkleTree: '0100000001100322c9aa95701ed2b345e2a65e42d50e126ee6e6d2e2d7e4480140ab259bf40101', - cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05029b040101ffffffff02aa8b4e1e030000001976a914331d5c5153b6599e256c61fc1da7905b43fbbd6788aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac000000004602009b040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', - deletedMNs: [], - mnList: [{ - proRegTxHash: 'f5ec54aed788c434da2fc535ea6b125ec6fc54e58bc0a00a005d1a8d5e477a90', confirmedHash: '53125505b0e9d11b371cf3e12c92d164296dfa215fde6201d28ea44bed992187', service: '192.168.65.2:20101', pubKeyOperator: '951a3208ba531ea75aedd2dc0a9efc75f2c4d9492f1ee0a989b593bcd9722b1a101774d80a426552a9f91d24eb55af6e', votingAddress: 'yYH1rgZsgvkmT8bSSSw1cKCjyVPnFpTBCw', isValid: true, nVersion: 2, nType: 0, payoutAddress: 'yZv7wf496sjqJVgnEUAtYKozWQhVpoHRh9', - }, { - proRegTxHash: 'a2c9b34ef525271d84f70a0d4d2c107e8a2f81cd4d8256dc7b3911ed253d5611', confirmedHash: '29ff8afb463604ba7d984b483e92dfefa4e80e12de3acae6d75f9b910df9eab6', service: '192.168.65.2:20201', pubKeyOperator: 'a5ad6d8cad7b233210b718a5fc9ec3cea18aeebe38b2e3122deb581e430aa28875fe7336c283871db42808f8d4107745', votingAddress: 'yRXtaRmQ7LCmT5XcgzQdLwPEf31dycBaeY', isValid: true, nVersion: 2, nType: 0, payoutAddress: 'yiBP17AgHGit2TE9p9FpHEh4ouowNSxMxg', - }, { - proRegTxHash: '1c81a5faa2c0e0d96eb59c58a10fcbc87f431bb6cd880d960b43b269e682d2d2', confirmedHash: '03cc2acc135ab51304d3cff42215c7a8041902fa3f19451d5562a03b38143e8f', service: '192.168.65.2:20001', pubKeyOperator: '96f83eedc8a7b87663e591987f051ce341a6fb88989322c64bbbf56d205e4e77d2cb7d839d8b4106a8a1f5d5cf7cfa57', votingAddress: 'ybJfuKs59MJWkPEnS8qNmtvdisHrCy7Njn', isValid: true, nVersion: 2, nType: 0, payoutAddress: 'yd3AnRA5YRtN1jsv7jqUK8egA6Mk9e8HoS', - }], - nVersion: 2, - deletedQuorums: [], - newQuorums: [], - merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', - merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '12d4bffbb6323da88ac6d35d742e33dec01d7f324dd44a5c5758cbf64d3ef024', blockHash: '4fa3b35537280a5ff0f8adbc966960bb0cd95ecb4782444ec9f9b62d72afd571', cbTxMerkleTree: '01000000010cc244c3b969a94ab809d87c2f31c9d9feeae5798a4afcd80191f605580367770101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05029c040101ffffffff02aa8b4e1e030000001976a91419dbb5e39a9c9bce01849dbbf4193929506e0f4588aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac000000004602009c040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '4fa3b35537280a5ff0f8adbc966960bb0cd95ecb4782444ec9f9b62d72afd571', blockHash: '62ec67e46a2c9710381e28f34c9c7f6605766b394cef156643ea906bb3b6701a', cbTxMerkleTree: '0100000001979a5826b0065b8dee4632c7f1d45c862c302d339e11656d58bdfc17b62b966e0101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05029d040101ffffffff02aa8b4e1e030000001976a914fbbc45c3fdbd26d51f8558f152b6f772d3260a7488aca28b4e1e030000001976a9149528697532e5e020c44aebaa1b6d0b66e239b3fe88ac000000004602009d040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '62ec67e46a2c9710381e28f34c9c7f6605766b394cef156643ea906bb3b6701a', blockHash: '0b00be86c561b54e4dfc661815ed107627fd7f29693b2a46f8c769c3504c16f1', cbTxMerkleTree: '01000000015d6ccc29f288527e8c800218385587382e2216fd2508058fb6e98fca91e08e6f0101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05029e040101ffffffff02aa8b4e1e030000001976a9142cb7b39eabcf81b31457806c9499a2d596f8a55788aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac000000004602009e040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '0b00be86c561b54e4dfc661815ed107627fd7f29693b2a46f8c769c3504c16f1', blockHash: '42adcd0b2b330c842754489a9f6cb1a0d1dcc6113229b14574696c5b87e6debe', cbTxMerkleTree: '0100000001ded16207cc61edee7129967c8ecf22de5de9c4035c63f72bf6582ff6aaa70c0e0101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05029f040101ffffffff02aa8b4e1e030000001976a914b87e86cab49d5ce4c6f2e3927f1f46acc2b0391188aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac000000004602009f040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '42adcd0b2b330c842754489a9f6cb1a0d1dcc6113229b14574696c5b87e6debe', blockHash: '22f50323777d6544e614ccd3bd7c4c52122974cf9fa34bf9330ddca7b76ded37', cbTxMerkleTree: '0100000001f09a49ac7c163ee6d92aee33d675665ef0f720720b5c84559ed1875ed99f5fc00101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a0040101ffffffff02aa8b4e1e030000001976a91405f5fd0cc306a3a826bd58b379429c44eb44b47c88aca28b4e1e030000001976a9149528697532e5e020c44aebaa1b6d0b66e239b3fe88ac00000000460200a0040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '22f50323777d6544e614ccd3bd7c4c52122974cf9fa34bf9330ddca7b76ded37', blockHash: '2ec79cb473fd23457f284c7635264cf5b4df7d6d232357f280a728c5beb28484', cbTxMerkleTree: '01000000014421d1126fef6d6dc7ba20db021397c73f5b702654b50fa6acc0c38712b799db0101', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a1040101ffffffff02aa8b4e1e030000001976a9143f17462c6fd90af0e1fb5dd53e404ded6f4c09a688aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac00000000460200a1040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '2ec79cb473fd23457f284c7635264cf5b4df7d6d232357f280a728c5beb28484', blockHash: '2482fb1720e54dea0243b7797ce5c3c44eb5ab9827916a97f6960e34210d4dc9', cbTxMerkleTree: '0500000004a6b029eb4dfa6fc655e0680e1e997e54fad8670ea332b7257118c7e960e5060ce2f09f1b5015b4eed4884246004df64d3f6d5fff1191b460a56801294036197bc9d3da79f4768cdb70282d9f96b82c345a082eb84229d4d3bd2fedb428770496d663ddda0ccd66f5cdd47a51403fe89c1d06982401c05c3c021c85995301e243010f', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a2040101ffffffff02aa8b4e1e030000001976a914d6dc361352264c01c1d439dab42cf67896971ced88aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac00000000460200a2040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e80000000000000000000000000000000000000000000000000000000000000000', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }, - { - baseBlockHash: '2482fb1720e54dea0243b7797ce5c3c44eb5ab9827916a97f6960e34210d4dc9', - blockHash: '52422c1f4ead389b73ca34fb786fab4c22663ef015e766010b635a99de993770', - cbTxMerkleTree: '0500000004bba36da8fd518b33d346625d330a924616b19ecf452f69bf200a4a7313299061a90f2604811e6794cace64f71ec8e5e11ad2e033272cfbbfb43c0fb522476148d5d2f1559de709b3e97569cb405476f46950bdc64dc7280d1734f0e0398f6002b3bd98c64208dc0cb3546e878e15e875f82a641c86cdf5a0fbe5d1146b90d767010f', - cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a3040101ffffffff02aa8b4e1e030000001976a91409bba8d0a9569d1332a98dcbecf1719165b01f1788aca28b4e1e030000001976a9149528697532e5e020c44aebaa1b6d0b66e239b3fe88ac00000000460200a3040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', - deletedMNs: [], - mnList: [], - nVersion: 2, - deletedQuorums: [], - newQuorums: [{ - version: 3, llmqType: 100, quorumHash: '53834140bf3774419d424b88de6e9d6e7bcea9e0b59c03110b561b8622a15f71', quorumIndex: 0, signersCount: 3, signers: '07', validMembersCount: 3, validMembers: '07', quorumPublicKey: '94ef4696184537701850d5b5ccc6d1e253cce668680327bea7329feb63f0de8db0cd85708f10cdeda33aaf17362a71a3', quorumVvecHash: 'e899b8cd254edc2389a40c114a5a75920e16e8ad29dc5da0a3cb1e228180ec4b', quorumSig: '936f0db22feee7e72d7a130635d25e64b1300595ff335b88b330271abc74c789f92248c26a9fef696e1eac72da7ac4f90620aa7aaadfdd0b4e923d1cc6dcc1aff99f8cd456e84fe2405bad614b79d9230f0f7df39f7d63e283443a2b734e0672', membersSig: '93970da789c60a2c070be0a57d7e25e29eff943581be9967aaa81d544f9ded4512182b03664a407b05de3a682c27b9a305499618bee7550329612a05aeddb591854b03fb23203d8ef1afbd9bb2ce3f874a8afa77ca69a12b4bc77d8d0e4d936f', - }, { - version: 3, llmqType: 102, quorumHash: '53834140bf3774419d424b88de6e9d6e7bcea9e0b59c03110b561b8622a15f71', quorumIndex: 0, signersCount: 3, signers: '07', validMembersCount: 3, validMembers: '07', quorumPublicKey: '902f14411145221b2c7333c9ea5b24b02771583b571b32496251b87cbf9f4421c50c7608d785ceae0e8e8774befb1bbe', quorumVvecHash: '1ff155a5a27490d92db5fba42bfaf8bfd0b73d651d80f19b76a1d1377f9901ab', quorumSig: 'a2cdd139c6a0be507f04712a1a38bc76942b8b8631ede0fa8797156576c4a82016316b5ed3ed8042dc1f77971f305f7306ad7333c761d9f3d4471a27ce964dd0ef66b8591b3f406eda25745466c31b9feb5a52e2fd3ee124142bc96579c1a853', membersSig: 'a9118d64f72443d525de207e64bcc02b1d26961de73f89a052c5c01d8fbfab18fecb29b9f714722c1eb4e61b3e58133507d5a065534a82df16dbd917ccad1b2c1175026a242a44f69713f5a9a5ef0b10956272a1b17880c7d1173e47e068f352', - }, { - version: 3, llmqType: 104, quorumHash: '53834140bf3774419d424b88de6e9d6e7bcea9e0b59c03110b561b8622a15f71', quorumIndex: 0, signersCount: 3, signers: '07', validMembersCount: 3, validMembers: '07', quorumPublicKey: 'aa1067497034c595f85f783a69be6d9bb1a139555e990ee6f60ddb2886ae52bff2c90f2669ea254204011940b8da92d3', quorumVvecHash: '79ac426c3cac22d0a8790df583424a319064f778df47bcedae9aa8cd00c09819', quorumSig: '97283c23faac0939a06ee1b959fe913eab816c3e1d924798ecf23094a1b711c7e8dd129e1ea082f995d40aa63d1eb7431402c306bc7d8a86105bbf07b6228f8c5ab76cab52c18a5c0d91d673afae199ca10e7dbb4f513bf47551f4b6d7e9a484', membersSig: 'b6712c9db9694da6986edd2c89b9ee912c08a06fad9ced811aae536f37eacf3196891ef9a0b319c0d27948b84cf42da00006a74daefb05e5b17995f2784f9ba2ceeedf9cbc205971d1d64401258cf9050da70d16af0533e9398188287e3dd165', - }], - merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', - merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '52422c1f4ead389b73ca34fb786fab4c22663ef015e766010b635a99de993770', blockHash: '401f9127185c81245d92ae9e93b2fc571e99bcdaf89404c61e1a918729a16a1f', cbTxMerkleTree: '04000000034bbfebdc0500a6403256d717c3d26c56334bd70175bf1c05675a247865bed851e277025a4cfb9b398ffaa5e7736d30bca29fae3cebf839d1ac94001f056b87f9d59d34522656a8ee3b2f4f0c7ee52d34f9c143665193bf3cd0ec6266945eb9d00107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a4040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac00000000460200a4040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '401f9127185c81245d92ae9e93b2fc571e99bcdaf89404c61e1a918729a16a1f', blockHash: '7618f37265698bac8944b075e259974e10844d4e03f8febc5d19c663369e27d4', cbTxMerkleTree: '0400000003e4c7d33cbf8f3577d7154391b4dbb7bf606202d97d2a7c119e61808f5274b0af8fcc5f70790cd0c9a2e3803fcbd368e80352f9a2dae07c6d91c98e29809c42b2d9cecbf65eadcd9d1c573181852bcbf5e2d54e166bc0a269585b776c4cdc129f0107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a5040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac00000000460200a5040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '7618f37265698bac8944b075e259974e10844d4e03f8febc5d19c663369e27d4', blockHash: '5c5a00c6bdfcbdfbf6d8bf97de5b3364701c2f7bbd62ea5a84611e746d662e85', cbTxMerkleTree: '0400000003631e7d56314d01d605f57a231fdc5c45ec8d41f9efa917426fae8da5891a34fd6189bf0e09922b2b865c5b520cd5bbb32530955d08b598d9c8776e213f66b5ad8c478bf186219418a2110f1ee300c2397559b9a2907aac8521653733b745fa2b0107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a6040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a9149528697532e5e020c44aebaa1b6d0b66e239b3fe88ac00000000460200a6040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '5c5a00c6bdfcbdfbf6d8bf97de5b3364701c2f7bbd62ea5a84611e746d662e85', blockHash: '1d86bfae61ae28380425327fda49aed105dabe1a584bf31b9e2fa18af5e63c05', cbTxMerkleTree: '040000000343017a1282bb74dc8078da1f458d7bb9c94c9f14c80c83edcbef02a782409c23d8d4eb59d1a3ce68f2fa3ea0bac2d4635db38a68f2582c409a1f161d7ff046dfc1b9c42b11a3f8d1a48e67a6f838de7a0a66cfcf5e01eeb249137b1385088f3d0107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a7040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac00000000460200a7040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '1d86bfae61ae28380425327fda49aed105dabe1a584bf31b9e2fa18af5e63c05', blockHash: '0ac9982e6cb21e568d409e0f52e45c74b174c9d6bc8866b07697fc55389332c4', cbTxMerkleTree: '04000000032e6d48f3ef9588579cc73bf48349f81423856314d31a37be9db34ca9b524c41fe8ec194cbf921e081bb9ece166ab9fe2d468eb52b913b030d24a51d8bfdba77834cf47adc014dd341f21d46aa7d527468d87e1a266ed9e3ed8609ac6d41c66120107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a8040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac00000000460200a8040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '0ac9982e6cb21e568d409e0f52e45c74b174c9d6bc8866b07697fc55389332c4', blockHash: '3bb27b4b4426019de01af80efdc751b8060a6fefbfadc4c9ccd8dac1b64a3740', cbTxMerkleTree: '04000000032a2da104b6d7ee01cccd5c91ec10d0714db0f0c2783dfd27a5ca51dbdbf58ee76d923b90c571ef8affe8228cba4ad7260753a43e7ce6089082dac63dca3b178a2b99e5f5aca8ffa045fd0d4ec5ee6fff3b77a07842681639222a02ae6c0aec990107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502a9040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a9149528697532e5e020c44aebaa1b6d0b66e239b3fe88ac00000000460200a9040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '3bb27b4b4426019de01af80efdc751b8060a6fefbfadc4c9ccd8dac1b64a3740', blockHash: '78a209f1187ddd2a9c674831be1dd024f7a61ea3ba48a48eac5b142f23193476', cbTxMerkleTree: '040000000355777cf283c0254f0171448b13c210bb0fea0bbfbf5158d19408aa093ccf71efbc30690a8d7d5ad9ad6bf34b5e71a3c66bd0e26b4e61b0817fd8783c258103074e129ef70b857be58c4dcef5bef8dae4b04c161553ad4c277d2c50219a3b3f970107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502aa040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914b7661283b68f07579114ac58aad96345acaaf2b488ac00000000460200aa040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - { - baseBlockHash: '78a209f1187ddd2a9c674831be1dd024f7a61ea3ba48a48eac5b142f23193476', blockHash: '48302f2c3d408228bf155b83600fac1e8e10a0f1b1b672116a0519c73807ddb2', cbTxMerkleTree: '030000000346ced9f4fd1379736bf9f20eec8b4b95d64227810da7fdee8ffe61b1fc62c7bbf0fbe0b62e41650587c00f65bc38d2ac2dc0724c7acf476b1148af625fde735bbc0eeae765e610a5808a88bf4ae18b8ad1318c0262e3f7edfcfd4ae76afd14290107', cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502ab040101ffffffff02aa8b4e1e030000001976a914e826d8130e37c9fc09641ee95f7255786c34234188aca28b4e1e030000001976a914efcc3a89faf4df61f3ba4f65f2e742a6c6e3453088ac00000000460200ab040000471ac09f6c873ae56b9e49de07efaf3f7b46fecbf64ba01eff65c3c3d755a4e82302877d6dd07fc54bf2f8c160ee1d74b37c7b4d866d674c097c4eddb6db6775', deletedMNs: [], mnList: [], nVersion: 2, deletedQuorums: [], newQuorums: [], merkleRootMNList: 'e8a455d7c3c365ff1ea04bf6cbfe467b3fafef07de499e6be53a876c9fc01a47', merkleRootQuorums: '7567dbb6dd4e7c094c676d864d7b7cb3741dee60c1f8f24bc57fd06d7d870223', - }, - ]; -}; diff --git a/packages/js-drive/lib/test/fixtures/getSystemIdentityPublicKeysFixture.js b/packages/js-drive/lib/test/fixtures/getSystemIdentityPublicKeysFixture.js deleted file mode 100644 index 16b1d1557a5..00000000000 --- a/packages/js-drive/lib/test/fixtures/getSystemIdentityPublicKeysFixture.js +++ /dev/null @@ -1,28 +0,0 @@ -const { PublicKey } = require('@dashevo/dashcore-lib'); - -function getSystemIdentityPublicKeysFixture() { - return { - masternodeRewardSharesContractOwner: { - master: new PublicKey(process.env.MASTERNODE_REWARD_SHARES_MASTER_PUBLIC_KEY).toBuffer(), - high: new PublicKey(process.env.MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY).toBuffer(), - }, - featureFlagsContractOwner: { - master: new PublicKey(process.env.FEATURE_FLAGS_MASTER_PUBLIC_KEY).toBuffer(), - high: new PublicKey(process.env.FEATURE_FLAGS_SECOND_PUBLIC_KEY).toBuffer(), - }, - dpnsContractOwner: { - master: new PublicKey(process.env.DPNS_MASTER_PUBLIC_KEY).toBuffer(), - high: new PublicKey(process.env.DPNS_SECOND_PUBLIC_KEY).toBuffer(), - }, - withdrawalsContractOwner: { - master: new PublicKey(process.env.WITHDRAWALS_MASTER_PUBLIC_KEY).toBuffer(), - high: new PublicKey(process.env.WITHDRAWALS_SECOND_PUBLIC_KEY).toBuffer(), - }, - dashpayContractOwner: { - master: new PublicKey(process.env.DASHPAY_MASTER_PUBLIC_KEY).toBuffer(), - high: new PublicKey(process.env.DASHPAY_SECOND_PUBLIC_KEY).toBuffer(), - }, - }; -} - -module.exports = getSystemIdentityPublicKeysFixture; diff --git a/packages/js-drive/lib/test/mock/BlockExecutionContextMock.js b/packages/js-drive/lib/test/mock/BlockExecutionContextMock.js deleted file mode 100644 index f35a0e7553a..00000000000 --- a/packages/js-drive/lib/test/mock/BlockExecutionContextMock.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @method addDataContract - * @method hasDataContract - * @method getDataContracts - * @method reset - * @method setHeight - * @method getHeight - * @method setVersion - * @method getVersion - * @method setProposedAppVersion - * @method getProposedAppVersion - * @method setLastCommitInfo - * @method getLastCommitInfo - * @method getValidTxCount - * @method getInvalidTxCount - * @method setContextLogger - * @method getContextLogger - * @method getRound - * @method fromObject - * @method toObject - * @method getEpochInfo - * @method setEpochInfo - * @method setTimeMs - * @method getTimeMs - * @method getRound - * @method setRound - */ -class BlockExecutionContextMock { - /** - * @param {SinonSandbox} sinon - */ - constructor(sinon) { - this.addDataContract = sinon.stub(); - this.hasDataContract = sinon.stub(); - this.getDataContracts = sinon.stub(); - this.setCoreChainLockedHeight = sinon.stub(); - this.getCoreChainLockedHeight = sinon.stub(); - this.setHeight = sinon.stub(); - this.getHeight = sinon.stub(); - this.reset = sinon.stub(); - this.setVersion = sinon.stub(); - this.getVersion = sinon.stub(); - this.setProposedAppVersion = sinon.stub(); - this.getProposedAppVersion = sinon.stub(); - this.setLastCommitInfo = sinon.stub(); - this.getLastCommitInfo = sinon.stub(); - this.setContextLogger = sinon.stub(); - this.getContextLogger = sinon.stub(); - this.setWithdrawalTransactionsMap = sinon.stub(); - this.getWithdrawalTransactionsMap = sinon.stub(); - this.getRound = sinon.stub(); - this.populate = sinon.stub(); - this.isEmpty = sinon.stub(); - this.fromObject = sinon.stub(); - this.toObject = sinon.stub(); - this.setEpochInfo = sinon.stub(); - this.getEpochInfo = sinon.stub(); - this.setTimeMs = sinon.stub(); - this.getTimeMs = sinon.stub(); - this.setRound = sinon.stub(); - this.getRound = sinon.stub(); - this.getPrepareProposalResult = sinon.stub(); - this.setPrepareProposalResult = sinon.stub(); - } -} - -module.exports = BlockExecutionContextMock; diff --git a/packages/js-drive/lib/test/mock/BlockExecutionContextRepositoryMock.js b/packages/js-drive/lib/test/mock/BlockExecutionContextRepositoryMock.js deleted file mode 100644 index 23af323c9f2..00000000000 --- a/packages/js-drive/lib/test/mock/BlockExecutionContextRepositoryMock.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @method store - * @method fetch - */ -class BlockExecutionContextRepositoryMock { - /** - * @param {SinonSandbox} sinon - */ - constructor(sinon) { - this.store = sinon.stub(); - this.fetch = sinon.stub(); - } -} - -module.exports = BlockExecutionContextRepositoryMock; diff --git a/packages/js-drive/lib/test/mock/BlockExecutionStoreTransactionsMock.js b/packages/js-drive/lib/test/mock/BlockExecutionStoreTransactionsMock.js deleted file mode 100644 index 44b2f87f360..00000000000 --- a/packages/js-drive/lib/test/mock/BlockExecutionStoreTransactionsMock.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @method start - * @method commit - * @method abort - * @method getTransaction - */ -class BlockExecutionStoreTransactionsMock { - /** - * @param {SinonSandbox} sinon - */ - constructor(sinon) { - this.start = sinon.stub(); - this.commit = sinon.stub(); - this.abort = sinon.stub(); - this.getTransaction = sinon.stub(); - this.clone = sinon.stub(); - this.isStarted = sinon.stub(); - } -} - -module.exports = BlockExecutionStoreTransactionsMock; diff --git a/packages/js-drive/lib/test/mock/DriveMock.js b/packages/js-drive/lib/test/mock/DriveMock.js deleted file mode 100644 index 322cdfb5543..00000000000 --- a/packages/js-drive/lib/test/mock/DriveMock.js +++ /dev/null @@ -1,29 +0,0 @@ -class DriveMock { - /** - * @param {Sandbox} sinon - * @method getGroveDB - * @method close - * @method createRootTree - * @method fetchContract - * @method createContract - * @method updateContract - * @method createDocument - * @method updateDocument - * @method deleteDocument - * @method queryDocuments - */ - constructor(sinon) { - this.getGroveDB = sinon.stub(); - this.close = sinon.stub(); - this.createRootTree = sinon.stub(); - this.fetchContract = sinon.stub(); - this.createContract = sinon.stub(); - this.createContract = sinon.stub(); - this.createDocument = sinon.stub(); - this.updateDocument = sinon.stub(); - this.deleteDocument = sinon.stub(); - this.queryDocuments = sinon.stub(); - } -} - -module.exports = DriveMock; diff --git a/packages/js-drive/lib/test/mock/GroveDBStoreMock.js b/packages/js-drive/lib/test/mock/GroveDBStoreMock.js deleted file mode 100644 index 795a3ea6ece..00000000000 --- a/packages/js-drive/lib/test/mock/GroveDBStoreMock.js +++ /dev/null @@ -1,43 +0,0 @@ -class GroveDBStoreMock { - /** - * @param {Sandbox} sinon - * @method put - * @method putReference - * @method createTree - * @method get - * @method delete - * @method getAux - * @method putAux - * @method deleteAux - * @method getRootHash - * @method startTransaction - * @method isTransactionStarted - * @method rollbackTransaction - * @method commitTransaction - * @method abortTransaction - * @method getDrive - * @method getDB - * @method setDB - */ - constructor(sinon) { - this.put = sinon.stub(); - this.putReference = sinon.stub(); - this.createTree = sinon.stub(); - this.get = sinon.stub(); - this.delete = sinon.stub(); - this.getAux = sinon.stub(); - this.putAux = sinon.stub(); - this.deleteAux = sinon.stub(); - this.getRootHash = sinon.stub(); - this.startTransaction = sinon.stub(); - this.isTransactionStarted = sinon.stub(); - this.rollbackTransaction = sinon.stub(); - this.commitTransaction = sinon.stub(); - this.abortTransaction = sinon.stub(); - this.getDrive = sinon.stub(); - this.getDB = sinon.stub(); - this.setDB = sinon.stub(); - } -} - -module.exports = GroveDBStoreMock; diff --git a/packages/js-drive/lib/test/mock/LoggerMock.js b/packages/js-drive/lib/test/mock/LoggerMock.js deleted file mode 100644 index ad45d080d92..00000000000 --- a/packages/js-drive/lib/test/mock/LoggerMock.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @method trace - * @method debug - * @method info - * @method warn - * @method error - * @method fatal - * @method child - */ -class LoggerMock { - /** - * @param {SinonSandbox} sinon - */ - constructor(sinon) { - this.trace = sinon.stub(); - this.debug = sinon.stub(); - this.info = sinon.stub(); - this.warn = sinon.stub(); - this.error = sinon.stub(); - this.fatal = sinon.stub(); - this.child = () => this; - } -} - -module.exports = LoggerMock; diff --git a/packages/js-drive/lib/test/mock/RootTreeMock.js b/packages/js-drive/lib/test/mock/RootTreeMock.js deleted file mode 100644 index 2347b53ba25..00000000000 --- a/packages/js-drive/lib/test/mock/RootTreeMock.js +++ /dev/null @@ -1,11 +0,0 @@ -class RootTreeMock { - /** - * @param {Sandbox} sinon - */ - constructor(sinon) { - this.getRootHash = sinon.stub(); - this.rebuild = sinon.stub(); - } -} - -module.exports = RootTreeMock; diff --git a/packages/js-drive/lib/test/mock/StateViewTransactionMock.js b/packages/js-drive/lib/test/mock/StateViewTransactionMock.js deleted file mode 100644 index 4c8b767ba04..00000000000 --- a/packages/js-drive/lib/test/mock/StateViewTransactionMock.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * @method start - * @method commit - * @method abort - * @property {boolean} isTransactionStarted - */ -class StateViewTransactionMock { - /** - * @param {Sandbox} sinon - */ - constructor(sinon) { - this.start = sinon.stub(); - this.commit = sinon.stub(); - this.abort = sinon.stub(); - - this.isTransactionStarted = false; - } -} - -module.exports = StateViewTransactionMock; diff --git a/packages/js-drive/lib/test/mock/StoreMock.js b/packages/js-drive/lib/test/mock/StoreMock.js deleted file mode 100644 index 6a5c77d74b3..00000000000 --- a/packages/js-drive/lib/test/mock/StoreMock.js +++ /dev/null @@ -1,13 +0,0 @@ -class StoreMock { - /** - * @param {Sandbox} sinon - */ - constructor(sinon) { - this.put = sinon.stub(); - this.get = sinon.stub(); - this.delete = sinon.stub(); - this.createTransaction = sinon.stub(); - } -} - -module.exports = StoreMock; diff --git a/packages/js-drive/lib/test/mock/StoreRepositoryMock.js b/packages/js-drive/lib/test/mock/StoreRepositoryMock.js deleted file mode 100644 index d37a99001ee..00000000000 --- a/packages/js-drive/lib/test/mock/StoreRepositoryMock.js +++ /dev/null @@ -1,17 +0,0 @@ -class StoreRepositoryMock { - /** - * @param {Sandbox} sinon - * @method store - * @method fetch - * @method createTree - */ - constructor(sinon) { - this.store = sinon.stub(); - this.fetch = sinon.stub(); - this.prove = sinon.stub(); - this.proveMany = sinon.stub(); - this.createTree = sinon.stub(); - } -} - -module.exports = StoreRepositoryMock; diff --git a/packages/js-drive/lib/test/mock/getBiggestPossibleIdentity.js b/packages/js-drive/lib/test/mock/getBiggestPossibleIdentity.js deleted file mode 100644 index 98a69715569..00000000000 --- a/packages/js-drive/lib/test/mock/getBiggestPossibleIdentity.js +++ /dev/null @@ -1,46 +0,0 @@ -const identityCreateTransitionSchema = require('@dashevo/dpp/schema/identity/stateTransition/identityCreate.json'); - -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); - -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -let identity; - -/** - * @return {Identity} - */ -function getBiggestPossibleIdentity() { - if (identity) { - return identity; - } - - const publicKeys = []; - - for (let i = 0; i < identityCreateTransitionSchema.properties.publicKeys.maxItems; i++) { - const securityLevel = i === 0 - ? IdentityPublicKey.SECURITY_LEVELS.MASTER - : IdentityPublicKey.SECURITY_LEVELS.HIGH; - - publicKeys.push({ - id: i, - type: IdentityPublicKey.TYPES.BLS12_381, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel, - readOnly: false, - data: Buffer.alloc(48).fill(255), - }); - } - - identity = new Identity({ - protocolVersion: 1, - id: generateRandomIdentifier().toBuffer(), - publicKeys, - balance: Math.floor(9223372036854775807 / 10000), // credits (i64) max + room for tests - revision: Math.floor(18446744073709551615 / 10000), // u64 max + room for tests - }); - - return identity; -} - -module.exports = getBiggestPossibleIdentity; diff --git a/packages/js-drive/lib/test/util/allocateRandomMemory.js b/packages/js-drive/lib/test/util/allocateRandomMemory.js deleted file mode 100644 index 4fda2848440..00000000000 --- a/packages/js-drive/lib/test/util/allocateRandomMemory.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * - * @param {number} sizeInBytes - size of memory to allocate - * @returns {number[]} - result of the allocation - array filled with random doubles - */ -/* istanbul ignore next */ -module.exports = function allocateRandomMemory(sizeInBytes) { - // This constant is inside of this function because - // it's easier to pass the whole function to the isolate in this case - const NUMBER_SIZE_IN_BYTES = 64 / 8; - const storage = []; - while ((storage.length * NUMBER_SIZE_IN_BYTES) < sizeInBytes) { - storage.push(Math.random()); - } - return storage; -}; diff --git a/packages/js-drive/lib/test/util/setTimeoutShim.js b/packages/js-drive/lib/test/util/setTimeoutShim.js deleted file mode 100644 index 976a0d47fe1..00000000000 --- a/packages/js-drive/lib/test/util/setTimeoutShim.js +++ /dev/null @@ -1,14 +0,0 @@ -/* istanbul ignore next */ -async function wait(timeout) { - const timeStarted = Date.now(); - let finished = false; - - while (!finished) { - if (Date.now() > timeStarted + timeout) { - finished = true; - } - await Promise.resolve(); - } -} - -module.exports = wait; diff --git a/packages/js-drive/lib/util/ExecutionTimer.js b/packages/js-drive/lib/util/ExecutionTimer.js deleted file mode 100644 index baead9caa20..00000000000 --- a/packages/js-drive/lib/util/ExecutionTimer.js +++ /dev/null @@ -1,95 +0,0 @@ -const process = require('process'); - -class ExecutionTimer { - /** - * @type {Object.} - */ - #started = {}; - - /** - * @type {Object.} - */ - #stopped = {}; - - /** - * Start named timer - * - * @param {string} name - * - * @return {void} - */ - startTimer(name) { - if (this.isStarted(name)) { - throw new Error(`${name} timer is already started`); - } - - this.#started[name] = process.hrtime(); - } - - /** - * Clear timer - * - * @param {string} name - */ - clearTimer(name) { - delete this.#started[name]; - delete this.#stopped[name]; - } - - /** - * Get timer - * - * @param {string} name - * @param {boolean} clear - clear timer after getting - * @returns {string} - */ - getTimer(name, clear = false) { - if (!this.#stopped[name]) { - throw new Error(`${name} timer is not stopped`); - } - - const timing = this.#stopped[name]; - - if (clear) { - this.clearTimer(name); - } - - return timing; - } - - /** - * Stop named timer and get timings - * - * @param {string} name - * @param {boolean} keep - do not delete timer - * - * @return {string} - */ - stopTimer(name, keep = false) { - if (!this.isStarted(name)) { - throw new Error(`${name} timer is not started`); - } - - const timings = process.hrtime(this.#started[name]); - - const result = ( - parseFloat(timings[0].toString()) + timings[1] / 1000000000 - ).toFixed(3); - - if (keep) { - this.#stopped[name] = result; - } - - return result; - } - - /** - * @param {string} name - * @return {boolean} - */ - isStarted(name) { - return this.#started[name] !== undefined; - } -} - -module.exports = ExecutionTimer; diff --git a/packages/js-drive/lib/util/millisToProtoTimestamp.js b/packages/js-drive/lib/util/millisToProtoTimestamp.js deleted file mode 100644 index 49f076b62b2..00000000000 --- a/packages/js-drive/lib/util/millisToProtoTimestamp.js +++ /dev/null @@ -1,28 +0,0 @@ -const { - google: { - protobuf: { - Timestamp, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -/** - * Get milliseconds time from seconds and nanoseconds - * - * @param {number} milliseconds - * - * @returns {number} - */ -function millisToProtoTimestamp(milliseconds) { - const seconds = Math.floor(milliseconds / 1000); - const nanos = (milliseconds - (seconds * 1000)) * (10 ** 6); - - return new Timestamp({ - seconds: Long.fromNumber(seconds), - nanos, - }); -} - -module.exports = millisToProtoTimestamp; diff --git a/packages/js-drive/lib/util/noopLogger.js b/packages/js-drive/lib/util/noopLogger.js deleted file mode 100644 index a1593e9d71c..00000000000 --- a/packages/js-drive/lib/util/noopLogger.js +++ /dev/null @@ -1,8 +0,0 @@ -const pino = require('pino'); - -const noopLogger = Object.keys(pino.levels.values).reduce((logger, functionName) => ({ - ...logger, - [functionName]: () => {}, -}), {}); - -module.exports = noopLogger; diff --git a/packages/js-drive/lib/util/printErrorFace.js b/packages/js-drive/lib/util/printErrorFace.js deleted file mode 100644 index b6e745d647a..00000000000 --- a/packages/js-drive/lib/util/printErrorFace.js +++ /dev/null @@ -1,35 +0,0 @@ -const chalk = require('chalk'); - -// Faces https://github.com/maxogden/cool-ascii-faces -const faces = [ - '\\_(ʘ_ʘ)_/', - '(•̀o•́)ง', - 'ヽ༼° ͟ل͜ ͡°༽ノ', - 'ノ( ゜-゜ノ)', - '༼ ºل͟º ༽', - '(ಥ﹏ಥ)', - '¯\\_(ツ)_/¯', - '(╯°□°)╯︵ ┻━┻', // https://looks.wtf/flipping-tables -]; - -/** - * @return {string} - */ -function printErrorFace() { - let face = ''; - - // top padding - face += '\n\n'; - - // face - face += chalk.red( - faces[Math.floor(Math.random() * faces.length)], - ); - - // bottom padding - face += '\n\n'; - - return face; -} - -module.exports = printErrorFace; diff --git a/packages/js-drive/lib/util/protoTimestampToMillis.js b/packages/js-drive/lib/util/protoTimestampToMillis.js deleted file mode 100644 index 79e47a8bf1d..00000000000 --- a/packages/js-drive/lib/util/protoTimestampToMillis.js +++ /dev/null @@ -1,11 +0,0 @@ -const timeToMillis = require('./timeToMillis'); - -/** - * @param {google.protobuf.ITimestamp} timestamp - * @returns {number} - */ -function protoTimestampToMillis(timestamp) { - return timeToMillis(timestamp.seconds.toNumber(), timestamp.nanos); -} - -module.exports = protoTimestampToMillis; diff --git a/packages/js-drive/lib/util/rejectAfter.js b/packages/js-drive/lib/util/rejectAfter.js deleted file mode 100644 index 4701716d38f..00000000000 --- a/packages/js-drive/lib/util/rejectAfter.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Reject with @param error if @param promise is not resolved in @param ms - * - * @param {Promise} promise - * @param {Error} error - * @param {number} ms - * @return {Promise} - */ -module.exports = async function rejectAfter(promise, error, ms) { - let timeout; - let res; - try { - res = await Promise.race([ - promise, - new Promise((resolve, reject) => { - timeout = setTimeout(() => reject(error), ms); - }), - ]); - } finally { - // noinspection JSUnusedAssignment - clearTimeout(timeout); - } - - return res; -}; diff --git a/packages/js-drive/lib/util/sanitizeUrl.js b/packages/js-drive/lib/util/sanitizeUrl.js deleted file mode 100644 index d3fedd42249..00000000000 --- a/packages/js-drive/lib/util/sanitizeUrl.js +++ /dev/null @@ -1,15 +0,0 @@ -function sanitizeUrl(url) { - for (let i = 0, len = url.length; i < len; i++) { - const charCode = url.charCodeAt(i); - // Some systems do not follow RFC and separate the path and query - // string with a `;` character (code 59), e.g. `/foo;jsessionid=123456`. - // Thus, we need to split on `;` as well as `?` and `#`. - if (charCode === 63 || charCode === 59 || charCode === 35) { - return url.slice(0, i); - } - } - - return url; -} - -module.exports = sanitizeUrl; diff --git a/packages/js-drive/lib/util/shuffleArray.js b/packages/js-drive/lib/util/shuffleArray.js deleted file mode 100644 index 1e6c97f9102..00000000000 --- a/packages/js-drive/lib/util/shuffleArray.js +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable no-param-reassign */ -/** - * Shuffle the given array in place - * - * @param {Array} array - * @returns {Array} - */ -module.exports = function shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - return array; -}; diff --git a/packages/js-drive/lib/util/timeToMillis.js b/packages/js-drive/lib/util/timeToMillis.js deleted file mode 100644 index 49037e73bfd..00000000000 --- a/packages/js-drive/lib/util/timeToMillis.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * Get milliseconds time from seconds and nanoseconds - * - * @param {number} seconds - * @param {number} nanoseconds - * - * @returns {number} - */ -function timeToMillis(seconds, nanoseconds) { - const overallNanos = nanoseconds + seconds * (10 ** 9); - - return Math.floor(overallNanos / (10 ** 6)); -} - -module.exports = timeToMillis; diff --git a/packages/js-drive/lib/util/wait.js b/packages/js-drive/lib/util/wait.js deleted file mode 100644 index b0d45b4c5ce..00000000000 --- a/packages/js-drive/lib/util/wait.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Asynchronously wait for a specified number of milliseconds. - * @param {Number} ms - Number of milliseconds to wait. - * @return {Promise} The promise to await on. - */ -async function wait(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -module.exports = wait; diff --git a/packages/js-drive/lib/validator/Validator.js b/packages/js-drive/lib/validator/Validator.js deleted file mode 100644 index daefdb63af4..00000000000 --- a/packages/js-drive/lib/validator/Validator.js +++ /dev/null @@ -1,72 +0,0 @@ -const PublicKeyShareIsNotPresentError = require('./errors/PublicKeyShareIsNotPresentError'); - -class Validator { - /** - * @param {Buffer} proTxHash - * @param {ValidatorNetworkInfo} networkInfo - * @param {Buffer} [pubKeyShare] - */ - constructor(proTxHash, networkInfo, pubKeyShare = undefined) { - this.proTxHash = proTxHash; - this.networkInfo = networkInfo; - this.pubKeyShare = pubKeyShare; - } - - /** - * Get validator pro tx hash - * - * @return {Buffer} - */ - getProTxHash() { - return this.proTxHash; - } - - /** - * Get validator public key share - * @return {Buffer} - */ - getPublicKeyShare() { - return this.pubKeyShare; - } - - /** - * Get validator voting power - * - * @return {number} - */ - getVotingPower() { - return Validator.DEFAULT_DASH_VOTING_POWER; - } - - /** - * Get network info - * - * @returns {ValidatorNetworkInfo} - */ - getNetworkInfo() { - return this.networkInfo; - } - - /** - * @param {Object} member - * @param {ValidatorNetworkInfo} networkInfo - * @param {boolean} [pubKeyShareRequired=false] - * @return {Validator} - */ - static createFromQuorumMember(member, networkInfo, pubKeyShareRequired = false) { - const proTxHash = Buffer.from(member.proTxHash, 'hex'); - - let pubKeyShare; - if (member.pubKeyShare) { - pubKeyShare = Buffer.from(member.pubKeyShare, 'hex'); - } else if (pubKeyShareRequired) { - throw new PublicKeyShareIsNotPresentError(member); - } - - return new Validator(proTxHash, networkInfo, pubKeyShare); - } -} - -Validator.DEFAULT_DASH_VOTING_POWER = 100; - -module.exports = Validator; diff --git a/packages/js-drive/lib/validator/ValidatorNetworkInfo.js b/packages/js-drive/lib/validator/ValidatorNetworkInfo.js deleted file mode 100644 index 91593bd4f8f..00000000000 --- a/packages/js-drive/lib/validator/ValidatorNetworkInfo.js +++ /dev/null @@ -1,29 +0,0 @@ -class ValidatorNetworkInfo { - /** - * - * @param {string} host - * @param {number} port - */ - constructor(host, port) { - this.host = host; - this.port = port; - } - - /** - * Get validator host - * @returns {string} - */ - getHost() { - return this.host; - } - - /** - * Get validator port - * @returns {number} - */ - getPort() { - return this.port; - } -} - -module.exports = ValidatorNetworkInfo; diff --git a/packages/js-drive/lib/validator/ValidatorSet.js b/packages/js-drive/lib/validator/ValidatorSet.js deleted file mode 100644 index ca3d0616bff..00000000000 --- a/packages/js-drive/lib/validator/ValidatorSet.js +++ /dev/null @@ -1,171 +0,0 @@ -const Validator = require('./Validator'); -const ValidatorSetIsNotInitializedError = require('./errors/ValidatorSetIsNotInitializedError'); -const ValidatorNetworkInfo = require('./ValidatorNetworkInfo'); - -class ValidatorSet { - /** - * @param {SimplifiedMasternodeList} simplifiedMasternodeList - * @param {getRandomQuorum} getRandomQuorum - * @param {fetchQuorumMembers} fetchQuorumMembers - * @param {number} validatorSetLLMQType - * @param {RpcClient} coreRpcClient - * @param {number} tenderdashP2pPort - */ - constructor( - simplifiedMasternodeList, - getRandomQuorum, - fetchQuorumMembers, - validatorSetLLMQType, - coreRpcClient, - tenderdashP2pPort, - ) { - this.simplifiedMasternodeList = simplifiedMasternodeList; - this.getRandomQuorum = getRandomQuorum; - this.fetchQuorumMembers = fetchQuorumMembers; - this.validatorSetLLMQType = validatorSetLLMQType; - this.coreRpcClient = coreRpcClient; - this.tenderdashP2pPort = tenderdashP2pPort; - - this.quorum = null; - this.validators = []; - } - - /** - * Chooses an active validator set from among all active validator quorums for the first time - * - * @param {number} coreHeight - */ - async initialize(coreHeight) { - const sml = this.simplifiedMasternodeList.getStore().getSMLbyHeight(coreHeight); - - // using the block hash at the first core height as entropy - const rotationEntropy = Buffer.from(sml.toSimplifiedMNListDiff().blockHash, 'hex'); - - await this.switchToRandomQuorum( - sml, - coreHeight, - rotationEntropy, - ); - } - - /** - * Rotates to a new active validator set from among all active validator quorums - * - * @param {Long} height - * @param {number} coreHeight - * @param {Buffer} rotationEntropy - */ - async rotate(height, coreHeight, rotationEntropy) { - const sml = this.simplifiedMasternodeList.getStore().getSMLbyHeight(coreHeight); - - // validator set is rotated every ROTATION_BLOCK_INTERVAL blocks - if (height.toNumber() % ValidatorSet.ROTATION_BLOCK_INTERVAL !== 0) { - return false; - } - - await this.switchToRandomQuorum( - sml, - coreHeight, - rotationEntropy, - ); - - return true; - } - - /** - * Get Validator Set Quorum - * - * @return {QuorumEntry} - */ - getQuorum() { - if (!this.quorum) { - throw new ValidatorSetIsNotInitializedError(); - } - - return this.quorum; - } - - /** - * Get validators - * - * @return {Validator[]} - */ - getValidators() { - if (this.validators.length === 0) { - throw new ValidatorSetIsNotInitializedError(); - } - - return this.validators; - } - - /** - * @private - * @param {SimplifiedMNList} sml - * @param {number} coreHeight - * @param {Buffer} rotationEntropy - * @return {Promise} - */ - async switchToRandomQuorum(sml, coreHeight, rotationEntropy) { - this.quorum = await this.getRandomQuorum( - sml, - this.validatorSetLLMQType, - rotationEntropy, - coreHeight, - ); - - const quorumMembers = await this.fetchQuorumMembers( - this.validatorSetLLMQType, - this.quorum.quorumHash, - ); - - // If the node is a quorum member and doesn't receive public key share for members - // it should throw an error - let proTxHash; - - try { - ({ - result: { - proTxHash, - }, - } = await this.coreRpcClient.masternode('status')); - } catch (e) { - // This node is not a masternode - if (e.code !== -32603) { - throw e; - } - } - - const isThisNodeMember = !!quorumMembers - .find((member) => member.valid && member.proTxHash === proTxHash); - - const validMasternodesList = this.simplifiedMasternodeList - .getStore() - .getCurrentSML() - .getValidMasternodesList(); - - const masternodes = {}; - - this.validators = quorumMembers.filter((member) => { - // Ignore invalid quorum members - if (!member.valid) { - return false; - } - - // Ignore members which are not part of SML - masternodes[member.proTxHash] = validMasternodesList - .find((mnEntry) => mnEntry.proRegTxHash === member.proTxHash); - - return Boolean(masternodes[member.proTxHash]); - }).map((member) => { - const masternode = masternodes[member.proTxHash]; - - const networkInfo = new ValidatorNetworkInfo(masternode.getIp(), this.tenderdashP2pPort); - - return Validator.createFromQuorumMember(member, networkInfo, isThisNodeMember); - }); - } -} - -ValidatorSet.ROTATION_BLOCK_INTERVAL = 15; - -module.exports = ValidatorSet; diff --git a/packages/js-drive/lib/validator/errors/PublicKeyShareIsNotPresentError.js b/packages/js-drive/lib/validator/errors/PublicKeyShareIsNotPresentError.js deleted file mode 100644 index aebcec4b46b..00000000000 --- a/packages/js-drive/lib/validator/errors/PublicKeyShareIsNotPresentError.js +++ /dev/null @@ -1,23 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class PublicKeyShareIsNotPresentError extends DriveError { - /** - * @param {Object} member - */ - constructor(member) { - super('Public key share is not present for validator'); - - this.member = member; - } - - /** - * Get quorum member info - * - * @return {Object} - */ - getMember() { - return this.member; - } -} - -module.exports = PublicKeyShareIsNotPresentError; diff --git a/packages/js-drive/lib/validator/errors/ValidatorSetIsNotInitializedError.js b/packages/js-drive/lib/validator/errors/ValidatorSetIsNotInitializedError.js deleted file mode 100644 index c6a2b1c0ea7..00000000000 --- a/packages/js-drive/lib/validator/errors/ValidatorSetIsNotInitializedError.js +++ /dev/null @@ -1,9 +0,0 @@ -const DriveError = require('../../errors/DriveError'); - -class ValidatorSetIsNotInitializedError extends DriveError { - constructor() { - super('Validator Set is not initialized'); - } -} - -module.exports = ValidatorSetIsNotInitializedError; diff --git a/packages/js-drive/package.json b/packages/js-drive/package.json deleted file mode 100644 index 019ff95d9b0..00000000000 --- a/packages/js-drive/package.json +++ /dev/null @@ -1,104 +0,0 @@ -{ - "name": "@dashevo/drive", - "private": true, - "version": "0.24.0-dev.16", - "description": "Replicated state machine for Dash Platform", - "engines": { - "node": ">=12" - }, - "contributors": [ - { - "name": "Ivan Shumkov", - "email": "ivan@shumkov.ru", - "url": "https://github.com/shumkov" - }, - { - "name": "Djavid Gabibiyan", - "email": "djavid@dash.org", - "url": "https://github.com/jawid-h" - }, - { - "name": "Anton Suprunchuk", - "email": "anton.suprunchuk@dash.org", - "url": "https://github.com/antouhou" - }, - { - "name": "Konstantin Shuplenkov", - "email": "konstantin.shuplenkov@dash.org", - "url": "https://github.com/shuplenkov" - } - ], - "scripts": { - "abci": "node scripts/abci", - "echo": "node scripts/echo", - "lint": "eslint .", - "test": "yarn run test:coverage", - "test:coverage": "nyc --check-coverage --stmts=93 --branch=85 --funcs=90 --lines=88 yarn run mocha './test/unit/**/*.spec.js' './test/integration/**/*.spec.js'", - "test:unit": "mocha './test/unit/**/*.spec.js'", - "test:integration": "mocha './test/integration/**/*.spec.js'" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/dashevo/js-drive.git" - }, - "license": "MIT", - "bugs": { - "url": "https://github.com/dashevo/js-drive/issues" - }, - "homepage": "https://github.com/dashevo/js-drive", - "devDependencies": { - "@dashevo/dp-services-ctl": "github:dashevo/js-dp-services-ctl#v0.19-dev", - "@types/pino": "^6.3.0", - "babel-eslint": "^10.1.0", - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "chai-string": "^1.5.0", - "dirty-chai": "^2.0.1", - "eslint": "^7.32.0", - "eslint-config-airbnb-base": "^14.2.1", - "eslint-plugin-import": "^2.24.2", - "levelup": "^4.4.0", - "memdown": "^5.1.0", - "mocha": "^9.1.2", - "moment": "^2.29.4", - "nyc": "^15.1.0", - "rimraf": "^3.0.2", - "sinon": "^11.1.2", - "sinon-chai": "^3.7.0" - }, - "dependencies": { - "@dashevo/abci": "github:dashpay/js-abci#09f72120bc2059144f72eb7a246d632ead3fc3c6", - "@dashevo/dapi-grpc": "workspace:*", - "@dashevo/dashcore-lib": "~0.20.0", - "@dashevo/dashd-rpc": "^18.2.0", - "@dashevo/dashpay-contract": "workspace:*", - "@dashevo/dpns-contract": "workspace:*", - "@dashevo/dpp": "workspace:*", - "@dashevo/feature-flags-contract": "workspace:*", - "@dashevo/grpc-common": "workspace:*", - "@dashevo/masternode-reward-shares-contract": "workspace:*", - "@dashevo/rs-drive": "workspace:*", - "@dashevo/withdrawals-contract": "workspace:*", - "ajv": "^8.6.0", - "ajv-keywords": "^5.0.0", - "awilix": "^4.2.6", - "blake3": "^2.1.4", - "bs58": "^4.0.1", - "cbor": "^8.0.0", - "chalk": "^4.1.0", - "dotenv-expand": "^5.1.0", - "dotenv-safe": "^8.2.0", - "find-my-way": "^2.2.2", - "js-merkle": "^0.1.5", - "lodash": "^4.17.21", - "long": "^5.2.0", - "node-graceful": "^3.0.1", - "pino": "^6.4.0", - "pino-multi-stream": "^5.2.0", - "pino-pretty": "^4.0.3", - "rimraf": "^3.0.2", - "setimmediate": "^1.0.5", - "through2": "^3.0.1", - "zeromq": "^5.2.8" - } -} diff --git a/packages/js-drive/scripts/abci.js b/packages/js-drive/scripts/abci.js deleted file mode 100644 index 4d577e27e22..00000000000 --- a/packages/js-drive/scripts/abci.js +++ /dev/null @@ -1,181 +0,0 @@ -require('dotenv-expand')(require('dotenv-safe').config()); - -const graceful = require('node-graceful'); - -const chalk = require('chalk'); - -const ZMQClient = require('../lib/core/ZmqClient'); - -const createDIContainer = require('../lib/createDIContainer'); - -const { version: driveVersion } = require('../package.json'); - -const banner = '\n ____ ______ ____ __ __ ____ ____ ______ __ __ ____ \n' -+ '/\\ _`\\ /\\ _ \\ /\\ _`\\ /\\ \\/\\ \\ /\\ _`\\ /\\ _`\\ /\\__ _\\ /\\ \\/\\ \\ /\\ _`\\ \n' -+ '\\ \\ \\/\\ \\ \\ \\ \\L\\ \\ \\ \\,\\L\\_\\ \\ \\ \\_\\ \\ \\ \\ \\/\\ \\ \\ \\ \\L\\ \\ \\/_/\\ \\/ \\ \\ \\ \\ \\ \\ \\ \\L\\_\\ \n' -+ ' \\ \\ \\ \\ \\ \\ \\ __ \\ \\/_\\__ \\ \\ \\ _ \\ \\ \\ \\ \\ \\ \\ \\ , / \\ \\ \\ \\ \\ \\ \\ \\ \\ \\ _\\L \n' -+ ' \\ \\ \\_\\ \\ \\ \\ \\/\\ \\ /\\ \\L\\ \\ \\ \\ \\ \\ \\ \\ \\ \\_\\ \\ \\ \\ \\\\ \\ \\_\\ \\__ \\ \\ \\_/ \\ \\ \\ \\L\\ \\\n' -+ ' \\ \\____/ \\ \\_\\ \\_\\ \\ `\\____\\ \\ \\_\\ \\_\\ \\ \\____/ \\ \\_\\ \\_\\ /\\_____\\ \\ `\\___/ \\ \\____/\n' -+ ' \\/___/ \\/_/\\/_/ \\/_____/ \\/_/\\/_/ \\/___/ \\/_/\\/ / \\/_____/ `\\/__/ \\/___/\n\n\n'; - -// eslint-disable-next-line no-console -console.log(chalk.hex('#008de4')(banner)); - -(async function main() { - const container = createDIContainer(process.env); - const logger = container.resolve('logger'); - const dpp = container.resolve('dpp'); - const transactionalDpp = container.resolve('transactionalDpp'); - const errorHandler = container.resolve('errorHandler'); - const latestProtocolVersion = container.resolve('latestProtocolVersion'); - const closeAbciServer = container.resolve('closeAbciServer'); - - logger.info(`Starting Drive ABCI application v${driveVersion} (latest protocol v${latestProtocolVersion})`); - - /** - * Ensure graceful shutdown - */ - - process - .on('unhandledRejection', errorHandler) - .on('uncaughtException', errorHandler); - - graceful.DEADLY_SIGNALS.push('SIGQUIT'); - - graceful.on('exit', async (signal) => { - logger.info({ signal }, `Received ${signal}. Stopping Drive ABCI application...`); - - await closeAbciServer(); - - await container.dispose(); - }); - - /** - * Initialize DPP - */ - - await dpp.initialize(); - await transactionalDpp.initialize(); - - /** - * Make sure Core is synced - */ - - const network = container.resolve('network'); - - logger.info(`Connecting to Core in ${network} network...`); - - const waitForCoreSync = container.resolve('waitForCoreSync'); - await waitForCoreSync((currentBlockHeight, currentHeaderNumber) => { - let message = `waiting for core to finish sync ${currentBlockHeight}/${currentHeaderNumber}...`; - - if (currentBlockHeight === 0 && currentHeaderNumber === 0) { - message = 'waiting for core to connect to peers...'; - } - - logger.info(message); - }); - - /** - * Connect to Core ZMQ socket - */ - - const coreZMQClient = container.resolve('coreZMQClient'); - - coreZMQClient.on(ZMQClient.events.CONNECTED, () => { - logger.debug('Connected to core ZMQ socket'); - }); - - coreZMQClient.on(ZMQClient.events.DISCONNECTED, () => { - logger.debug('Disconnected from core ZMQ socket'); - }); - - coreZMQClient.on(ZMQClient.events.MAX_RETRIES_REACHED, async () => { - const error = new Error('Can\'t connect to core ZMQ'); - - await errorHandler(error); - }); - - try { - await coreZMQClient.start(); - } catch (e) { - const error = new Error(`Can't connect to core ZMQ socket: ${e.message}`); - - await errorHandler(error); - } - - /** - * Obtain chain lock - */ - - logger.info('Obtaining the latest chain lock...'); - - const waitForCoreChainLockSync = container.resolve('waitForCoreChainLockSync'); - await waitForCoreChainLockSync(); - - /** - * Wait for initial core chain locked height - */ - const initialCoreChainLockedHeight = container.resolve('initialCoreChainLockedHeight'); - - logger.info(`Waiting for initial core chain locked height #${initialCoreChainLockedHeight}...`); - - const waitForChainLockedHeight = container.resolve('waitForChainLockedHeight'); - await waitForChainLockedHeight(initialCoreChainLockedHeight); - - /** - * Start ABCI server - */ - - const abciServer = container.resolve('abciServer'); - - abciServer.on('connection', (socket) => { - logger.debug( - { - abciConnectionId: socket.connection.id, - }, - `Accepted new ABCI connection #${socket.connection.id} from ${socket.remoteAddress}:${socket.remotePort}`, - ); - - socket.on('error', (e) => { - logger.error( - { - err: e, - abciConnectionId: socket.connection.id, - }, - `ABCI connection #${socket.connection.id} error: ${e.message}`, - ); - }); - - socket.once('close', (hasError) => { - let message = `ABCI connection #${socket.connection.id} is closed`; - if (hasError) { - message += ' with error'; - } - - logger.debug( - { - abciConnectionId: socket.connection.id, - }, - message, - ); - }); - }); - - abciServer.once('close', () => { - logger.info('ABCI server and all connections are closed'); - }); - - abciServer.on('error', async (e) => { - await errorHandler(e); - }); - - abciServer.on('listening', () => { - logger.info(`ABCI server is waiting for connection on port ${container.resolve('abciPort')}`); - }); - - abciServer.listen( - container.resolve('abciPort'), - container.resolve('abciHost'), - ); -}()); diff --git a/packages/js-drive/scripts/echo.js b/packages/js-drive/scripts/echo.js deleted file mode 100644 index efd6d7f8353..00000000000 --- a/packages/js-drive/scripts/echo.js +++ /dev/null @@ -1,34 +0,0 @@ -const net = require('net'); - -async function sendEcho(ip) { - const echoRequestBytes = Buffer.from('0a0a080a0668656c6c6f21', 'hex'); - - return new Promise((resolve, reject) => { - const client = net.connect(26658, ip); - - client.on('connect', () => { - client.write(echoRequestBytes); - }); - - client.on('data', () => { - client.destroy(); - - resolve('ok'); - }); - - client.on('error', reject); - - setTimeout(() => { - reject(new Error('Can\'t connect to ABCI port: timeout.')); - }, 2000); - }); -} - -sendEcho('127.0.0.1') - // eslint-disable-next-line no-console - .then(console.log) - .catch((e) => { - // eslint-disable-next-line no-console - console.error(e); - process.exit(1); - }); diff --git a/packages/js-drive/test/.eslintrc b/packages/js-drive/test/.eslintrc deleted file mode 100644 index 720ced73852..00000000000 --- a/packages/js-drive/test/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "env": { - "node": true, - "mocha": true - }, - "rules": { - "import/no-extraneous-dependencies": "off" - }, - "globals": { - "expect": true - } -} diff --git a/packages/js-drive/test/README.md b/packages/js-drive/test/README.md deleted file mode 100644 index ce3a86a76af..00000000000 --- a/packages/js-drive/test/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# Drive Tests - -We believe in [Test Pyramid](http://verraes.net/2015/01/economy-of-tests/). - -## Structure - - - `integration/` - [Integration tests](https://en.wikipedia.org/wiki/Integration_testing) - - `unit/` - [Unit tests](https://en.wikipedia.org/wiki/Unit_testing) - -A subsequent paths the same as the structure of the code in the [lib/](../lib) directory. - -## How to run tests - -Run all tests: - -```bash -npm test -``` - -Run unit tests: - -```bash -npm run test:unit -``` - -Run integration tests: - -```bash -npm run test:integration -``` - -## How to write tests - -We use: - - [Mocha](https://mochajs.org) as testing framework - - [Sinon.JS](http://sinonjs.org/) for stubs and spies - - [Chai](http://chaijs.com/) with several plugins for assertions: - - [Sinon Chai](https://github.com/domenic/sinon-chai) for Sinon.JS assertions - - [Chai as promised](https://github.com/domenic/chai-as-promised) for assertions about promises - - [Dirty Chai](https://github.com/prodatakey/dirty-chai) for lint-friendly terminating assertions - -We prefer `expect` assertions syntax instead of `should`. - -All tools are [bootstrapped](../lib/test/bootstrap.js) before tests: - - `expect` function is available in global context - - Sinon sandbox is created before each test and available as `this.sinon` property in the test's context - - Envs from `.env` are loaded before all tests - -## Evolution helpers -We use [js-evo-services-ctl](https://github.com/dashevo/js-evo-services-ctl) library to manipulate Evolution's services. - -## Other tools - -You may find other useful tools for testing in [lib/test](../lib/test) directory. diff --git a/packages/js-drive/test/integration/abci/handlers/queryHandlerFactory.spec.js b/packages/js-drive/test/integration/abci/handlers/queryHandlerFactory.spec.js deleted file mode 100644 index a06c3c3e9a4..00000000000 --- a/packages/js-drive/test/integration/abci/handlers/queryHandlerFactory.spec.js +++ /dev/null @@ -1,150 +0,0 @@ -const cbor = require('cbor'); - -const { - asValue, -} = require('awilix'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); - -const createTestDIContainer = require('../../../../lib/test/createTestDIContainer'); -const InvalidArgumentAbciError = require('../../../../lib/abci/errors/InvalidArgumentAbciError'); - -describe('queryHandlerFactory', function main() { - this.timeout(90000); - - let container; - let queryHandler; - let identityQueryHandlerMock; - let dataContractQueryHandlerMock; - let documentQueryHandlerMock; - let dataContract; - let documents; - let identity; - let proof; - - beforeEach(async function beforeEach() { - proof = Buffer.from('GbYYWuLCU6u7nb4pdnMM1uzAeURhE7ZPxGqAbUARBsb3', 'hex'); - - container = await createTestDIContainer(); - - dataContract = getDataContractFixture(); - documents = getDocumentsFixture(dataContract); - identity = getIdentityFixture(); - - identityQueryHandlerMock = this.sinon.stub(); - identityQueryHandlerMock.resolves({ - value: identity, - proof, - }); - - dataContractQueryHandlerMock = this.sinon.stub(); - dataContractQueryHandlerMock.resolves(dataContract); - - documentQueryHandlerMock = this.sinon.stub(); - documentQueryHandlerMock.resolves(documents); - - container.register('identityQueryHandler', asValue(identityQueryHandlerMock)); - container.register('dataContractQueryHandler', asValue(dataContractQueryHandlerMock)); - container.register('documentQueryHandler', asValue(documentQueryHandlerMock)); - - const enrichErrorWithContextError = container.resolve('enrichErrorWithContextError'); - queryHandler = enrichErrorWithContextError(container.resolve('queryHandler')); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - describe('/identities', () => { - it('should call identity handler and return an identity with proof', async () => { - const result = await queryHandler({ - path: '/identities', - data: cbor.encode({ - id: 1, - }), - prove: 'true', - }); - - expect(identityQueryHandlerMock).to.have.been.calledOnceWithExactly( - {}, - { id: 1 }, - { - path: '/identities', - data: cbor.encode({ - id: 1, - }), - prove: 'true', - }, - ); - - expect(result).to.deep.equal({ - value: identity, - proof, - }); - }); - }); - - describe('/dataContracts', () => { - it('should call data contract handler and return data contract', async () => { - const result = await queryHandler({ - path: '/dataContracts', - data: cbor.encode({ - id: 1, - }), - }); - - expect(dataContractQueryHandlerMock).to.have.been.calledOnceWithExactly( - {}, - { id: 1 }, - { - path: '/dataContracts', - data: cbor.encode({ - id: 1, - }), - }, - ); - expect(result).to.deep.equal(dataContract); - }); - }); - - describe('/dataContracts/documents', () => { - it('should call documents handler and return documents', async () => { - const result = await queryHandler({ - path: '/dataContracts/documents', - data: cbor.encode({ - contractId: 1, - type: 'someType', - }), - }); - - expect(documentQueryHandlerMock).to.have.been.calledOnceWithExactly( - {}, - { contractId: 1, type: 'someType' }, - { - path: '/dataContracts/documents', - data: cbor.encode({ - contractId: 1, - type: 'someType', - }), - }, - ); - expect(result).to.deep.equal(documents); - }); - }); - - it('should throw an error if invalid path is submitted', async () => { - try { - await queryHandler({ - path: '/unknownPath', - data: Buffer.alloc(0), - }); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidArgumentAbciError); - expect(e.getMessage()).to.equal('Invalid path'); - } - }); -}); diff --git a/packages/js-drive/test/integration/blockExecution/BlockExecutionContextRepository.spec.js b/packages/js-drive/test/integration/blockExecution/BlockExecutionContextRepository.spec.js deleted file mode 100644 index 0044355bc3c..00000000000 --- a/packages/js-drive/test/integration/blockExecution/BlockExecutionContextRepository.spec.js +++ /dev/null @@ -1,121 +0,0 @@ -const rimraf = require('rimraf'); -const cbor = require('cbor'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const Drive = require('@dashevo/rs-drive'); -const getBlockExecutionContextObjectFixture = require('../../../lib/test/fixtures/getBlockExecutionContextObjectFixture'); -const BlockExecutionContext = require('../../../lib/blockExecution/BlockExecutionContext'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const noopLogger = require('../../../lib/util/noopLogger'); -const BlockExecutionContextRepository = require('../../../lib/blockExecution/BlockExecutionContextRepository'); - -describe('BlockExecutionContextRepository', () => { - // let container; - let blockExecutionContextRepository; - let blockExecutionContext; - let rsDrive; - let store; - let options; - - beforeEach(async () => { - const dataContract = getDataContractFixture(); - delete dataContract.entropy; - - const plainObject = getBlockExecutionContextObjectFixture(dataContract); - - blockExecutionContext = new BlockExecutionContext(); - blockExecutionContext.fromObject(plainObject); - - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, noopLogger); - - blockExecutionContextRepository = new BlockExecutionContextRepository(store); - - options = {}; - }); - - afterEach(async () => { - await rsDrive.close(); - rimraf.sync('./db/grovedb_test'); - }); - - it('should store blockExecutionContext', async () => { - const result = await blockExecutionContextRepository.store(blockExecutionContext, options); - - expect(result).to.be.instanceOf(BlockExecutionContextRepository); - - const encodedResult = await store.getAux( - BlockExecutionContextRepository.EXTERNAL_STORE_KEY_NAME, - options, - ); - - const blockExecutionContextEncoded = encodedResult.getValue(); - - const rawBlockExecutionContext = cbor.decode(blockExecutionContextEncoded); - - expect(rawBlockExecutionContext).to.deep.equal(blockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })); - }); - - it('should fetch blockExecutionContext', async () => { - await store.putAux( - BlockExecutionContextRepository.EXTERNAL_STORE_KEY_NAME, - await cbor.encodeAsync(blockExecutionContext.toObject({ - skipContextLogger: true, - })), - options, - ); - - const fetchedBlockExecutionContext = await blockExecutionContextRepository.fetch(options); - - expect(fetchedBlockExecutionContext).to.be.instanceOf(BlockExecutionContext); - - expect(fetchedBlockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })).to.deep.equal(blockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })); - }); - - it('should fetch blockExecutionContext stored in transaction', async () => { - await store.startTransaction(); - - await blockExecutionContextRepository.store(blockExecutionContext, { useTransaction: true }); - - let fetchedBlockExecutionContext = await blockExecutionContextRepository.fetch(); - - expect(fetchedBlockExecutionContext).to.be.instanceOf(BlockExecutionContext); - - expect(fetchedBlockExecutionContext.isEmpty()).to.be.true(); - - await store.commitTransaction(); - - fetchedBlockExecutionContext = await blockExecutionContextRepository.fetch(); - - expect(fetchedBlockExecutionContext).to.be.instanceOf(BlockExecutionContext); - - expect(fetchedBlockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })).to.deep.equal(blockExecutionContext.toObject({ - skipContextLogger: true, - skipPrepareProposalResult: true, - })); - }); -}); diff --git a/packages/js-drive/test/integration/core/SimplifiedMasternodeList.spec.js b/packages/js-drive/test/integration/core/SimplifiedMasternodeList.spec.js deleted file mode 100644 index b9794d449e4..00000000000 --- a/packages/js-drive/test/integration/core/SimplifiedMasternodeList.spec.js +++ /dev/null @@ -1,103 +0,0 @@ -const getSmlFixture = require('../../../lib/test/fixtures/getSmlFixture'); -const SimplifiedMasternodeList = require('../../../lib/core/SimplifiedMasternodeList'); - -describe('SimplifiedMasternodeList', function SimplifiedMasternodeListTest() { - let simplifiedMasternodeList; - let smlMaxListsLimit; - let initialSmlDiffs; - let updatedSmlDiffs; - - this.timeout(10000); - - beforeEach(() => { - simplifiedMasternodeList = new SimplifiedMasternodeList({ - smlMaxListsLimit, - }); - - initialSmlDiffs = getSmlFixture().slice(0, 16); - updatedSmlDiffs = getSmlFixture().slice(16, 17); - }); - - it('should set options', async () => { - expect(simplifiedMasternodeList.options).to.deep.equal({ maxListsLimit: smlMaxListsLimit }); - }); - - describe('#applyDiffs', () => { - it('should create simplifiedMNList', async () => { - let simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList).to.deep.equal(undefined); - - simplifiedMasternodeList.applyDiffs(initialSmlDiffs); - - simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList.baseSimplifiedMNList.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.baseSimplifiedMNList.blockHash).to.equal( - initialSmlDiffs[0].blockHash, - ); - expect(simplifiedMNList.currentSML.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.currentSML.blockHash).to.equal( - initialSmlDiffs[initialSmlDiffs.length - 1].blockHash, - ); - }); - - it('should add diff to simplifiedMNList', async () => { - let simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList).to.deep.equal(undefined); - - simplifiedMasternodeList.applyDiffs(initialSmlDiffs); - - simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList.baseSimplifiedMNList.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.baseSimplifiedMNList.blockHash).to.equal( - initialSmlDiffs[0].blockHash, - ); - expect(simplifiedMNList.currentSML.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.currentSML.blockHash).to.equal( - initialSmlDiffs[initialSmlDiffs.length - 1].blockHash, - ); - - simplifiedMasternodeList.applyDiffs(updatedSmlDiffs); - - simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList.baseSimplifiedMNList.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.baseSimplifiedMNList.blockHash).to.equal( - initialSmlDiffs[0].blockHash, - ); - expect(simplifiedMNList.currentSML.baseBlockHash).to.equal( - initialSmlDiffs[0].baseBlockHash, - ); - expect(simplifiedMNList.currentSML.blockHash).to.equal( - updatedSmlDiffs[0].blockHash, - ); - }); - }); - - describe('#getStore', () => { - it('should return simplifiedMNList', async () => { - let simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList).to.deep.equal(undefined); - - simplifiedMasternodeList.applyDiffs(initialSmlDiffs); - - simplifiedMNList = simplifiedMasternodeList.getStore(); - - expect(simplifiedMNList).to.deep.equal(simplifiedMasternodeList.store); - }); - }); -}); diff --git a/packages/js-drive/test/integration/core/updateSimplifiedMasternodeListFactory.spec.js b/packages/js-drive/test/integration/core/updateSimplifiedMasternodeListFactory.spec.js deleted file mode 100644 index f494a542d87..00000000000 --- a/packages/js-drive/test/integration/core/updateSimplifiedMasternodeListFactory.spec.js +++ /dev/null @@ -1,92 +0,0 @@ -const { startDashCore } = require('@dashevo/dp-services-ctl'); -const SimplifiedMNListStore = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListStore'); - -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); - -describe('updateSimplifiedMasternodeListFactory', function main() { - this.timeout(190000); - - let container; - let dashCore; - let dashCoreOptions; - - after(async () => { - if (dashCore) { - await dashCore.remove(); - } - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should wait until SML will be retrieved', async () => { - dashCore = await startDashCore(dashCoreOptions); - - container = await createTestDIContainer(dashCore); - - const simplifiedMasternodeList = container.resolve('simplifiedMasternodeList'); - - expect(simplifiedMasternodeList.getStore()).to.equal(undefined); - - const { result: randomAddress } = await dashCore.getApi().getNewAddress({ wallet: 'main' }); - - await dashCore.getApi().generateToAddress(1000, randomAddress); - - const updateSimplifiedMasternodeList = container.resolve('updateSimplifiedMasternodeList'); - - await updateSimplifiedMasternodeList(1000); - - expect(simplifiedMasternodeList.getStore()) - .to.be.an.instanceOf(SimplifiedMNListStore); - }); - - it('should update SML Store so other consumers can use it', async () => { - dashCore = await startDashCore(dashCoreOptions); - - container = await createTestDIContainer(dashCore); - - // Create initial state - const groveDBStore = container.resolve('groveDBStore'); - await groveDBStore.startTransaction(); - - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(true); - - const simplifiedMasternodeList = container.resolve('simplifiedMasternodeList'); - const updateSimplifiedMasternodeList = container.resolve('updateSimplifiedMasternodeList'); - const synchronizeMasternodeIdentities = container.resolve('synchronizeMasternodeIdentities'); - const smlMaxListsLimit = container.resolve('smlMaxListsLimit'); - - const api = dashCore.getApi(); - const { result: randomAddress } = await api.getNewAddress({ wallet: 'main' }); - - await api.generateToAddress(600, randomAddress); - - let blockNumber = 500; - - await updateSimplifiedMasternodeList(blockNumber); - await synchronizeMasternodeIdentities(blockNumber); - - expect(simplifiedMasternodeList.getStore()) - .to.be.an.instanceOf(SimplifiedMNListStore); - - blockNumber += smlMaxListsLimit; - - await updateSimplifiedMasternodeList(blockNumber); - await synchronizeMasternodeIdentities(blockNumber); - - expect(simplifiedMasternodeList.getStore()) - .to.be.an.instanceOf(SimplifiedMNListStore); - - blockNumber += smlMaxListsLimit; - - await updateSimplifiedMasternodeList(blockNumber); - await synchronizeMasternodeIdentities(blockNumber); - - expect(simplifiedMasternodeList.getStore()) - .to.be.an.instanceOf(SimplifiedMNListStore); - }); -}); diff --git a/packages/js-drive/test/integration/core/waitForCoreSyncFactory.spec.js b/packages/js-drive/test/integration/core/waitForCoreSyncFactory.spec.js deleted file mode 100644 index 9859e6d8c96..00000000000 --- a/packages/js-drive/test/integration/core/waitForCoreSyncFactory.spec.js +++ /dev/null @@ -1,54 +0,0 @@ -const { startDashCore } = require('@dashevo/dp-services-ctl'); - -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); - -describe('waitForCoreSyncFactory', function main() { - this.timeout(90000); - - let firstDashCore; - let secondDashCore; - let container; - let waitForCoreSync; - - after(async () => { - if (firstDashCore) { - await firstDashCore.remove(); - } - - if (secondDashCore) { - await secondDashCore.remove(); - } - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should wait until Dash Core in regtest mode with peers is synced', async () => { - firstDashCore = await startDashCore(); - const { result: randomAddress } = await firstDashCore.getApi().getNewAddress({ wallet: 'main' }); - await firstDashCore.getApi().generateToAddress(1000, randomAddress); - - secondDashCore = await startDashCore(); - await secondDashCore.connect(firstDashCore); - - container = await createTestDIContainer(secondDashCore); - waitForCoreSync = container.resolve('waitForCoreSync'); - - await waitForCoreSync(() => {}); - - const secondApi = secondDashCore.getApi(); - - const { - result: { - blocks: currentBlockHeight, - headers: currentHeadersNumber, - }, - } = await secondApi.getBlockchainInfo(); - - expect(currentHeadersNumber).to.equal(1000); - expect(currentBlockHeight).to.equal(1000); - }); -}); diff --git a/packages/js-drive/test/integration/createDIContainer.spec.js b/packages/js-drive/test/integration/createDIContainer.spec.js deleted file mode 100644 index 13112ee7935..00000000000 --- a/packages/js-drive/test/integration/createDIContainer.spec.js +++ /dev/null @@ -1,40 +0,0 @@ -const { expect } = require('chai'); - -const createTestDIContainer = require('../../lib/test/createTestDIContainer'); - -describe('createDIContainer', function describeContainer() { - this.timeout(25000); - - let container; - - beforeEach(async () => { - container = await createTestDIContainer(); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should create DI container', async () => { - expect(container).to.respondTo('register'); - expect(container).to.respondTo('resolve'); - }); - - describe('container', () => { - it('should resolve abciHandlers', () => { - const abciHandlers = container.resolve('abciHandlers'); - - expect(abciHandlers).to.have.property('info'); - expect(abciHandlers).to.have.property('checkTx'); - expect(abciHandlers).to.have.property('finalizeBlock'); - expect(abciHandlers).to.have.property('extendVote'); - expect(abciHandlers).to.have.property('initChain'); - expect(abciHandlers).to.have.property('prepareProposal'); - expect(abciHandlers).to.have.property('processProposal'); - expect(abciHandlers).to.have.property('verifyVoteExtension'); - expect(abciHandlers).to.have.property('query'); - }); - }); -}); diff --git a/packages/js-drive/test/integration/dataContract/DataContractStoreRepository.spec.js b/packages/js-drive/test/integration/dataContract/DataContractStoreRepository.spec.js deleted file mode 100644 index a8be383ef27..00000000000 --- a/packages/js-drive/test/integration/dataContract/DataContractStoreRepository.spec.js +++ /dev/null @@ -1,438 +0,0 @@ -const rimraf = require('rimraf'); -const Drive = require('@dashevo/rs-drive'); -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const DataContract = require('@dashevo/dpp/lib/dataContract/DataContract'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const DataContractStoreRepository = require('../../../lib/dataContract/DataContractStoreRepository'); -const noopLogger = require('../../../lib/util/noopLogger'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('DataContractStoreRepository', () => { - let rsDrive; - let store; - let repository; - let decodeProtocolEntity; - let dataContract; - let blockInfo; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, noopLogger); - - await rsDrive.createInitialStateStructure(); - - decodeProtocolEntity = decodeProtocolEntityFactory(); - - repository = new DataContractStoreRepository(store, decodeProtocolEntity, noopLogger); - - dataContract = getDataContractFixture(); - - blockInfo = new BlockInfo(1, 1, Date.now()); - }); - - afterEach(async () => { - await rsDrive.close(); - rimraf.sync('./db/grovedb_test'); - }); - - describe('#create', () => { - it('should store Data Contract', async () => { - const result = await repository.create( - dataContract, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const encodedDataContractResult = await store.get( - DataContractStoreRepository.TREE_PATH.concat([dataContract.getId().toBuffer()]), - DataContractStoreRepository.DATA_CONTRACT_KEY, - ); - - const [protocolVersion, rawDataContract] = decodeProtocolEntity( - encodedDataContractResult.getValue(), - ); - - rawDataContract.protocolVersion = protocolVersion; - - const fetchedDataContract = new DataContract(rawDataContract); - - expect(dataContract.toObject()).to.deep.equal(fetchedDataContract.toObject()); - }); - - it('should store Data Contract using transaction', async () => { - await store.startTransaction(); - - const result = await repository.create( - dataContract, - blockInfo, - { useTransaction: true }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const notFoundDataContractResult = await store.get( - DataContractStoreRepository.TREE_PATH, - dataContract.getId().toBuffer(), - { useTransaction: false }, - ); - - expect(notFoundDataContractResult.getValue()).to.be.null(); - - const dataFromTransactionResult = await store.get( - DataContractStoreRepository.TREE_PATH.concat([dataContract.getId().toBuffer()]), - DataContractStoreRepository.DATA_CONTRACT_KEY, - { useTransaction: true }, - ); - - let [protocolVersion, rawDataContract] = decodeProtocolEntity( - dataFromTransactionResult.getValue(), - ); - - rawDataContract.protocolVersion = protocolVersion; - - const fetchedDataContract = new DataContract(rawDataContract); - - expect(dataContract.toObject()).to.deep.equal(fetchedDataContract.toObject()); - - await store.commitTransaction(); - - const committedDataResult = await store.get( - DataContractStoreRepository.TREE_PATH.concat([dataContract.getId().toBuffer()]), - DataContractStoreRepository.DATA_CONTRACT_KEY, - ); - - [protocolVersion, rawDataContract] = decodeProtocolEntity(committedDataResult.getValue()); - - rawDataContract.protocolVersion = protocolVersion; - - const fetchedOneMoreDataContract = new DataContract(rawDataContract); - - expect(dataContract.toObject()).to.deep.equal(fetchedOneMoreDataContract.toObject()); - }); - - it('should not store Data Contract with dry run', async () => { - const result = await repository.create( - dataContract, - blockInfo, - { dryRun: true }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const encodedDataContractResult = await store.get( - DataContractStoreRepository.TREE_PATH, - dataContract.getId().toBuffer(), - ); - - expect(encodedDataContractResult.isNull()).to.be.true(); - }); - }); - - describe('#update', () => { - beforeEach(async () => { - await repository.create(dataContract, blockInfo); - }); - - it('should store Data Contract', async () => { - const result = await repository.update( - dataContract, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const encodedDataContractResult = await store.get( - DataContractStoreRepository.TREE_PATH.concat([dataContract.getId().toBuffer()]), - DataContractStoreRepository.DATA_CONTRACT_KEY, - ); - - const [protocolVersion, rawDataContract] = decodeProtocolEntity( - encodedDataContractResult.getValue(), - ); - - rawDataContract.protocolVersion = protocolVersion; - - const fetchedDataContract = new DataContract(rawDataContract); - - expect(dataContract.toObject()).to.deep.equal(fetchedDataContract.toObject()); - }); - - it('should store Data Contract using transaction', async () => { - await store.startTransaction(); - - dataContract.incrementVersion(); - - const result = await repository.update( - dataContract, - blockInfo, - { useTransaction: true }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const dataContractWithoutTransactionResult = await repository.fetch(dataContract.getId()); - - expect(dataContractWithoutTransactionResult.isNull()).to.be.false(); - expect(dataContractWithoutTransactionResult.getValue().getVersion()).to.equals(1); - - const dataContractWithTransactionResult = await repository.fetch(dataContract.getId(), { - useTransaction: true, - }); - - expect(dataContractWithTransactionResult.isNull()).to.be.false(); - - const fetchedDataContract = dataContractWithTransactionResult.getValue(); - - expect(fetchedDataContract.getVersion()).to.equals(2); - - expect(fetchedDataContract.toObject()).to.deep.equal(dataContract.toObject()); - }); - - it('should not store Data Contract with dry run', async () => { - dataContract.incrementVersion(); - - const result = await repository.update( - dataContract, - blockInfo, - { dryRun: true }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const dataContractResult = await repository.fetch(dataContract.getId()); - - expect(dataContractResult.isNull()).to.be.false(); - - const fetchedDataContract = dataContractResult.getValue(); - - expect(fetchedDataContract.getVersion()).to.equals(1); - - expect(fetchedDataContract.toObject()).to.not.deep.equal(dataContract.toObject()); - }); - }); - - describe('#fetch', () => { - it('should should fetch null if Data Contract not found', async () => { - const result = await repository.fetch(dataContract.getId()); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch Data Contract', async () => { - await store.getDrive().createContract(dataContract, blockInfo, false); - - const result = await repository.fetch(dataContract.getId()); - - expect(result).to.be.instanceOf(StorageResult); - - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - const storedDataContract = result.getValue(); - - expect(storedDataContract).to.be.an.instanceof(DataContract); - expect(storedDataContract.toObject()).to.deep.equal(storedDataContract.toObject()); - }); - - it('should fetch Data Contract using transaction', async () => { - await store.startTransaction(); - - await store.getDrive().createContract(dataContract, blockInfo, true); - - const notFoundDataContractResult = await repository.fetch(dataContract.getId(), { - useTransaction: false, - }); - - expect(notFoundDataContractResult.isNull()).to.be.true(); - - const transactionalDataContractResult = await repository.fetch(dataContract.getId(), { - useTransaction: true, - }); - - const transactionalDataContract = transactionalDataContractResult.getValue(); - - expect(transactionalDataContract).to.be.an.instanceof(DataContract); - expect(transactionalDataContract.toObject()).to.deep.equal(dataContract.toObject()); - - await store.commitTransaction(); - - const storedDataContractResult = await repository.fetch(dataContract.getId()); - - const storedDataContract = storedDataContractResult.getValue(); - - expect(storedDataContract).to.be.an.instanceof(DataContract); - expect(storedDataContract.toObject()).to.deep.equal(dataContract.toObject()); - }); - - it('should fetch null on dry run', async () => { - await store.getDrive().createContract(dataContract, blockInfo, false); - - const result = await repository.fetch(dataContract.getId(), { dryRun: true }); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - }); - - describe('#prove', () => { - it('should should return proof if Data Contract not found', async () => { - const result = await repository.prove(dataContract.getId()); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof', async () => { - await store.getDrive().createContract(dataContract, blockInfo, false); - - const result = await repository.prove(dataContract.getId()); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - // TODO enable this test when we support transactions - it.skip('should return proof using transaction', async () => { - await store.startTransaction(); - - await store.getDrive().createContract(dataContract, blockInfo, true); - - const notFoundDataContractResult = await repository.prove(dataContract.getId(), { - useTransaction: false, - }); - - expect(notFoundDataContractResult.isNull()).to.be.true(); - - const transactionalDataContractResult = await repository.prove(dataContract.getId(), { - useTransaction: true, - }); - - const transactionalDataContract = transactionalDataContractResult.getValue(); - - expect(transactionalDataContract).to.be.an.instanceof(Buffer); - - await store.commitTransaction(); - - const storedDataContractResult = await repository.prove(dataContract.getId()); - - const storedDataContract = storedDataContractResult.getValue(); - - expect(storedDataContract).to.be.an.instanceof(Buffer); - }); - }); - - describe('#proveMany', () => { - let dataContract2; - - beforeEach(async () => { - dataContract2 = new DataContract(dataContract.toObject()); - dataContract2.id = generateRandomIdentifier(); - }); - - it('should should return proof if Data Contract not found', async () => { - const result = await repository.proveMany([dataContract.getId(), dataContract2.getId()]); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof', async () => { - await store.getDrive().createContract(dataContract, blockInfo, false); - await store.getDrive().createContract(dataContract2, blockInfo, false); - - const result = await repository.proveMany([dataContract.getId(), dataContract2.getId()]); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equals(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - // TODO enable this test when we support transactions - it.skip('should return proof using transaction', async () => { - await store.startTransaction(); - - await store.getDrive().createContract(dataContract, blockInfo, true); - await store.getDrive().createContract(dataContract2, blockInfo, true); - - const notFoundDataContractResult = await repository.prove( - [dataContract.getId(), dataContract2.getId()], { - useTransaction: false, - }, - ); - - expect(notFoundDataContractResult.getValue()).to.be.null(); - - const transactionalDataContractResult = await repository.proveMany( - [dataContract.getId(), dataContract2.getId()], - { useTransaction: true }, - ); - - const transactionalDataContract = transactionalDataContractResult.getValue(); - - expect(transactionalDataContract).to.be.an.instanceof(Buffer); - - await store.commitTransaction(); - - const storedDataContractResult = await repository.proveMany( - [dataContract.getId(), dataContract2.getId()], - ); - - const storedDataContract = storedDataContractResult.getValue(); - - expect(storedDataContract).to.be.an.instanceof(Buffer); - }); - }); -}); diff --git a/packages/js-drive/test/integration/document/DocumentRepository.spec.js b/packages/js-drive/test/integration/document/DocumentRepository.spec.js deleted file mode 100644 index 803e6673f77..00000000000 --- a/packages/js-drive/test/integration/document/DocumentRepository.spec.js +++ /dev/null @@ -1,3408 +0,0 @@ -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const Document = require('@dashevo/dpp/lib/document/Document'); -const DataContractFactory = require('@dashevo/dpp/lib/dataContract/DataContractFactory'); -const createDPPMock = require('@dashevo/dpp/lib/test/mocks/createDPPMock'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); -const createDocumentTypeTreePath = require('../../../lib/document/groveDB/createDocumentTreePath'); -const InvalidQueryError = require('../../../lib/document/errors/InvalidQueryError'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -function ucFirst(string) { - return string.charAt(0).toUpperCase() + string.slice(1); -} - -const typesTestCases = { - number: { - type: 'number', - value: 1, - }, - boolean: { - type: 'boolean', - value: true, - }, - string: { - type: 'string', - value: 'test', - }, - null: { - type: 'null', - value: null, - }, - undefined: { - type: 'undefined', - value: undefined, - }, - object: { - type: 'object', - value: {}, - }, - buffer: { - type: 'buffer', - value: Buffer.alloc(32), - }, -}; - -const notObjectTestCases = [ - typesTestCases.number, - typesTestCases.boolean, - typesTestCases.string, - typesTestCases.null, -]; - -const notArrayTestCases = [ - typesTestCases.number, - typesTestCases.boolean, - typesTestCases.string, - typesTestCases.null, - typesTestCases.object, -]; - -const nonScalarTestCases = [ - typesTestCases.null, - typesTestCases.undefined, - typesTestCases.object, -]; - -const scalarTestCases = [ - typesTestCases.number, - typesTestCases.string, - typesTestCases.boolean, - typesTestCases.buffer, -]; - -const nonNumberTestCases = [ - typesTestCases.string, - typesTestCases.boolean, - typesTestCases.null, - typesTestCases.undefined, - typesTestCases.object, - typesTestCases.buffer, -]; - -const nonNumberNullAndUndefinedTestCases = [ - typesTestCases.string, - typesTestCases.boolean, - typesTestCases.object, - typesTestCases.buffer, -]; - -const validFieldNameTestCases = [ - 'a', - 'a.b', - 'a.b.c', - 'array.element', - 'a.0', - 'a.0.b', - 'a_._b', - 'a-b.c_', - '$id', - '$ownerId', - '$createdAt', - '$updatedAt', -]; - -const invalidFieldNameTestCases = [ - '$a', - '$#1321', - 'a...', - '.a', - 'a.b.c.', -]; - -const validOrderByOperators = [ - { - operator: '>', - value: 42, - documentType: 'documentNumber', - }, - { - operator: '<', - value: 42, - documentType: 'documentNumber', - }, - { - operator: 'startsWith', - value: 'rt-', - documentType: 'documentString', - }, - { - operator: 'in', - value: [1, 2], - documentType: 'documentNumber', - }, -]; - -const queryDocumentSchema = { - testDocument: { - type: 'object', - properties: { - firstName: { - type: 'string', - }, - lastName: { - type: 'string', - }, - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - c: { - type: 'integer', - }, - d: { - type: 'integer', - }, - e: { - type: 'integer', - }, - }, - required: ['$createdAt'], - additionalProperties: false, - indices: [ - { - name: 'one', - properties: [ - { firstName: 'asc' }, - ], - }, - { - name: 'two', - properties: [ - { a: 'asc' }, - { b: 'asc' }, - { c: 'asc' }, - { d: 'asc' }, - { e: 'asc' }, - ], - }, - { - name: 'three', - properties: [ - { firstName: 'asc' }, - { lastName: 'asc' }, - ], - }, - ], - }, - documentA: { - type: 'object', - properties: { - firstName: { - type: 'string', - }, - }, - additionalProperties: false, - indices: [ - { - name: 'one', - properties: [{ $id: 'asc' }], - }, - ], - }, - documentB: { - type: 'object', - additionalProperties: false, - properties: { - firstName: { - type: 'string', - }, - }, - indices: [ - { - properties: [{ $id: 'asc' }], - unique: true, - }, - ], - }, - documentC: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - }, - indices: [ - { - properties: [{ a: 'asc' }, { b: 'asc' }], - }, - ], - }, - documentD: { - // no index - type: 'object', - additionalProperties: false, - properties: { - firstName: { - type: 'string', - }, - }, - }, - documentE: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'string', - }, - b: { - type: 'string', - }, - }, - indices: [ - { - properties: [{ a: 'asc' }, { b: 'asc' }], - }, - ], - }, - documentF: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - c: { - type: 'integer', - }, - }, - indices: [ - { - properties: [{ a: 'asc' }, { b: 'asc' }, { c: 'asc' }], - }, - ], - }, - documentG: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - }, - indices: [ - { - properties: [{ b: 'asc' }, { a: 'asc' }], - }, - { - properties: [{ a: 'asc' }, { b: 'asc' }], - }, - ], - }, - documentH: { - type: 'object', - additionalProperties: false, - properties: { - firstName: { - type: 'string', - }, - }, - indices: [ - { - properties: [{ $updatedAt: 'asc' }], - }, - ], - required: ['$updatedAt'], - }, - documentI: { - type: 'object', - additionalProperties: false, - properties: { - firstName: { - type: 'string', - }, - }, - indices: [ - { - properties: [{ $createdAt: 'asc' }], - }, - ], - required: ['$createdAt'], - }, - documentJ: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - c: { - type: 'integer', - }, - d: { - type: 'integer', - }, - e: { - type: 'integer', - }, - }, - indices: [ - { - name: 'index1', - properties: [ - { a: 'asc' }, - { b: 'asc' }, - { c: 'asc' }, - { d: 'asc' }, - { e: 'asc' }, - ], - unique: true, - }, - ], - }, - documentK: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'string', - }, - b: { - type: 'string', - }, - }, - indices: [ - { - properties: [{ b: 'asc' }], - }, - ], - }, - documentL: { - type: 'object', - additionalProperties: false, - properties: { - a: { - type: 'integer', - }, - b: { - type: 'integer', - }, - c: { - type: 'integer', - }, - d: { - type: 'integer', - }, - }, - indices: [ - { - name: 'index1', - properties: [ - { a: 'asc' }, - { b: 'asc' }, - { c: 'asc' }, - { d: 'asc' }, - ], - unique: true, - }, - ], - }, -}; - -for (const fieldName of validFieldNameTestCases) { - queryDocumentSchema[`document${fieldName}`] = { - type: 'object', - properties: { - [fieldName]: { - type: 'integer', - }, - }, - additionalProperties: false, - indices: [ - { - name: 'one', - properties: [{ [fieldName]: 'asc' }], - }, - ], - }; -} - -for (const type of ['number', 'string', 'boolean', 'buffer']) { - const properties = { - a: { - type, - }, - }; - - if (type === 'buffer') { - properties.a.type = 'array'; - properties.a.byteArray = true; - } - - queryDocumentSchema[`document${ucFirst(type)}`] = { - type: 'object', - properties, - additionalProperties: false, - indices: [ - { - name: 'one', - properties: [{ a: 'asc' }], - }, - ], - }; -} - -queryDocumentSchema.documentBig = { - type: 'object', - properties: Array(256).fill().map((v, i) => `a${i}`).reduce((res, key) => { - res[key] = { - type: 'integer', - }; - - return res; - }, {}), - additionalProperties: false, - indices: Array(256).fill().map((v, i) => ({ - properties: [{ [`a${i}`]: 'asc' }], - })), -}; - -const validQueries = [ - {}, - { - where: [['$id', 'in', [ - generateRandomIdentifier(), - generateRandomIdentifier(), - generateRandomIdentifier(), - ]]], - orderBy: [['$id', 'asc']], - }, - { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['c', '==', 3], - ['d', 'in', [1, 2]], - ], - orderBy: [ - ['d', 'desc'], - ['e', 'asc'], - ], - }, - { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['c', '==', 3], - ['d', 'in', [1, 2]], - ['e', '>', 3], - ], - orderBy: [ - ['d', 'desc'], - ['e', 'asc'], - ], - }, - { - where: [ - ['firstName', '>', 'Chris'], - ['firstName', '<=', 'Noellyn'], - ], - orderBy: [ - ['firstName', 'asc'], - ], - }, - { - where: [ - ['firstName', '==', '1'], - ['lastName', '==', '2'], - ], - limit: 1, - }, -]; - -const invalidQueries = [ - { - query: { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ], - }, - error: 'query is too far from index: query must better match an existing index', - }, - { - query: { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['c', 'in', [1, 2]], - ], - orderBy: [ - ['c', 'desc'], - ], - }, - error: 'where clause on non indexed property error: query must be for valid indexes', - }, - { - query: { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['b', 'in', [1, 2]], - ], - orderBy: [ - ['b', 'desc'], - ], - }, - error: 'duplicate non groupable clause on same field error: in clause has same field as an equality clause', - }, - { - query: { - where: [ - ['z', '==', 1], - ], - }, - error: 'where clause on non indexed property error: query must be for valid indexes', - }, - { - query: { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['c', '>', 3], - ['d', 'in', [1, 2]], - ['e', '>', 3], - ], - }, - error: 'multiple range clauses error: all ranges must be on same field', - }, - { - query: { - where: [ - ['a', '==', 1], - ['b', '==', 2], - ['c', '>', 3], - ['d', '>', 3], - ], - orderBy: [ - ['c', 'asc'], - ['d', 'desc'], - ], - }, - error: 'multiple range clauses error: all ranges must be on same field', - }, - { - query: { - where: [ - ['a', '==', 3], - ['b', '==', 2], - ['c', '>', 1], - ], - }, - error: 'missing order by for range error: query must have an orderBy field for each range element', - }, - { - query: { - where: [ - ['a', '==', 3], - ['b', '==', 2], - ['c', '==', 3], - ['d', 'in', [1, 2]], - ['e', '<', 1], - ], - orderBy: [ - ['e', 'asc'], - ['d', 'asc'], - ], - }, - error: 'where clause on non indexed property error: query must be for valid indexes', - }, - { - query: 'abc', - error: 'deserialization error: unable to decode query from cbor', - }, - { - query: [], - error: 'deserialization error: unable to decode query from cbor', - }, - { - query: { where: [1, 2, 3] }, - error: 'query invalid format for where clause error: where clause must be an array', - }, - { - query: { invalid: 'query' }, - error: 'unsupported error: unsupported syntax in where clause', - }, -]; - -const invalidOperators = ['<<', '<==', '===', '!>', '>>=']; - -async function createDocuments(documentRepository, documents, blockInfo) { - return Promise.all( - documents.map(async (o) => { - const result = await documentRepository.create(o, blockInfo); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - }), - ); -} - -describe('DocumentRepository', function main() { - this.timeout(30000); - - let documentRepository; - let dataContractRepository; - let container; - let dataContract; - let queryDataContract; - let documents; - let document; - let documentSchema; - let blockInfo; - - beforeEach(async function beforeEach() { - const now = 86400; - container = await createTestDIContainer(); - - dataContract = getDataContractFixture(); - documents = getDocumentsFixture(dataContract).slice(0, 5); - - [document] = documents; - - // Modify documents for the test cases - documents = documents.map((doc, i) => { - const currentDocument = doc; - // const arrayItem = { item: i + 1, flag: true }; - - currentDocument.set('order', i); - currentDocument.set('$createdAt', now); - // currentDocument.set('arrayWithScalar', Array(i + 1) - // .fill(1) - // .map((item, index) => i + index)); - // currentDocument.set('arrayWithObjects', Array(i + 1).fill(arrayItem)); - currentDocument.type = document.getType(); - - return currentDocument; - }); - - [document] = documents; - - dataContract.documents[document.getType()].properties = { - ...dataContract.documents[document.getType()].properties, - name: { - type: 'string', - maxLength: 63, - }, - order: { - type: 'number', - }, - lastName: { - type: 'string', - maxLength: 63, - }, - // arrayWithScalar: { - // type: 'array', - // items: [ - // { type: 'string' }, - // ], - // }, - // arrayWithObjects: { - // type: 'array', - // items: { - // type: 'object', - // properties: { - // flag: { - // type: 'string', - // }, - // }, - // }, - // }, - }; - - const documentsSchema = dataContract.getDocuments(); - - documentSchema = documentsSchema[document.getType()]; - - // redeclare indices - const indices = documentSchema.indices || []; - documentSchema.indices = indices.concat([ - { - name: 'index1', - properties: [{ name: 'asc' }], - }, - // { - // name: 'index2', - // - // properties: [{ name: 'asc' }, { 'arrayWithObjects.item': 'asc' }], - // }, - { - name: 'index3', - properties: [{ order: 'asc' }], - }, - { - name: 'index4', - properties: [{ lastName: 'asc' }], - }, - // { - // name: 'index5', - // properties: [{ arrayWithScalar: 'asc' }], - // }, - // { - // name: 'index6', - // properties: [{ arrayWithObjects: 'asc' }], - // }, - // { - // name: 'index7', - // properties: [{ 'arrayWithObjects.item': 'asc' }], - // }, - // { - // name: 'index8', - // properties: [{ 'arrayWithObjects.flag': 'asc' }], - // }, - // { - // name: 'index9', - // properties: [{ primaryOrder: 'asc' }, { order: 'desc' }], - // }, - { - name: 'index10', - properties: [{ $ownerId: 'asc' }], - }, - ]); - - const dpp = container.resolve('dpp'); - queryDataContract = dpp.dataContract.create(generateRandomIdentifier(), queryDocumentSchema); - - documentRepository = container.resolve('documentRepository'); - documentRepository.logger = { - info: this.sinon.stub(), - }; - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(); - - dataContractRepository = container.resolve('dataContractRepository'); - - blockInfo = new BlockInfo(1, 1, Date.now()); - - await dataContractRepository.create(dataContract, blockInfo); - await dataContractRepository.create(queryDataContract, blockInfo); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - describe('#create', () => { - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - }); - - it('should create Document', async () => { - const documentTypeTreePath = createDocumentTypeTreePath( - document.getDataContract(), - document.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - const result = await documentRepository - .storage - .db - .get(documentTreePath, document.getId().toBuffer(), false); - - expect(document.toBuffer()).to.deep.equal(result.value); - }); - - it('should create Document in transaction', async () => { - await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - ); - - await documentRepository - .storage - .startTransaction(); - - await documentRepository.create(document, blockInfo, { - useTransaction: true, - }); - - const documentTypeTreePath = createDocumentTypeTreePath( - document.getDataContract(), - document.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - const transactionDocument = await documentRepository - .storage - .db - .get(documentTreePath, document.getId().toBuffer(), true); - - try { - await documentRepository - .storage - .db - .get(documentTreePath, document.getId().toBuffer(), false); - - expect.fail('should fail with NotFoundError error'); - } catch (e) { - expect(e.message.startsWith('grovedb: path key not found: key not found in Merk')).to.be.true(); - } - - await documentRepository.storage.commitTransaction(); - - const createdDocument = await documentRepository - .storage - .db - .get(documentTreePath, document.getId().toBuffer(), false); - - expect(document.toBuffer()).to.deep.equal(transactionDocument.value); - expect(document.toBuffer()).to.deep.equal(createdDocument.value); - }); - - it('should not create Document on dry run', async () => { - await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - ); - - await documentRepository.create(document, blockInfo, { - dryRun: true, - }); - - const documentTypeTreePath = createDocumentTypeTreePath( - document.getDataContract(), - document.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - try { - await documentRepository - .storage - .db - .get(documentTreePath, document.getId().toBuffer()); - - expect.fail('should fail with NotFoundError error'); - } catch (e) { - expect(e.message.startsWith('grovedb: path key not found: key not found in Merk')).to.be.true(); - } - }); - }); - - describe('#update', () => { - let replaceDocument; - - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - - replaceDocument = new Document({ - ...documents[1].toObject(), - lastName: 'NotSoShiny', - }, dataContract); - }); - - it('should update Document', async () => { - const updateResult = await documentRepository.update(replaceDocument, blockInfo); - - expect(updateResult).to.be.instanceOf(StorageResult); - expect(updateResult.getOperations().length).to.be.greaterThan(0); - - const documentTypeTreePath = createDocumentTypeTreePath( - replaceDocument.getDataContract(), - replaceDocument.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - const result = await documentRepository - .storage - .db - .get(documentTreePath, replaceDocument.getId().toBuffer(), false); - - expect(replaceDocument.toBuffer()).to.deep.equal(result.value); - }); - - it('should store Document in transaction', async () => { - await documentRepository - .storage - .startTransaction(); - - const updateResult = await documentRepository.update(replaceDocument, blockInfo, { - useTransaction: true, - }); - - expect(updateResult).to.be.instanceOf(StorageResult); - expect(updateResult.getOperations().length).to.be.greaterThan(0); - - const documentTypeTreePath = createDocumentTypeTreePath( - replaceDocument.getDataContract(), - replaceDocument.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - const transactionDocument = await documentRepository - .storage - .db - .get(documentTreePath, replaceDocument.getId().toBuffer(), true); - - const notUpdatedDocument = await documentRepository - .storage - .db - .get(documentTreePath, replaceDocument.getId().toBuffer(), false); - - await documentRepository.storage.commitTransaction(); - - const createdDocument = await documentRepository - .storage - .db - .get(documentTreePath, replaceDocument.getId().toBuffer(), false); - - expect(replaceDocument.toBuffer()).to.deep.equal(transactionDocument.value); - expect(replaceDocument.toBuffer()).to.deep.equal(createdDocument.value); - expect(documents[1].toBuffer()).to.deep.equal(notUpdatedDocument.value); - }); - - it('should not update Document on dry run', async () => { - const updateResult = await documentRepository.update(replaceDocument, blockInfo, { - dryRun: true, - }); - - expect(updateResult).to.be.instanceOf(StorageResult); - expect(updateResult.getOperations().length).to.be.greaterThan(0); - - const documentTypeTreePath = createDocumentTypeTreePath( - replaceDocument.getDataContract(), - replaceDocument.getType(), - ); - - const documentTreePath = documentTypeTreePath.concat( - [Buffer.from([0])], - ); - - const notUpdatedDocument = await documentRepository - .storage - .db - .get(documentTreePath, replaceDocument.getId().toBuffer(), false); - - expect(documents[1].toBuffer()).to.deep.equal(notUpdatedDocument.value); - }); - }); - - describe('#find', () => { - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - }); - - it('should find all existing documents', async () => { - const result = await documentRepository.find(dataContract, document.getType()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(documents.length); - - const foundDocumentsBuffers = foundDocuments.map((doc) => doc.toBuffer()); - - expect(foundDocumentsBuffers).to.have.deep.members(documents.map((doc) => doc.toBuffer())); - }); - - it('should find all existing documents in transaction', async () => { - await documentRepository - .storage - .startTransaction(); - - const foundDocumentsResult = await documentRepository - .find(dataContract, document.getType(), { - useTransaction: true, - }); - - expect(foundDocumentsResult).to.be.instanceOf(StorageResult); - expect(foundDocumentsResult.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = foundDocumentsResult.getValue(); - - await documentRepository.storage.commitTransaction(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(documents.length); - - const foundDocumentsBuffers = foundDocuments.map((doc) => doc.toBuffer()); - - expect(foundDocumentsBuffers).to.have.deep.members(documents.map((doc) => doc.toBuffer())); - }); - - it('should fetch Documents with dry run', async () => { - await documentRepository - .storage - .startTransaction(); - - const foundDocumentsResult = await documentRepository - .find(dataContract, document.getType(), { - dryRun: true, - }); - - expect(foundDocumentsResult).to.be.instanceOf(StorageResult); - expect(foundDocumentsResult.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = foundDocumentsResult.getValue(); - - await documentRepository.storage.commitTransaction(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(documents.length); - - const foundDocumentsBuffers = foundDocuments.map((doc) => doc.toBuffer()); - - expect(foundDocumentsBuffers).to.have.deep.members(documents.map((doc) => doc.toBuffer())); - }); - - describe('queries', () => { - describe('valid queries', () => { - validQueries.forEach((query) => { - it(`should return valid result for query "${JSON.stringify(query)}"`, async () => { - const result = await documentRepository.find(queryDataContract, 'testDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - it('should return valid result if data contract has only system properties', async () => { - const schema = { - chat: { - type: 'object', - indices: [ - { - name: 'ownerAndCreatedAt', - properties: [ - { - $ownerId: 'asc', - }, - { - $createdAt: 'asc', - }, - ], - }, - ], - properties: { - test: { - type: 'string', - }, - }, - required: ['$createdAt'], - additionalProperties: false, - }, - }; - - const factory = new DataContractFactory(createDPPMock(), () => {}); - const ownerId = generateRandomIdentifier(); - const myDataContract = factory.create(ownerId, schema); - await dataContractRepository.create(myDataContract, blockInfo); - - const result = await documentRepository.find(myDataContract, 'chat', { - where: [ - ['$ownerId', '==', ownerId], - ['$createdAt', '>', new Date().getTime()], - ], - orderBy: [['$createdAt', 'asc']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return valid result for DPNS contract', async () => { - const schema = { - label: { - type: 'object', - properties: { - normalizedLabel: { - type: 'string', - }, - normalizedParentDomainName: { - type: 'string', - }, - }, - indices: [ - { - name: 'index1', - properties: [ - { - normalizedParentDomainName: 'asc', - }, - { - normalizedLabel: 'asc', - }, - ], - unique: true, - }, - ], - }, - }; - - const factory = new DataContractFactory(createDPPMock(), () => {}); - const ownerId = generateRandomIdentifier(); - const myDataContract = factory.create(ownerId, schema); - await dataContractRepository.create(myDataContract, blockInfo); - - const result = await documentRepository.find(myDataContract, 'label', { - where: [ - ['normalizedParentDomainName', '==', 'dash'], - ], - orderBy: [['normalizedLabel', 'asc']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - describe('invalid queries', () => { - invalidQueries.forEach(({ query, error }) => { - it(`should throw InvalidQueryError for query "${JSON.stringify(query)}"`, async () => { - try { - await documentRepository.find(queryDataContract, 'testDocument', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(error); - } - }); - }); - - notObjectTestCases.forEach(({ type, value: query }) => { - it(`should return invalid result if query is a ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentA', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('deserialization error: unable to decode query from cbor'); - } - }); - }); - }); - - describe('where', () => { - it('should return empty array if where clause conditions do not match', async () => { - const query = { - where: [['name', '==', 'Dash enthusiast']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.have.lengthOf(0); - }); - - it.skip('should find documents by nested object fields', async () => { - const query = { - where: [ - ['arrayWithObjects.item', '==', 2], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.an('array'); - expect(result).to.be.lengthOf(1); - - const [expectedDocument] = result; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[1].toBuffer()); - }); - - it.skip('should return documents by several conditions', async () => { - const query = { - where: [ - ['name', '==', 'Cutie'], - ['arrayWithObjects.item', '==', 1], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.an('array'); - expect(result).to.be.lengthOf(1); - - const [expectedDocument] = result; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[0].toBuffer()); - }); - - notArrayTestCases.forEach(({ type, value: query }) => { - it(`should return invalid result if "where" is not an array, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentA', { where: query }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('query invalid format for where clause error: where clause must be an array'); - } - }); - }); - - it('should return invalid result if "where" contains more than 10 conditions', async () => { - const where = Array(11).fill(['a', '<', 1]); - try { - await documentRepository.find(queryDataContract, 'documentA', { where }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('multiple range clauses error: there can only be at most 2 range clauses that must be on the same field'); - } - }); - - it('should return invalid result if "where" contains conflicting conditions', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '<', 1], - ['a', '>', 1], - ], - orderBy: [['a', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); - - it('should return invalid result if number of properties queried does not match number of indexed ones minus 2', async () => { - try { - await documentRepository.find(queryDataContract, 'documentL', { - where: [ - ['a', '==', 1], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('query is too far from index: query must better match an existing index'); - } - }); - - describe('condition', () => { - describe('property', () => { - it('should return valid result if condition contains "$id" field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentB', { - where: - [['$id', '==', generateRandomIdentifier()]], - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.isEmpty()).to.be.true(); - }); - - it('should return valid result if condition contains top-level field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentE', { - where: [ - ['a', '==', '1'], - ], - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.isEmpty()).to.be.true(); - }); - - it.skip('should return valid result if condition contains nested path field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentD', { - where: - [['a.b', '==', '1']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return invalid result if property is not specified in document indices', async () => { - try { - await documentRepository.find(queryDataContract, 'documentD', { - where: [ - ['a', '==', '1'], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - }); - - it('should return invalid result if condition array has less than 3 elements (field, operator, value)', async () => { - try { - await documentRepository.find(queryDataContract, 'documentA', { - where: - [['a', '==']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid where clause components error: where clauses should have at most 3 components'); - } - }); - - it('should return invalid result if condition array has more than 3 elements (field, operator, value)', async () => { - try { - await documentRepository.find(queryDataContract, 'documentA', { - where: [ - [['a', '==', '1', '2']], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid where clause components error: where clauses should have at most 3 components'); - } - }); - - describe('operators', () => { - describe('comparisons', () => { - invalidOperators.forEach((operator) => { - it('should return invalid result if condition contains invalid comparison operator', async () => { - const query = { where: [['a', operator, '1']] }; - if (operator !== '===') { - query.orderBy = [['a', 'asc']]; - } - - try { - await documentRepository.find(queryDataContract, 'documentE', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid where clause components error: second field of where component should be a known operator'); - } - }); - }); - - describe('<', () => { - it('should find documents with "<" operator', async () => { - const query = { - where: [['order', '<', documents[1].get('order')]], - orderBy: [['order', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[0].toBuffer()); - }); - - it('should return invalid result if "<" operator used with a string value longer than 255 bytes', async () => { - const longString = 't'.repeat(255); - - const result = await documentRepository.find( - queryDataContract, - 'documentString', - { - where: [['a', '<', longString]], - orderBy: [['a', 'asc']], - }, - ); - - expect(result).to.be.instanceOf(StorageResult); - - const veryLongString = 't'.repeat(256); - - try { - await documentRepository.find( - queryDataContract, - 'documentString', - { - where: [['a', '<', veryLongString]], - orderBy: [['a', 'asc']], - }, - ); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('field requirement unmet: value must be less than 256 bytes long'); - } - }); - - nonScalarTestCases.forEach(({ type, value }) => { - it(`should return invalid result if "<" operator used with a not scalar value, but ${type}`, async function it() { - if ((typeof value === 'object' && value === null) || typeof value === 'undefined') { - this.skip('will be implemented later'); - } - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', '<', value]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: structure error: value is not a float'); - } - }); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if "<" operator used with a scalar value ${type}`, async () => { - const docType = `document${ucFirst(type)}`; - - const result = await documentRepository.find(queryDataContract, docType, { where: [['a', '<', value]], orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - }); - - describe('<=', () => { - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if "<=" operator used with a scalar value ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, `document${ucFirst(type)}`, { where: [['a', '<=', value]], orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - it('should find Documents using "<=" operator', async () => { - const query = { - where: [['order', '<=', documents[1].get('order')]], - orderBy: [['order', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(2); - - const expectedDocuments = documents.slice(0, 2).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members( - expectedDocuments, - ); - }); - }); - - describe('==', () => { - it('should find existing documents using "==" operator', async () => { - const query = { - where: [['name', '==', document.get('name')]], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(document.toBuffer()); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if "==" operator used with a scalar value ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, `document${ucFirst(type)}`, { where: [['a', '==', value]] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - }); - - describe('=>', () => { - it('should find existing documents using ">=" operator', async () => { - const query = { - where: [['order', '>=', documents[1].get('order')]], - orderBy: [['order', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(documents.length - 1); - - documents.shift(); - const expectedDocuments = documents - .map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members( - expectedDocuments, - ); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if ">=" operator used with a scalar value ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, `document${ucFirst(type)}`, { where: [['a', '>=', value]], orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - }); - - describe('>', () => { - it('should find existing documents using ">" operator', async () => { - const query = { - where: [['order', '>', documents[1].get('order')]], - orderBy: [['order', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(documents.length - 2); - - const expectedDocuments = documents - .splice(2, documents.length) - .map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members( - expectedDocuments, - ); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if ">" operator used with a scalar value ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, `document${ucFirst(type)}`, { where: [['a', '>', value]], orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - }); - - ['>', '<', '<=', '>='].forEach((operator) => { - it(`should return invalid results if "${operator}" used not in the last 2 where conditions`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', operator, 1], - ['a', 'startsWith', 'rt-'], - ['a', 'startsWith', 'r-'], - ], - orderBy: [['a', 'asc']], - }); - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('range clauses not groupable error: clauses are not groupable'); - } - }); - }); - - describe('ranges', () => { - describe('multiple ranges', () => { - ['>', '<', '<=', '>='].forEach((firstOperator) => { - ['>', '<', '>=', '<='].forEach((secondOperator) => { - it(`should return invalid result if ${firstOperator} operator used with ${secondOperator} operator`, async () => { - const query = { where: [['a', firstOperator, '1'], ['b', secondOperator, 'a']] }; - - try { - await documentRepository.find(queryDataContract, 'documentE', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('multiple range clauses error: all ranges must be on same field'); - } - }); - }); - }); - - ['>', '<', '<=', '>='].forEach((firstOperator) => { - it(`should return invalid result if ${firstOperator} operator used with startsWith operator`, async () => { - const query = { where: [['a', firstOperator, '1'], ['b', 'startsWith', 'a']] }; - - try { - await documentRepository.find(queryDataContract, 'documentE', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('range clauses not groupable error: clauses are not groupable'); - } - }); - }); - - it('should return invalid result if startsWith operator used with startsWith operator', async () => { - const query = { where: [['a', 'startsWith', '1'], ['b', 'startsWith', 'a']] }; - - try { - await documentRepository.find(queryDataContract, 'documentE', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('multiple range clauses error: there can not be more than 1 non groupable range clause'); - } - }); - }); - - describe('conflicting operators', () => { - const conflictingOperators = [ - { - operators: ['>', '>'], - errorMessage: 'multiple range clauses error: there can only at most one range clause with a lower bound', - }, - { - operators: ['>', '=>'], - errorMessage: 'invalid where clause components error: second field of where component should be a known operator', - }, - { - operators: ['<', '<'], - errorMessage: 'range clauses not groupable error: lower and upper bounds must be passed if providing 2 ranges', - }, - { - operators: ['<', '<='], - errorMessage: 'range clauses not groupable error: lower and upper bounds must be passed if providing 2 ranges', - }, - ]; - - conflictingOperators.forEach(({ errorMessage, operators }) => { - it(`should return invalid result if ${operators[0]} operator used with ${operators[1]} operator`, async () => { - const query = { - where: [['a', operators[0], '1'], ['a', operators[1], 'a']], - orderBy: [['a', 'asc']], - }; - - try { - await documentRepository.find(queryDataContract, 'documentE', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(errorMessage); - } - }); - }); - }); - - it('should return invalid result if "in" operator is used before last two indexed conditions', async () => { - const query = { where: [['a', 'in', [1, 2]]] }; - - try { - await documentRepository.find(queryDataContract, 'documentF', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - // TODO is it correct ?????? - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - - ['>', '<', '>=', '<='].forEach((operator) => { - it(`should return invalid result if ${operator} operator is used before "=="`, async () => { - const query = { where: [['a', operator, 2], ['b', '==', 1]], orderBy: [['a', 'asc']] }; - - try { - await documentRepository.find(queryDataContract, 'documentF', query); - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - // TODO is it correct? - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - }); - - ['>', '<', '>=', '<='].forEach((operator) => { - it(`should return valid result if ${operator} operator is used before "in"`, async () => { - const query = { where: [['a', operator, 2], ['b', 'in', [1, 2]]], orderBy: [['a', 'asc'], ['b', 'asc']] }; - - const result = await documentRepository.find(queryDataContract, 'documentG', query); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - it('should return invalid result if "in" or range operators are not in orderBy', async () => { - const query = { - where: [ - ['a', '==', 1], - ['b', '>', 1], - ], - orderBy: [['b', 'asc']], - }; - - delete query.orderBy; - - try { - await documentRepository.find(queryDataContract, 'documentF', query); - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - }); - }); - - describe('timestamps', () => { - nonNumberNullAndUndefinedTestCases.forEach(({ type, value }) => { - it(`should return invalid result if $createdAt timestamp used with ${type} value`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentI', { where: [['$createdAt', '>', value]], orderBy: [['$createdAt', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e.message).to.startsWith( - 'value error: structure error: value is not an integer', - ); - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); - }); - - nonNumberNullAndUndefinedTestCases.forEach(({ type, value }) => { - it(`should return invalid result if $updatedAt timestamp used with ${type} value`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentH', { where: [['$updatedAt', '>', value]], orderBy: [['$updatedAt', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.startsWith( - 'value error: structure error: value is not an integer', - ); - } - }); - }); - - it('should return valid result if condition contains "$createdAt" field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentI', { where: [['$createdAt', '==', Date.now()]] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return valid result if condition contains "$updatedAt" field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentH', { where: [['$updatedAt', '==', Date.now()]] }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - describe('in', () => { - it('should return valid result if "in" operator used with an array value', async () => { - const query = { - where: [ - ['$id', 'in', [ - documents[0].getId(), - documents[1].getId(), - ]], - ], - orderBy: [['$id', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(2); - - const expectedDocuments = documents.slice(0, 2).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members( - expectedDocuments, - ); - }); - - notArrayTestCases.forEach(({ type, value }) => { - it(`should return invalid result if "in" operator used with not an array value, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', value]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid IN clause error: when using in operator you must provide an array of values'); - } - }); - }); - - it('should return invalid result if "in" operator used with an empty array value', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', []]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid IN clause error: in clause must at least 1 value'); - } - }); - - it('should return invalid result if "in" operator used with an array value which contains more than 100 elements', async () => { - const arr = []; - - for (let i = 0; i < 100; i++) { - arr.push(i); - } - - const result = await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', arr]], orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - - arr.push(101); - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', arr]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid IN clause error: in clause must at most 100 values'); - } - }); - - it('should return invalid result if "in" operator used with an array which contains not unique elements', async () => { - const arr = [1, 1]; - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', arr]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid IN clause error: there should be no duplicates values for In query'); - } - }); - - it('should return invalid results if "in" condition contains an array as an element', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where: [['a', 'in', [[]]]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: structure error: value is not a float'); - } - }); - }); - - describe('startsWith', () => { - it('should return valid result if "startsWith" operator used with a string value', async () => { - const query = { - where: [['lastName', 'startsWith', 'Swe']], - orderBy: [['lastName', 'asc']], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[2].toBuffer()); - }); - - it('should return invalid result if "startsWith" operator used with an empty string value', async () => { - try { - await documentRepository.find(queryDataContract, 'documentString', { where: [['a', 'startsWith', '']], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('starts with illegal string error: starts with can not start with an empty string'); - } - }); - - it('should return invalid result if "startsWith" operator used with a string value which is more than 255 bytes long', async () => { - const value = 'b'.repeat(256); - try { - await documentRepository.find(queryDataContract, 'documentString', { where: [['a', 'startsWith', value]], orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('field requirement unmet: value must be less than 256 bytes long'); - } - }); - - [ - typesTestCases.number, - typesTestCases.boolean, - typesTestCases.object, - typesTestCases.buffer, - ].forEach(({ type, value }) => { - it(`should return invalid result if "startWith" operator used with a not string value, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentString', { where: [['a', 'startsWith', value]], orderBy: [['a', 'asc']] }); - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value wrong type error: document field type doesn\'t match document value'); - } - }); - }); - - [ - typesTestCases.null, - typesTestCases.undefined, - ].forEach(({ type, value }) => { - it(`should return invalid result if "startWith" operator used with a not string value, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentString', { where: [['a', 'startsWith', value]], orderBy: [['a', 'asc']] }); - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid STARTSWITH clause error: starts with must have at least one character'); - } - }); - }); - }); - - describe.skip('elementMatch', () => { - it('should return valid result if "elementMatch" operator used with "where" conditions', async () => { - const query = { - where: [ - ['arrayWithObjects', 'elementMatch', [ - ['item', '==', 2], ['flag', '==', true], - ]], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[1].toBuffer()); - }); - - it('should return invalid result if "elementMatch" operator used with invalid "where" conditions', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['elem', 'startsWith', 1], ['elem', '<', 3]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if "elementMatch" operator used with less than 2 "where" conditions', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['elem', '>', 1]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if value contains conflicting conditions', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['elem', '>', 1], ['elem', '>', 1]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if $id field is specified', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['$id', '>', 1], ['$id', '<', 3]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if $ownerId field is specified', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['$ownerId', '>', 1], ['$ownerId', '<', 3]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if value contains nested "elementMatch" operator', async () => { - const query = { - where: [ - ['arr', 'elementMatch', - [['subArr', 'elementMatch', [ - ['subArrElem', '>', 1], ['subArrElem', '<', 3], - ]], ['subArr', '<', 3]], - ], - ], - }; - - try { - await documentRepository.find(queryDataContract, 'document', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - }); - - describe.skip('length', () => { - it('should return valid result if "length" operator used with a positive numeric value', async () => { - const query = { - where: [['arrayWithObjects', 'length', 2]], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[1].toBuffer()); - }); - - it('should return valid result if "length" operator used with zero', async () => { - const result = await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'length', 0], - ], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return invalid result if "length" operator used with a float numeric value', async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'length', 1.2], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if "length" operator used with a NaN', async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'length', NaN], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if "length" operator used with a numeric value which is less than 0', async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'length', -1], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - nonNumberTestCases.forEach(({ type, value }) => { - it(`should return invalid result if "length" operator used with a ${type} instead of numeric value`, async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'length', value], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - }); - }); - - describe.skip('contains', () => { - it('should find Documents using "contains" operator and array value', async () => { - const query = { - where: [ - ['arrayWithScalar', 'contains', [2, 3]], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(1); - - const [expectedDocument] = foundDocuments; - - expect(expectedDocument.toBuffer()).to.deep.equal(documents[2].toBuffer()); - }); - - it('should find Documents using "contains" operator and scalar value', async () => { - const query = { - where: [ - ['arrayWithScalar', 'contains', 2], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(2); - - const expectedDocuments = documents.slice(1, 3).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members( - expectedDocuments, - ); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if "contains" operator used with a scalar value ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', value], - ], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - scalarTestCases.forEach(({ type, value }) => { - it(`should return valid result if "contains" operator used with an array of scalar values ${type}`, async () => { - const result = await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', [value]], - ], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - it('should return invalid result if "contains" operator used with an array which has ' - + ' more than 100 elements', async () => { - const arr = []; - for (let i = 0; i < 100; i++) { - arr.push(i); - } - - const result = await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', arr], - ], - }); - - expect(result).to.be.instanceOf(StorageResult); - - arr.push(101); - - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', arr], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if "contains" operator used with an empty array', async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', []], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - it('should return invalid result if "contains" operator used with an array which contains not unique' - + ' elements', async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', [1, 1]], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - - nonScalarTestCases.forEach(({ type, value }) => { - it(`should return invalid result if used with non-scalar value ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', value], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - }); - - nonScalarTestCases.forEach(({ type, value }) => { - it(`should return invalid result if used with an array of non-scalar values ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'document', { - where: [ - ['arr', 'contains', [value]], - ], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(''); - } - }); - }); - }); - }); - }); - }); - - describe('limit', () => { - it('should limit return to 1 Document if limit is set', async () => { - const options = { - limit: 1, - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - options, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(1); - }); - - it('should limit result to 100 Documents if limit is not set', async () => { - // Store 101 document - for (let i = 0; i < 101; i++) { - const svDoc = document; - - svDoc.id = Identifier.from(Buffer.alloc(32, i + 1)); - await documentRepository.create(svDoc, blockInfo); - } - - const result = await documentRepository.find(dataContract, document.getType()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(100); - }); - - it('should return valid result if "limit" is a number', async () => { - const result = await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a', 'asc']], - limit: 1, - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return invalid result if "limit" is less than 0', async () => { - const where = [ - ['a', '>', 1], - ]; - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where, limit: -1, orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: integer out of bounds'); - } - }); - - it('should return invalid result if "limit" is 0', async () => { - const where = [ - ['a', '>', 1], - ]; - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where, limit: 0, orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('query invalid limit error: limit should be a integer from 1 to 100'); - } - }); - - it('should return invalid result if "limit" is bigger than 100', async () => { - const where = [ - ['a', '>', 1], - ]; - - const result = await documentRepository.find(queryDataContract, 'documentNumber', { where, limit: 100, orderBy: [['a', 'asc']] }); - - expect(result).to.be.instanceOf(StorageResult); - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where, limit: 101, orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('query invalid limit error: limit should be a integer from 1 to 100'); - } - }); - - it('should return invalid result if "limit" is a float number', async () => { - const where = [ - ['a', '>', 1], - ]; - - try { - await documentRepository.find(queryDataContract, 'documentNumber', { where, limit: 1.5, orderBy: [['a', 'asc']] }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: structure error: value is not an integer'); - } - }); - - nonNumberNullAndUndefinedTestCases.forEach(({ type, value }) => { - it(`should return invalid result if "limit" is not a number, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - limit: value, - orderBy: [['a', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: structure error: value is not an integer'); - } - }); - }); - }); - - describe('startAt', () => { - it('should return the second document using identifier', async () => { - const query = { - where: [ - ['order', '>=', 0], - ], - orderBy: [ - ['order', 'asc'], - ], - startAt: documents[1].getId(), - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - - const expectedDocuments = documents.splice(1).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members(expectedDocuments); - }); - - it('should return the second document using base58', async () => { - const query = { - where: [ - ['order', '>=', 0], - ], - orderBy: [ - ['order', 'asc'], - ], - startAt: documents[1].getId().toString(), - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - - const expectedDocuments = documents.splice(1).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members(expectedDocuments); - }); - - it('should throw InvalidQuery if document not found', async () => { - const options = { - startAt: Buffer.alloc(0), - }; - - try { - await documentRepository.find(dataContract, document.getType(), options); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidQueryError); - expect(e.message).to.equal('start document not found error: startAt document not found'); - } - }); - - [ - typesTestCases.boolean, - typesTestCases.null, - typesTestCases.object, - typesTestCases.number, - ].forEach(({ type, value }) => { - it(`should return invalid result if "startAt" is not a buffer, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - startAt: value, - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); - }); - }); - - describe('startAfter', () => { - it('should return Documents after 1 document', async () => { - const options = { - where: [ - ['order', '>=', 0], - ], - orderBy: [ - ['order', 'asc'], - ], - startAfter: documents[0].id, - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - options, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - - const expectedDocuments = documents.splice(1).map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.members(expectedDocuments); - }); - - it('should throw InvalidQuery if document not found', async () => { - const options = { - startAfter: Buffer.alloc(0), - }; - - try { - await documentRepository.find(dataContract, document.getType(), options); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidQueryError); - expect(e.message).to.equal('start document not found error: startAfter document not found'); - } - }); - - it('should return invalid result if both "startAt" and "startAfter" are present', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - startAfter: documents[1].getId(), - startAt: documents[1].getId(), - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('duplicate start conditions error: only one of startAt or startAfter should be provided'); - } - }); - - [ - typesTestCases.boolean, - typesTestCases.null, - typesTestCases.object, - typesTestCases.number, - ].forEach(({ type, value }) => { - it(`should return invalid result if "startAfter" is not a buffer, but ${type}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - startAfter: value, - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('value error: structure error: value are not bytes, a string, or an array of values representing bytes'); - } - }); - }); - }); - - describe('orderBy', () => { - it('should sort Documents in descending order', async () => { - const query = { - where: [ - ['order', '>=', 0], - ], - orderBy: [ - ['order', 'desc'], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - - const expectedDocuments = documents.reverse().map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.equal(expectedDocuments); - }); - - it('should sort Documents in ascending order', async () => { - const query = { - where: [ - ['order', '>=', 0], - ], - orderBy: [ - ['order', 'asc'], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - - const expectedDocuments = documents.map((doc) => doc.toBuffer()); - - expect(foundDocuments.map((doc) => doc.toBuffer())).to.deep.equal(expectedDocuments); - }); - - it('should sort Documents by $id', async () => { - await Promise.all( - documents.map((d) => documentRepository - .delete(dataContract, document.getType(), d.getId(), blockInfo)), - ); - - const createdIds = []; - let i = 0; - for (const svDoc of documents) { - svDoc.id = Identifier.from(Buffer.alloc(32, i + 1)); - await documentRepository.create(svDoc, blockInfo); - i++; - createdIds.push(svDoc.id); - } - - const query = { - where: [ - ['$id', 'in', createdIds], - ], - orderBy: [ - ['$id', 'desc'], - ], - }; - - const result = await documentRepository.find( - dataContract, - document.getType(), - query, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.be.lengthOf(documents.length); - - expect(foundDocuments[0].getId()).to.deep.equal(createdIds[4]); - expect(foundDocuments[1].getId()).to.deep.equal(createdIds[3]); - expect(foundDocuments[2].getId()).to.deep.equal(createdIds[2]); - expect(foundDocuments[3].getId()).to.deep.equal(createdIds[1]); - expect(foundDocuments[4].getId()).to.deep.equal(createdIds[0]); - }); - - it('should return valid result if "orderBy" contains 1 sorting field', async () => { - const result = await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a', 'asc']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return valid result if "orderBy" contains a second fields not used in where clause', async () => { - const result = await documentRepository.find(queryDataContract, 'documentC', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a', 'asc'], ['b', 'desc']], - }); - - expect(result).to.be.an.instanceOf(StorageResult); - }); - - it('should return invalid result if "orderBy" is an empty array', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - - it('should return invalid result if sorting applied to not range condition', async function it() { - this.skip('will be implemented later'); - - try { - await documentRepository.find(queryDataContract, 'documentString', { - where: [['a', '==', 'b']], - orderBy: [['a', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); - - it('should return valid result if there is no where conditions', async () => { - const result = await documentRepository.find(queryDataContract, 'documentNumber', { - orderBy: [['a', 'asc']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - - it('should return invalid result if the field inside an "orderBy" is an empty array', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [[]], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - - it('should return invalid result if order of three of two properties after indexed one is not preserved', async () => { - try { - await documentRepository.find(queryDataContract, 'documentL', { - where: [ - ['b', '>', 1], - ], - orderBy: [['b', 'desc'], ['e', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - - it('should return invalid result if order of properties does not match index', async () => { - try { - await documentRepository.find(queryDataContract, 'documentJ', { - where: [ - ['b', '>', 1], - ], - orderBy: [['b', 'desc'], ['d', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - - validFieldNameTestCases.forEach((fieldName) => { - it(`should return valid result if "orderBy" has valid field format, ${fieldName}`, async () => { - const result = await documentRepository.find(queryDataContract, `document${fieldName}`, { - where: [ - [fieldName, '>', fieldName.startsWith('$') && !fieldName.endsWith('At') ? generateRandomIdentifier() : 1], - ], - orderBy: [[fieldName, 'asc']], - }); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - invalidFieldNameTestCases.forEach((fieldName) => { - it(`should return invalid result if "orderBy" has invalid field format, ${fieldName}`, async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['$a', 'asc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - }); - - it('should return invalid result if "orderBy" has wrong direction', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a', 'a']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - - it('should return invalid result if "orderBy" field array has less than 2 elements (field, direction)', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - - it('should return invalid result if "orderBy" field array has more than 2 elements (field, direction)', async () => { - try { - await documentRepository.find(queryDataContract, 'documentNumber', { - where: [ - ['a', '>', 1], - ], - orderBy: [['a', 'asc', 'desc']], - }); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('missing order by for range error: query must have an orderBy field for each range element'); - } - }); - - validOrderByOperators.forEach(({ operator, value, documentType }) => { - it(`should return valid result if "orderBy" has valid field with valid operator (${operator}) and value (${value})" in "where" clause`, async () => { - const result = await documentRepository.find( - queryDataContract, - documentType, - { - where: [ - ['a', operator, value], - ], - orderBy: [['a', 'asc']], - }, - ); - - expect(result).to.be.instanceOf(StorageResult); - }); - }); - - it('should return invalid result if "orderBy" was not used with range operator', async () => { - const query = { - where: [['a', '==', 1]], - orderBy: [['b', 'asc']], - }; - - try { - await documentRepository.find(queryDataContract, 'documentK', query); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('where clause on non indexed property error: query must be for valid indexes'); - } - }); - }); - }); - }); - - describe('#delete', () => { - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - }); - - it('should delete Document', async () => { - let result = await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - result = await documentRepository.find(dataContract, document.getType(), { - where: [['$id', '==', document.getId()]], - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.have.lengthOf(0); - }); - - it('should delete Document in transaction', async () => { - await documentRepository - .storage - .startTransaction(); - - const result = await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - { - useTransaction: true, - }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const query = { - where: [['$id', '==', document.getId()]], - }; - - const removedDocumentResult = await documentRepository - .find( - dataContract, - document.getType(), - { - ...query, - useTransaction: true, - }, - ); - - const removedDocument = removedDocumentResult.getValue(); - - const notRemovedDocumentsResult = await documentRepository - .find(dataContract, document.getType(), query); - - const notRemovedDocuments = notRemovedDocumentsResult.getValue(); - - await documentRepository - .storage.commitTransaction(); - - const completelyRemovedDocumentResult = await documentRepository - .find(dataContract, document.getType(), query); - - const completelyRemovedDocument = completelyRemovedDocumentResult.getValue(); - - expect(removedDocument).to.have.lengthOf(0); - expect(notRemovedDocuments).to.be.not.null(); - expect(notRemovedDocuments[0].toBuffer()).to.deep.equal(document.toBuffer()); - expect(completelyRemovedDocument).to.have.lengthOf(0); - }); - - it('should restore document if transaction aborted', async () => { - await documentRepository - .storage - .startTransaction(); - - await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - { - useTransaction: true, - }, - ); - - const query = { - where: [['$id', '==', document.getId()]], - }; - - // Document should be removed in transaction - - const removedDocumentsResult = await documentRepository.find( - dataContract, - document.getType(), - { - ...query, - useTransaction: true, - }, - ); - - const removedDocuments = removedDocumentsResult.getValue(); - - expect(removedDocuments).to.have.lengthOf(0); - - // But still exists in main database - - const removedDocumentsWithoutTransactionResult = await documentRepository - .find(dataContract, document.getType(), query); - - const removedDocumentsWithoutTransaction = removedDocumentsWithoutTransactionResult - .getValue(); - - expect(removedDocumentsWithoutTransaction).to.not.have.lengthOf(0); - expect(removedDocumentsWithoutTransaction[0].toBuffer()).to.deep.equal(document.toBuffer()); - - await documentRepository - .storage - .abortTransaction(); - - const restoredDocumentsResult = await documentRepository - .find(dataContract, document.getType(), query); - - const restoredDocuments = restoredDocumentsResult.getValue(); - - expect(restoredDocuments).to.not.have.lengthOf(0); - expect(restoredDocuments[0].toBuffer()).to.deep.equal(document.toBuffer()); - }); - - it('should not delete Document on dry run', async () => { - const result = await documentRepository.delete( - dataContract, - document.getType(), - document.getId(), - blockInfo, - { - dryRun: true, - }, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const query = { - where: [['$id', '==', document.getId()]], - }; - - const removedDocumentsResult = await documentRepository - .find(dataContract, document.getType(), query); - - const removedDocuments = removedDocumentsResult - .getValue(); - - expect(removedDocuments).to.not.have.lengthOf(0); - expect(removedDocuments[0].toBuffer()).to.deep.equal(document.toBuffer()); - }); - }); - - describe('#prove', () => { - // TODO do we need to check prove result with every single find test request? - - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - }); - - it('should return proof for all existing documents', async () => { - const result = await documentRepository.prove(dataContract, document.getType()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - // TODO enable this test when we support transactions for proofs - it.skip('should return proof for all existing documents in transaction', async () => { - await documentRepository - .storage - .startTransaction(); - - const result = await documentRepository - .prove(dataContract, document.getType(), { - useTransaction: true, - }); - - await documentRepository - .storage - .abortTransaction(); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - }); - - describe('#proveManyDocumentsFromDifferentContracts', () => { - beforeEach(async () => { - await createDocuments(documentRepository, documents, blockInfo); - }); - - it('should return proof for all existing documents', async () => { - const documentsToProve = documents.map((doc) => ({ - dataContractId: doc.getDataContractId().toBuffer(), - documentId: doc.getId().toBuffer(), - type: doc.getType(), - })); - - const result = await documentRepository.proveManyDocumentsFromDifferentContracts( - documentsToProve, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof non existing documents', async () => { - const documentsToProve = [{ - dataContractId: generateRandomIdentifier().toBuffer(), - documentId: generateRandomIdentifier().toBuffer(), - type: 'unknownType', - }]; - - const result = await documentRepository.proveManyDocumentsFromDifferentContracts( - documentsToProve, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof for existing and non existing documents', async () => { - const documentsToProve = documents.map((doc) => ({ - dataContractId: doc.getDataContractId().toBuffer(), - documentId: doc.getId().toBuffer(), - type: doc.getType(), - })); - - documentsToProve.push({ - dataContractId: generateRandomIdentifier().toBuffer(), - documentId: generateRandomIdentifier().toBuffer(), - type: 'unknownType', - }); - - const result = await documentRepository.proveManyDocumentsFromDifferentContracts( - documentsToProve, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - }); -}); diff --git a/packages/js-drive/test/integration/document/fetchDataContractFactory.spec.js b/packages/js-drive/test/integration/document/fetchDataContractFactory.spec.js deleted file mode 100644 index ad2f04c9eb4..00000000000 --- a/packages/js-drive/test/integration/document/fetchDataContractFactory.spec.js +++ /dev/null @@ -1,83 +0,0 @@ -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const InvalidQueryError = require('../../../lib/document/errors/InvalidQueryError'); - -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('fetchDataContractFactory', () => { - let fetchDataContract; - let contractId; - let dataContractRepository; - let dataContract; - let container; - let blockInfo; - - beforeEach(async () => { - container = await createTestDIContainer(); - - dataContractRepository = container.resolve('dataContractRepository'); - - dataContract = getDataContractFixture(); - - contractId = dataContract.getId(); - - blockInfo = new BlockInfo(1, 1, Date.now()); - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(); - - await dataContractRepository.create(dataContract, blockInfo); - - fetchDataContract = container.resolve('fetchDataContract'); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should fetch DataContract for specified contract ID and document type', async () => { - const result = await fetchDataContract(contractId); - - expect(result).to.be.instanceOf(StorageResult); - // TODO: Processing fees are ignored for v0.23 - expect(result.getOperations().length).to.equals(0); - - const foundDataContract = result.getValue(); - - expect(foundDataContract.toObject()).to.deep.equal(dataContract.toObject()); - }); - - it('should throw InvalidQueryError if contract ID is not valid', async () => { - contractId = 'something'; - - try { - await fetchDataContract(contractId); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('invalid data contract ID: Identifier expects Buffer'); - } - }); - - it('should throw InvalidQueryError if contract ID does not exist', async () => { - contractId = generateRandomIdentifier(); - - try { - await fetchDataContract(contractId); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal(`data contract ${contractId} not found`); - } - }); -}); diff --git a/packages/js-drive/test/integration/document/fetchDocumentsFactory.spec.js b/packages/js-drive/test/integration/document/fetchDocumentsFactory.spec.js deleted file mode 100644 index f10ec5f54dc..00000000000 --- a/packages/js-drive/test/integration/document/fetchDocumentsFactory.spec.js +++ /dev/null @@ -1,221 +0,0 @@ -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); - -const InvalidQueryError = require('../../../lib/document/errors/InvalidQueryError'); - -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('fetchDocumentsFactory', () => { - let fetchDocuments; - let documentType; - let contractId; - let document; - let dataContractRepository; - let documentRepository; - let dataContract; - let container; - let blockInfo; - - beforeEach(async () => { - container = await createTestDIContainer(); - - dataContractRepository = container.resolve('dataContractRepository'); - documentRepository = container.resolve('documentRepository'); - - dataContract = getDataContractFixture(); - - contractId = dataContract.getId(); - - [document] = getDocumentsFixture(dataContract); - - documentType = document.getType(); - - dataContract.documents[documentType].indices = [ - { - properties: [ - { name: 'asc' }, - ], - }, - ]; - - blockInfo = new BlockInfo(1, 0, Date.now()); - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(); - - await dataContractRepository.create(dataContract, blockInfo); - - fetchDocuments = container.resolve('fetchDocuments'); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should fetch Documents for specified contract ID and document type', async () => { - await documentRepository.create(document, blockInfo); - - const result = await fetchDocuments(contractId, documentType); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(1); - - const [actualDocument] = foundDocuments; - - expect(actualDocument.toObject()).to.deep.equal(document.toObject()); - }); - - it('should fetch Documents for specified contract id, document type and name', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['name', '==', document.get('name')]] }; - - const result = await fetchDocuments(contractId, documentType, query); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.be.an('array'); - expect(foundDocuments).to.have.lengthOf(1); - - const [actualDocument] = foundDocuments; - - expect(actualDocument.toObject()).to.deep.equal(document.toObject()); - }); - - it('should return empty array for specified contract ID, document type and name not exist', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['name', '==', 'unknown']] }; - - const result = await fetchDocuments(contractId, documentType, query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.deep.equal([]); - }); - - it('should fetch documents by an equal date', async () => { - const indexedDocument = getDocumentsFixture(dataContract)[3]; - - await documentRepository.create(indexedDocument, blockInfo); - - const query = { - where: [ - ['$createdAt', '==', indexedDocument.getCreatedAt().getTime()], - ], - }; - - const result = await fetchDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments[0].toObject()).to.deep.equal( - indexedDocument.toObject(), - ); - }); - - it('should fetch documents by a date range', async () => { - const [, , , indexedDocument] = getDocumentsFixture(dataContract); - - await documentRepository.create(indexedDocument, blockInfo); - - const startDate = new Date(); - startDate.setSeconds(startDate.getSeconds() - 10); - - const endDate = new Date(); - endDate.setSeconds(endDate.getSeconds() + 10); - - const query = { - where: [ - ['$createdAt', '>', startDate.getTime()], - ['$createdAt', '<=', endDate.getTime()], - ], - orderBy: [['$createdAt', 'asc']], - }; - - const result = await fetchDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments[0].toObject()).to.deep.equal( - indexedDocument.toObject(), - ); - }); - - it('should fetch empty array in case date is out of range', async () => { - const [, , , indexedDocument] = getDocumentsFixture(dataContract); - - await documentRepository.create(indexedDocument, blockInfo); - - const startDate = new Date(); - startDate.setSeconds(startDate.getSeconds() + 10); - - const endDate = new Date(); - endDate.setSeconds(endDate.getSeconds() + 20); - - const query = { - where: [ - ['$createdAt', '>', startDate.getTime()], - ['$createdAt', '<=', endDate.getTime()], - ], - orderBy: [['$createdAt', 'asc']], - }; - - const result = await fetchDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const foundDocuments = result.getValue(); - - expect(foundDocuments).to.have.length(0); - }); - - it('should throw InvalidQueryError if searching by non indexed fields', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['lastName', '==', 'unknown']] }; - - try { - await fetchDocuments(contractId, documentType, blockInfo, query); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); - - it('should throw InvalidQueryError if type does not exist', async () => { - documentType = 'Unknown'; - - try { - await fetchDocuments(contractId, documentType); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - expect(e.message).to.equal('document type Unknown is not defined in the data contract'); - } - }); -}); diff --git a/packages/js-drive/test/integration/document/proveDocumentsFactory.spec.js b/packages/js-drive/test/integration/document/proveDocumentsFactory.spec.js deleted file mode 100644 index cf4bea8abc3..00000000000 --- a/packages/js-drive/test/integration/document/proveDocumentsFactory.spec.js +++ /dev/null @@ -1,198 +0,0 @@ -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const InvalidQueryError = require('../../../lib/document/errors/InvalidQueryError'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('proveDocumentsFactory', () => { - let proveDocuments; - let documentType; - let contractId; - let document; - let dataContractRepository; - let documentRepository; - let dataContract; - let container; - let blockInfo; - - beforeEach(async () => { - container = await createTestDIContainer(); - - dataContractRepository = container.resolve('dataContractRepository'); - documentRepository = container.resolve('documentRepository'); - - dataContract = getDataContractFixture(); - - contractId = dataContract.getId(); - - [document] = getDocumentsFixture(dataContract); - - documentType = document.getType(); - - dataContract.documents[documentType].indices = [ - { - properties: [ - { name: 'asc' }, - ], - }, - ]; - - blockInfo = new BlockInfo(1, 0, Date.now()); - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(); - - await dataContractRepository.create(dataContract, blockInfo); - - proveDocuments = container.resolve('proveDocuments'); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should return proof for specified contract ID and document type', async () => { - await documentRepository.create(document, blockInfo); - - const result = await proveDocuments(contractId, documentType); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof for specified contract id, document type and name', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['name', '==', document.get('name')]] }; - - const result = await proveDocuments(contractId, documentType, query); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof for specified contract ID, document type and name not exist', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['name', '==', 'unknown']] }; - - const result = await proveDocuments(contractId, documentType, query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof by an equal date', async () => { - const indexedDocument = getDocumentsFixture(dataContract)[3]; - - await documentRepository.create(indexedDocument, blockInfo); - - const query = { - where: [ - ['$createdAt', '==', indexedDocument.getCreatedAt().getTime()], - ], - }; - - const result = await proveDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof by a date range', async () => { - const [, , , indexedDocument] = getDocumentsFixture(dataContract); - - await documentRepository.create(indexedDocument, blockInfo); - - const startDate = new Date(); - startDate.setSeconds(startDate.getSeconds() - 10); - - const endDate = new Date(); - endDate.setSeconds(endDate.getSeconds() + 10); - - const query = { - where: [ - ['$createdAt', '>', startDate.getTime()], - ['$createdAt', '<=', endDate.getTime()], - ], - orderBy: [['$createdAt', 'asc']], - }; - - const result = await proveDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should fetch empty array in case date is out of range', async () => { - const [, , , indexedDocument] = getDocumentsFixture(dataContract); - - await documentRepository.create(indexedDocument, blockInfo); - - const startDate = new Date(); - startDate.setSeconds(startDate.getSeconds() + 10); - - const endDate = new Date(); - endDate.setSeconds(endDate.getSeconds() + 20); - - const query = { - where: [ - ['$createdAt', '>', startDate.getTime()], - ['$createdAt', '<=', endDate.getTime()], - ], - orderBy: [['$createdAt', 'asc']], - }; - - const result = await proveDocuments(contractId, 'indexedDocument', query); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.be.greaterThan(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceOf(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should throw InvalidQueryError if searching by non indexed fields', async () => { - await documentRepository.create(document, blockInfo); - - const query = { where: [['lastName', '==', 'unknown']] }; - - try { - await proveDocuments(contractId, documentType, query); - - expect.fail('should throw InvalidQueryError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidQueryError); - } - }); -}); diff --git a/packages/js-drive/test/integration/fee/feesPrediction.spec.js b/packages/js-drive/test/integration/fee/feesPrediction.spec.js deleted file mode 100644 index b50b8432b03..00000000000 --- a/packages/js-drive/test/integration/fee/feesPrediction.spec.js +++ /dev/null @@ -1,549 +0,0 @@ -const crypto = require('crypto'); - -const Long = require('long'); - -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const getInstantAssetLockProofFixture = require('@dashevo/dpp/lib/test/fixtures/getInstantAssetLockProofFixture'); -const identityUpdateTransitionSchema = require('@dashevo/dpp/schema/identity/stateTransition/identityUpdate.json'); -const StateTransitionExecutionContext = require('@dashevo/dpp/lib/stateTransition/StateTransitionExecutionContext'); -const PrivateKey = require('@dashevo/dashcore-lib/lib/privatekey'); - -const BlsSignatures = require('@dashevo/dpp/lib/bls/bls'); - -const getBiggestPossibleIdentity = require('../../../lib/test/mock/getBiggestPossibleIdentity'); - -const createTestDIContainer = require('../../../lib/test/createTestDIContainer'); -const createDataContractDocuments = require('../../../lib/test/fixtures/createDataContractDocuments'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -/** - * @param {DashPlatformProtocol} dpp - * @param {AbstractStateTransition} stateTransition - * @return {Promise} - */ -async function validateStateTransition(dpp, stateTransition) { - const validateBasicResult = await dpp.stateTransition.validateBasic(stateTransition); - expect(validateBasicResult.isValid()).to.be.true(); - - const validateSignatureResult = await dpp.stateTransition.validateSignature(stateTransition); - expect(validateSignatureResult.isValid()).to.be.true(); - - const validateFeeResult = await dpp.stateTransition.validateFee(stateTransition); - expect(validateFeeResult.isValid()).to.be.true(); - - const validateStateResult = await dpp.stateTransition.validateState(stateTransition); - expect(validateStateResult.isValid()).to.be.true(); - - const applyResult = await dpp.stateTransition.validateState(stateTransition); - expect(applyResult.isValid()).to.be.true(); -} - -/** - * @param {DashPlatformProtocol} dpp - * @param {GroveDBStore} groveDBStore - * @param {AbstractStateTransition} stateTransition - * @return {Promise} - */ -async function expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition) { - // Execute state transition without dry run - - const actualExecutionContext = new StateTransitionExecutionContext(); - - stateTransition.setExecutionContext(actualExecutionContext); - - await validateStateTransition(dpp, stateTransition); - - // Execute state transition with dry run enabled - - const predictedExecutionContext = new StateTransitionExecutionContext(); - - predictedExecutionContext.enableDryRun(); - - stateTransition.setExecutionContext(predictedExecutionContext); - - const initialAppHash = await groveDBStore.getRootHash(); - - await validateStateTransition(dpp, stateTransition); - - // AppHash shouldn't be changed after dry run - const appHashAfterDryRun = await groveDBStore.getRootHash(); - - expect(appHashAfterDryRun).to.deep.equal(initialAppHash); - - // Compare operations - - // TODO: Processing fees are disabled for v0.23 - // const actualOperations = actualExecutionContext.getOperations(); - // const predictedOperations = predictedExecutionContext.getOperations(); - - // expect(predictedOperations).to.have.lengthOf(actualOperations.length); - - // Compare fees - - // stateTransition.setExecutionContext(actualExecutionContext); - // const actualFees = calculateStateTransitionFee(stateTransition); - // - // stateTransition.setExecutionContext(predictedExecutionContext); - // const predictedFees = calculateStateTransitionFee(stateTransition); - // - // expect(predictedFees).to.be.greaterThanOrEqual(actualFees); - // - // predictedOperations.forEach((predictedOperation, i) => { - // expect(predictedOperation.getStorageCost()).to.be.greaterThanOrEqual( - // actualOperations[i].getStorageCost(), - // ); - // - // expect(predictedOperation.getProcessingCost()).to.be.greaterThanOrEqual( - // actualOperations[i].getProcessingCost(), - // ); - // }); -} - -describe('feesPrediction', () => { - let dpp; - let container; - let stateRepository; - let identity; - let groveDBStore; - let blockInfo; - - beforeEach(async function beforeEach() { - container = await createTestDIContainer(); - - const latestBlockExecutionContext = container.resolve('latestBlockExecutionContext'); - - blockInfo = new BlockInfo(1, 0, Date.now()); - - latestBlockExecutionContext.getEpochInfo = this.sinon.stub().returns({ - currentEpochIndex: blockInfo.epoch, - }); - - latestBlockExecutionContext.getTimeMs = this.sinon.stub().returns(blockInfo.timeMs); - latestBlockExecutionContext.getHeight = this.sinon.stub().returns(Long.fromNumber(0)); - - dpp = container.resolve('dpp'); - - stateRepository = container.resolve('stateRepository'); - groveDBStore = container.resolve('groveDBStore'); - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.createInitialStateStructure(); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - describe('Identity', () => { - let assetLockPrivateKey; - let instantAssetLockProof; - let privateKeys; - - beforeEach(async function beforeEachFunction() { - assetLockPrivateKey = new PrivateKey(); - - instantAssetLockProof = getInstantAssetLockProofFixture(assetLockPrivateKey); - - identity = getBiggestPossibleIdentity(); - identity.id = instantAssetLockProof.createIdentifier(); - identity.setAssetLockProof(instantAssetLockProof); - - // Generate real keys - const { BasicSchemeMPL } = await BlsSignatures.getInstance(); - - privateKeys = identity.getPublicKeys().map((identityPublicKey) => { - const randomBytes = new Uint8Array(crypto.randomBytes(256)); - - const privateKey = BasicSchemeMPL.keyGen(randomBytes); - const publicKey = privateKey.getG1(); - const publicKeyBuffer = Buffer.from(publicKey.serialize()); - - identityPublicKey.setData(publicKeyBuffer); - - const result = Buffer.from(privateKey.serialize()); - - privateKey.delete(); - publicKey.delete(); - - return result; - }); - - stateRepository.verifyInstantLock = this.sinon.stub().resolves(true); - }); - - describe('IdentityCreateTransition', () => { - it('should have predicted fee more than actual fee', async () => { - const stateTransition = dpp.identity.createIdentityCreateTransition(identity); - - // Sign public keys - const publicKeys = stateTransition.getPublicKeys(); - - for (let i = 0; i < publicKeys.length; i++) { - await stateTransition.signByPrivateKey( - privateKeys[i], - IdentityPublicKey.TYPES.BLS12_381, - ); - - publicKeys[i].setSignature(stateTransition.getSignature()); - - stateTransition.setSignature(undefined); - } - - // Sign state transition - await stateTransition.signByPrivateKey( - assetLockPrivateKey, - IdentityPublicKey.TYPES.ECDSA_SECP256K1, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - - describe('IdentityTopUpTransition', () => { - it('should have predicted fee more than actual fee', async () => { - await stateRepository.createIdentity(identity); - - const stateTransition = dpp.identity.createIdentityTopUpTransition( - identity.getId(), - instantAssetLockProof, - ); - - await stateTransition.signByPrivateKey( - assetLockPrivateKey, - IdentityPublicKey.TYPES.ECDSA_SECP256K1, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - - describe('IdentityUpdateTransition', () => { - it('should have predicted fee more than actual fee', async () => { - await stateRepository.createIdentity(identity); - - const newIdentityPublicKeys = []; - const disableIdentityPublicKeys = []; - - const { BasicSchemeMPL } = await BlsSignatures.getInstance(); - - const newPrivateKeys = []; - for (let i = 0; i < identityUpdateTransitionSchema.properties.addPublicKeys.maxItems; i++) { - const randomBytes = new Uint8Array(crypto.randomBytes(256)); - const privateKey = BasicSchemeMPL.keyGen(randomBytes); - const publicKey = privateKey.getG1(); - const publicKeyBuffer = Buffer.from(publicKey.serialize()); - - newPrivateKeys.push(privateKey); - - newIdentityPublicKeys.push( - new IdentityPublicKey({ - id: i + identity.getPublicKeys().length, - type: IdentityPublicKey.TYPES.BLS12_381, - data: publicKeyBuffer, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: i === 0 - ? IdentityPublicKey.SECURITY_LEVELS.MASTER : IdentityPublicKey.SECURITY_LEVELS.HIGH, - readOnly: false, - }), - ); - - disableIdentityPublicKeys.push(identity.getPublicKeyById(i)); - - publicKey.delete(); - } - - const stateTransition = dpp.identity.createIdentityUpdateTransition( - identity, - { - add: newIdentityPublicKeys, - disable: disableIdentityPublicKeys, - }, - ); - - const [signerKey] = identity.getPublicKeys(); - - const starterPromise = Promise.resolve(null); - - await stateTransition.getPublicKeysToAdd().reduce( - (previousPromise, publicKey) => previousPromise.then(async () => { - const privateKey = newPrivateKeys[publicKey.getId() - identity.getPublicKeys().length]; - - if (!privateKey) { - throw new Error(`Private key for key ${publicKey.getId()} not found`); - } - - stateTransition.setSignaturePublicKeyId(signerKey.getId()); - - await stateTransition.signByPrivateKey(privateKey, publicKey.getType()); - - publicKey.setSignature(stateTransition.getSignature()); - - stateTransition.setSignature(undefined); - stateTransition.setSignaturePublicKeyId(undefined); - }), - starterPromise, - ); - - await stateTransition.sign( - identity.getPublicKeyById(0), - privateKeys[0], - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - }); - - describe('DataContract', () => { - let dataContract; - let privateKey; - - beforeEach(async () => { - // Create identity - - privateKey = new PrivateKey(); - - identity = new Identity({ - protocolVersion: 1, - id: generateRandomIdentifier().toBuffer(), - publicKeys: [ - { - id: 0, - type: IdentityPublicKey.TYPES.BLS12_381, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: false, - data: Buffer.alloc(48).fill(255), - }, - { - id: 1, - type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.HIGH, - readOnly: false, - data: privateKey.toPublicKey().toBuffer(), - }, - ], - balance: Math.floor(9223372036854775807 / 10000), - revision: 0, - }); - - await stateRepository.createIdentity(identity); - - // Generate Data Contract - - const documents = createDataContractDocuments(); - - dataContract = dpp.dataContract.create(identity.getId(), documents); - }); - - describe('DataContractCreate', () => { - it('should have predicted fee more than actual fee', async () => { - const stateTransition = dpp.dataContract.createDataContractCreateTransition(dataContract); - - await stateTransition.sign( - identity.getPublicKeyById(1), - privateKey, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - - describe('DataContractUpdate', () => { - it('should have predicted fee more than actual fee', async () => { - await stateRepository.createDataContract(dataContract); - - dataContract.incrementVersion(); - - const documents = dataContract.getDocuments(); - - documents.newDoc = { - type: 'object', - indices: [ - { - name: 'onwerIdToUser', - properties: [ - { $ownerId: 'asc' }, - { user: 'asc' }, - ], - unique: true, - }, - ], - properties: { - user: { - type: 'string', - maxLength: 63, - }, - publicKey: { - type: 'array', - byteArray: true, - maxItems: 33, - }, - }, - required: ['user', 'publicKey'], - additionalProperties: false, - }; - - dataContract.setDocuments(documents); - - const stateTransition = dpp.dataContract.createDataContractUpdateTransition(dataContract); - - await stateTransition.sign( - identity.getPublicKeyById(1), - privateKey, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - }); - - describe('Document', () => { - let documents; - let dataContract; - let privateKey; - - beforeEach(async () => { - // Create Identity - - privateKey = new PrivateKey(); - - identity = new Identity({ - protocolVersion: 1, - id: generateRandomIdentifier().toBuffer(), - publicKeys: [ - { - id: 0, - type: IdentityPublicKey.TYPES.BLS12_381, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: false, - data: Buffer.alloc(48).fill(255), - }, - { - id: 1, - type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.HIGH, - readOnly: false, - data: privateKey.toPublicKey().toBuffer(), - }, - ], - balance: Math.floor(9223372036854775807 / 10000), - revision: 0, - }); - - await stateRepository.createIdentity(identity); - - // Create Data Contract - - const documentTypes = createDataContractDocuments(); - - dataContract = dpp.dataContract.create(identity.getId(), documentTypes); - - await stateRepository.createDataContract(dataContract); - - // Create documents - - documents = []; - - let i = 0; - for (const documentType of Object.keys(documentTypes)) { - const data = {}; - - for (const propertyName of Object.keys(documentTypes[documentType].properties)) { - data[propertyName] = `${crypto.randomBytes(31).toString('hex')}a`; - } - - const document = dpp.document.create( - dataContract, - identity.getId(), - documentType, - data, - ); - - documents.push(document); - - i += 1; - - if (i === 10) { - break; - } - } - }); - - describe('DocumentsBatchTransition', () => { - context('create', () => { - it('should have predicted fee more than actual fee', async () => { - const stateTransition = dpp.document.createStateTransition({ - create: documents, - }); - - await stateTransition.sign( - identity.getPublicKeyById(1), - privateKey, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - - context('replace', () => { - it('should have predicted fee more than actual fee', async () => { - for (const document of documents) { - await stateRepository.createDocument(document); - } - - for (const document of documents) { - const data = document.getData(); - - for (const propertyName of Object.keys(data)) { - data[propertyName] = `${crypto.randomBytes(31).toString('hex')}b`; - } - - document.setData(data); - } - - const stateTransition = dpp.document.createStateTransition({ - replace: documents, - }); - - await stateTransition.sign( - identity.getPublicKeyById(1), - privateKey, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - - context('delete', () => { - it('should have predicted fee more than actual fee', async () => { - for (const document of documents) { - await stateRepository.createDocument(document); - } - - const stateTransition = dpp.document.createStateTransition({ - delete: documents, - }); - - await stateTransition.sign( - identity.getPublicKeyById(1), - privateKey, - ); - - await expectPredictedFeeHigherOrEqualThanActual(dpp, groveDBStore, stateTransition); - }); - }); - }); - }); -}); diff --git a/packages/js-drive/test/integration/groveDB/GroveDBStore.spec.js b/packages/js-drive/test/integration/groveDB/GroveDBStore.spec.js deleted file mode 100644 index 162c155e7fd..00000000000 --- a/packages/js-drive/test/integration/groveDB/GroveDBStore.spec.js +++ /dev/null @@ -1,423 +0,0 @@ -const rimraf = require('rimraf'); - -const Drive = require('@dashevo/rs-drive'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const logger = require('../../../lib/util/noopLogger'); -const StorageResult = require('../../../lib/storage/StorageResult'); - -describe('GroveDBStore', () => { - let rsDrive; - let store; - let key; - let value; - let testTreePath; - let otherTreePath; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, logger); - - testTreePath = [Buffer.from('testTree')]; - otherTreePath = [Buffer.from('otherTree')]; - - await store.createTree([], testTreePath[0]); - await store.createTree([], otherTreePath[0]); - - key = Buffer.alloc(32).fill(1); - value = Buffer.alloc(32).fill(2); - }); - - afterEach(async () => { - await rsDrive.close(); - rimraf.sync('./db/grovedb_test'); - }); - - describe('#put', () => { - it('should store value', async () => { - const result = await store.put(testTreePath, key, value); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const actualValue = await rsDrive.getGroveDB().get(testTreePath, key); - - expect(actualValue).to.be.deep.equal({ - type: 'item', - value, - }); - }); - - it('should store value in transaction', async () => { - await store.startTransaction(); - - // store data in transaction - await store.put(testTreePath, key, value, { - useTransaction: true, - }); - - // check we don't have data in db before commit - try { - await rsDrive.getGroveDB().get(testTreePath, key); - - expect.fail('Should fail with NotFoundError error'); - } catch (e) { - expect(e.message.startsWith('grovedb: path key not found: key not found in Merk')).to.be.true(); - } - - // check we can't fetch data without transaction - const notFoundValueResult = await store.get(testTreePath, key); - - expect(notFoundValueResult.getValue()).to.be.null(); - - // check we can fetch data inside transaction - const valueFromTransactionResult = await store.get(testTreePath, key, { - useTransaction: true, - }); - - expect(valueFromTransactionResult).to.be.instanceOf(StorageResult); - expect(valueFromTransactionResult.getOperations().length).to.equal(0); - - expect(valueFromTransactionResult.getValue()).to.deep.equal(value); - - await store.commitTransaction(); - - // check we have data in db after commit - const storedValue = await rsDrive.getGroveDB().get(testTreePath, key); - - expect(storedValue).to.deep.equal({ - type: 'item', - value, - }); - }); - }); - - describe('#get', () => { - it('should return null if key was not found', async () => { - const result = await store.get(testTreePath, key); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should return stored value', async () => { - await rsDrive.getGroveDB().insert( - testTreePath, - key, - { type: 'item', value }, - false, - ); - - const result = await store.get(testTreePath, key); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.deep.equal(value); - }); - - it('should return stored value with transaction', async () => { - await store.put(testTreePath, key, value); - - await store.startTransaction(); - - const result = await store.get(testTreePath, key, { - useTransaction: true, - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.deep.equal(value); - }); - }); - - describe('#putReference', () => { - it('should put an item by reference', async () => { - await store.put(otherTreePath, key, value); - - const result = await store.putReference(testTreePath, key, [otherTreePath[0], key]); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const getResult = await store.get(testTreePath, key); - - expect(getResult.getValue()).to.deep.equal(value); - }); - - it('should put an item by reference in transaction', async () => { - await store.put(otherTreePath, key, value); - - await store.startTransaction(); - - const result = await store.putReference(testTreePath, key, [otherTreePath[0], key], { - useTransaction: true, - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const nonTxResult = await store.get(testTreePath, key); - - expect(nonTxResult.getValue()).to.be.null(); - - const txResult = await store.get(testTreePath, key, { - useTransaction: true, - }); - - expect(txResult.getValue()).to.deep.equal(value); - }); - }); - - describe('#query', () => { - it('should return results', async () => { - await store.put(testTreePath, key, value); - - const result = await store.query({ - path: testTreePath, - query: { - query: { - items: [ - { - type: 'rangeFull', - }, - ], - }, - }, - }); - - expect(result).to.have.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.have.lengthOf(1); - - const [item] = result.getValue(); - - expect(item).to.deep.equal(value); - }); - }); - - describe('#proveQuery', () => { - it('should return proof', async () => { - await store.put(testTreePath, key, value); - - const result = await store.proveQuery({ - path: testTreePath, - query: { - query: { - items: [ - { - type: 'rangeFull', - }, - ], - }, - }, - }); - - expect(result).to.have.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - }); - }); - - describe('#delete', () => { - it('should delete value', async () => { - await store.put(testTreePath, key, value); - - const result = await store.delete(testTreePath, key); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - try { - await rsDrive.getGroveDB().get(testTreePath, key); - - expect.fail('should throw no value found for key error'); - } catch (e) { - expect(e.message.startsWith('grovedb: path key not found: key not found in Merk')).to.be.true(); - } - }); - - it('should delete value in transaction', async () => { - await store.put(testTreePath, key, value); - - await store.startTransaction(); - - // Delete a value from transaction - const result = await store.delete(testTreePath, key, { - useTransaction: true, - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - // Now it should be absent there - const valueFromTransactionResult = await store.get(testTreePath, key, { - useTransaction: true, - }); - - expect(valueFromTransactionResult.getValue()).to.be.null(); - - // But should be still present in store - const valueFromStoreResult = await store.get(testTreePath, key); - expect(valueFromStoreResult.getValue()).to.deep.equal(value); - - await store.commitTransaction(); - - // When we commit transaction this key should disappear from store too - const valueFromStoreAfterCommitResult = await store.get(testTreePath, key); - expect(valueFromStoreAfterCommitResult.getValue()).to.be.null(); - }); - }); - - describe('#getAux', () => { - it('should get an auxiliary data from db', async () => { - await rsDrive.getGroveDB().putAux(key, value); - - const result = await store.getAux(key); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.deep.equal(value); - }); - - it('should get an auxiliary data from db with transaction', async () => { - await rsDrive.getGroveDB().putAux(key, value); - - await store.startTransaction(); - - const result = await store.getAux(key, { - useTransaction: true, - }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.deep.equal(value); - }); - }); - - describe('#putAux', () => { - it('should put an auxiliary data', async () => { - await store.putAux(key, value); - - const result = await rsDrive.getGroveDB().getAux(key); - - expect(result).to.deep.equal(value); - }); - - it('should put an auxiliary data using transaction', async () => { - await store.startTransaction(); - - await store.putAux(key, value, { - useTransaction: true, - }); - - const nonTxResult = await rsDrive.getGroveDB().getAux(key); - - expect(nonTxResult).to.be.null(); - - const txResult = await rsDrive.getGroveDB().getAux(key, true); - - expect(txResult).to.deep.equal(value); - }); - }); - - describe('#deleteAux', () => { - it('should delete an auxiliary data', async () => { - await store.putAux(key, value); - - const getResult = await store.getAux(key); - - expect(getResult.getValue()).to.deep.equal(value); - - const deleteResult = await store.deleteAux(key); - - expect(deleteResult).to.be.instanceOf(StorageResult); - expect(deleteResult.getOperations().length).to.equal(0); - - const deletedValue = await rsDrive.getGroveDB().getAux(key); - - expect(deletedValue).to.be.null(); - }); - - it('should delete an auxiliary data within transaction', async () => { - await store.putAux(key, value); - - await store.startTransaction(); - - const deleteResult = await store.deleteAux(key, { - useTransaction: true, - }); - - expect(deleteResult).to.be.instanceOf(StorageResult); - expect(deleteResult.getOperations().length).to.equal(0); - - const nonTxResult = await store.getAux(key); - - expect(nonTxResult.getValue()).to.deep.equal(value); - - const txResult = await store.getAux(key, { - useTransaction: true, - }); - - expect(txResult.getValue()).to.be.null(); - }); - }); - - describe('#getRootHash', () => { - it('should return a null hash for empty store', async () => { - await rsDrive.close(); - - rimraf.sync('./db/grovedb_test'); - - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, logger); - - const result = await store.getRootHash(); - - expect(result).to.deep.equal(Buffer.alloc(32).fill(0)); - }); - - it('should return a root hash for store with value', async () => { - await store.put(testTreePath, key, value); - - const valueHash = Buffer.from('9522321fe08ddbbd5a37cf875cdd7f7a104ac9b9e9246f1454b7360341b29124', 'hex'); - - const result = await store.getRootHash(); - - expect(result).to.deep.equal(valueHash); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/IdentityBalanceStoreRepository.spec.js b/packages/js-drive/test/integration/identity/IdentityBalanceStoreRepository.spec.js deleted file mode 100644 index 86e79eca563..00000000000 --- a/packages/js-drive/test/integration/identity/IdentityBalanceStoreRepository.spec.js +++ /dev/null @@ -1,452 +0,0 @@ -const fs = require('fs'); -const Drive = require('@dashevo/rs-drive'); -const { FeeResult } = require('@dashevo/rs-drive'); -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const IdentityBalanceStoreRepository = require('../../../lib/identity/IdentityBalanceStoreRepository'); -const IdentityStoreRepository = require('../../../lib/identity/IdentityStoreRepository'); -const logger = require('../../../lib/util/noopLogger'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('IdentityStoreRepository', () => { - let rsDrive; - let store; - let balanceRepository; - let identityRepository; - let decodeProtocolEntity; - let identity; - let blockInfo; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - await rsDrive.createInitialStateStructure(); - - store = new GroveDBStore(rsDrive, logger); - - decodeProtocolEntity = decodeProtocolEntityFactory(); - - balanceRepository = new IdentityBalanceStoreRepository(store, decodeProtocolEntity); - identityRepository = new IdentityStoreRepository(store, decodeProtocolEntity); - identity = getIdentityFixture(); - - blockInfo = new BlockInfo(1, 1, Date.now()); - }); - - afterEach(async () => { - await rsDrive.close(); - - fs.rmSync('./db/grovedb_test', { recursive: true, force: true }); - }); - - describe('#add', () => { - beforeEach(async () => { - await identityRepository.create( - identity, - blockInfo, - ); - }); - - it('should add to balance', async () => { - const amount = 100; - - const result = await balanceRepository.add( - identity.getId(), - amount, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const fetchedIdentity = fetchedIdentityResult.getValue(); - - expect(fetchedIdentity.getBalance()).to.equal(identity.getBalance() + amount); - }); - - it('should add to balance using transaction', async () => { - await store.startTransaction(); - - const amount = 100; - - await balanceRepository.add( - identity.getId(), - amount, - blockInfo, - { useTransaction: true }, - ); - - const previousIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const previousIdentity = previousIdentityResult.getValue(); - - expect(previousIdentity.getBalance()).to.equal(identity.getBalance()); - - const transactionalIdentityResult = await identityRepository.fetch( - identity.getId(), - { useTransaction: true }, - ); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity.getBalance()).to.equal(identity.getBalance() + amount); - - await store.commitTransaction(); - - const committedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const committedIdentity = committedIdentityResult.getValue(); - - expect(committedIdentity.getBalance()).to.equal(identity.getBalance() + amount); - }); - }); - - describe('#applyFees', () => { - beforeEach(async () => { - identity.setBalance(10000); - - await identityRepository.create( - identity, - blockInfo, - ); - }); - - it('should apply fees to balance', async () => { - const feeResult = FeeResult.create(1000, 100, []); - - const result = await balanceRepository.applyFees( - identity.getId(), - feeResult, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.instanceOf(FeeResult); - - const fetchedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const fetchedIdentity = fetchedIdentityResult.getValue(); - - expect(fetchedIdentity.getBalance()).to.equal( - identity.getBalance() - feeResult.storageFee - feeResult.processingFee, - ); - }); - - it('should add to balance using transaction', async () => { - await store.startTransaction(); - - const feeResult = FeeResult.create(1000, 100, []); - - await balanceRepository.applyFees( - identity.getId(), - feeResult, - { useTransaction: true }, - ); - - const previousIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const previousIdentity = previousIdentityResult.getValue(); - - expect(previousIdentity.getBalance()).to.equal(identity.getBalance()); - - const transactionalIdentityResult = await identityRepository.fetch( - identity.getId(), - { useTransaction: true }, - ); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity.getBalance()).to.equal( - identity.getBalance() - feeResult.storageFee - feeResult.processingFee, - ); - - await store.commitTransaction(); - - const committedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const committedIdentity = committedIdentityResult.getValue(); - - expect(committedIdentity.getBalance()).to.equal( - identity.getBalance() - feeResult.storageFee - feeResult.processingFee, - ); - }); - }); - - describe('#remove', () => { - beforeEach(async () => { - await identityRepository.create( - identity, - blockInfo, - ); - }); - - it('should remove from balance', async () => { - const amount = 5; - - const result = await balanceRepository.remove( - identity.getId(), - amount, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const fetchedIdentity = fetchedIdentityResult.getValue(); - - expect(fetchedIdentity.getBalance()).to.equal(identity.getBalance() - amount); - }); - - it('should remove from balance using transaction', async () => { - await store.startTransaction(); - - const amount = 5; - - await balanceRepository.remove( - identity.getId(), - amount, - blockInfo, - { useTransaction: true }, - ); - - const previousIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const previousIdentity = previousIdentityResult.getValue(); - - expect(previousIdentity.getBalance()).to.equal(identity.getBalance()); - - const transactionalIdentityResult = await identityRepository.fetch( - identity.getId(), - { useTransaction: true }, - ); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity.getBalance()).to.equal(identity.getBalance() - amount); - - await store.commitTransaction(); - - const committedIdentityResult = await identityRepository.fetch( - identity.getId(), - ); - - const committedIdentity = committedIdentityResult.getValue(); - - expect(committedIdentity.getBalance()).to.equal(identity.getBalance() - amount); - }); - }); - - describe('#fetch', () => { - context('without block info', () => { - it('should fetch null if identity not found', async () => { - const result = await balanceRepository.fetch(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch balance', async () => { - await identityRepository.create(identity, blockInfo); - - const result = await balanceRepository.fetch(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const balance = result.getValue(); - - expect(balance).to.equals(identity.getBalance()); - }); - - it('should fetch an identity using transaction', async () => { - await store.startTransaction(); - - await identityRepository.create(identity, blockInfo, { - useTransaction: true, - }); - - const notFoundBalanceResult = await balanceRepository.fetch(identity.getId(), { - useTransaction: false, - }); - - expect(notFoundBalanceResult.getValue()).to.be.null(); - - const transactionalBalanceResult = await balanceRepository.fetch(identity.getId(), { - useTransaction: true, - }); - - const transactionalBalance = transactionalBalanceResult.getValue(); - - expect(transactionalBalance).to.equals(identity.getBalance()); - - await store.commitTransaction(); - - const storedBalanceResult = await balanceRepository.fetch(identity.getId()); - - const storedBalance = storedBalanceResult.getValue(); - - expect(storedBalance).to.equals(identity.getBalance()); - }); - }); - - context('with block info', () => { - it('should fetch null if identity not found', async () => { - const result = await balanceRepository.fetch(identity.getId(), { blockInfo }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch an identity', async () => { - await identityRepository.create(identity, blockInfo); - - const result = await balanceRepository.fetch(identity.getId(), { blockInfo }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const storedBalance = result.getValue(); - - expect(storedBalance).to.equals(identity.getBalance()); - }); - - it('should fetch an identity using transaction', async () => { - await store.startTransaction(); - - await identityRepository.create(identity, blockInfo, { - useTransaction: true, - }); - - const notFoundBalanceResult = await balanceRepository.fetch(identity.getId(), { - blockInfo, - useTransaction: false, - }); - - expect(notFoundBalanceResult.getValue()).to.be.null(); - - const transactionalBalanceResult = await balanceRepository.fetch(identity.getId(), { - blockInfo, - useTransaction: true, - }); - - const transactionalBalance = transactionalBalanceResult.getValue(); - - expect(transactionalBalance).to.equals(identity.getBalance()); - - await store.commitTransaction(); - - const storedBalanceResult = await balanceRepository.fetch(identity.getId(), { - blockInfo, - }); - - const storedBalance = storedBalanceResult.getValue(); - - expect(storedBalance).to.equals(identity.getBalance()); - }); - }); - }); - - describe('#fetchWithDebt', () => { - it('should fetch null if identity not found', async () => { - const result = await balanceRepository.fetchWithDebt(identity.getId(), blockInfo); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch an identity', async () => { - await identityRepository.create(identity, blockInfo); - - const result = await balanceRepository.fetchWithDebt(identity.getId(), blockInfo); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const storedBalance = result.getValue(); - - expect(storedBalance).to.equals(identity.getBalance()); - }); - - it('should fetch an identity using transaction', async () => { - await store.startTransaction(); - - await identityRepository.create(identity, blockInfo, { - useTransaction: true, - }); - - const notFoundBalanceResult = await balanceRepository.fetchWithDebt( - identity.getId(), - blockInfo, - { - useTransaction: false, - }, - ); - - expect(notFoundBalanceResult.getValue()).to.be.null(); - - const transactionalBalanceResult = await balanceRepository.fetchWithDebt( - identity.getId(), - blockInfo, - { - useTransaction: true, - }, - ); - - const transactionalBalance = transactionalBalanceResult.getValue(); - - expect(transactionalBalance).to.equals(identity.getBalance()); - - await store.commitTransaction(); - - const storedBalanceResult = await balanceRepository.fetchWithDebt( - identity.getId(), - blockInfo, - ); - - const storedBalance = storedBalanceResult.getValue(); - - expect(storedBalance).to.equals(identity.getBalance()); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/IdentityPublicKeyStoreRepository.spec.js b/packages/js-drive/test/integration/identity/IdentityPublicKeyStoreRepository.spec.js deleted file mode 100644 index b51a68f8c25..00000000000 --- a/packages/js-drive/test/integration/identity/IdentityPublicKeyStoreRepository.spec.js +++ /dev/null @@ -1,177 +0,0 @@ -const fs = require('fs'); -const Drive = require('@dashevo/rs-drive'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); -const IdentityPublicKeyStoreRepository = require('../../../lib/identity/IdentityPublicKeyStoreRepository'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const logger = require('../../../lib/util/noopLogger'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const IdentityStoreRepository = require('../../../lib/identity/IdentityStoreRepository'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('IdentityPublicKeyStoreRepository', () => { - let rsDrive; - let store; - let publicKeyRepository; - let identityRepository; - let identity; - let blockInfo; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, logger); - - await rsDrive.createInitialStateStructure(); - - const decodeProtocolEntity = decodeProtocolEntityFactory(); - - identityRepository = new IdentityStoreRepository(store, decodeProtocolEntity); - - publicKeyRepository = new IdentityPublicKeyStoreRepository(store, decodeProtocolEntity); - - identity = getIdentityFixture(); - - blockInfo = new BlockInfo(1, 1, Date.now()); - }); - - afterEach(async () => { - await rsDrive.close(); - - fs.rmSync('./db/grovedb_test', { recursive: true, force: true }); - }); - - describe('#add', () => { - it('should add public keys to identity', async () => { - const publicKey = identity.getPublicKeys().pop(); - - await identityRepository.create(identity, blockInfo); - - const result = await publicKeyRepository.add( - identity.getId(), - [publicKey], - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedIdentityResult = await identityRepository.fetch(identity.getId()); - - const fetchedIdentity = fetchedIdentityResult.getValue(); - - identity.getPublicKeys().push(publicKey); - - expect(fetchedIdentity.toObject()).to.deep.equals(identity.toObject()); - }); - - it('should store public key to identities using transaction', async () => { - const publicKey = identity.getPublicKeys().pop(); - - await identityRepository.create(identity, blockInfo); - - await store.startTransaction(); - - await publicKeyRepository.add( - identity.getId(), - [publicKey], - blockInfo, - { useTransaction: true }, - ); - - const noKeyIdentityResult = await identityRepository.fetch(identity.getId()); - - const noKeyIdentity = noKeyIdentityResult.getValue(); - - expect(noKeyIdentity.toObject()).to.deep.equals(identity.toObject()); - - const transactionalIdentityResult = await identityRepository.fetch(identity.getId(), { - useTransaction: true, - }); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - identity.getPublicKeys().push(publicKey); - - expect(transactionalIdentity.toObject()).to.deep.equals(identity.toObject()); - - await store.commitTransaction(); - - const committedIdentityResult = await identityRepository.fetch(identity.getId()); - - const committedIdentity = committedIdentityResult.getValue(); - - expect(committedIdentity.toObject()).to.deep.equals(identity.toObject()); - }); - }); - - describe('#disable', () => { - it('should disable public keys in identity', async () => { - await identityRepository.create(identity, blockInfo); - - const result = await publicKeyRepository.disable( - identity.getId(), - [0, 1], - Date.now(), - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedIdentityResult = await identityRepository.fetch(identity.getId()); - - const fetchedIdentity = fetchedIdentityResult.getValue(); - - expect(fetchedIdentity.toObject()).to.not.deep.equals(identity.toObject()); - }); - - it('should store public key to identities using transaction', async () => { - await identityRepository.create(identity, blockInfo); - - await store.startTransaction(); - - await publicKeyRepository.disable( - identity.getId(), - [0, 1], - Date.now(), - blockInfo, - { useTransaction: true }, - ); - - const noChangeIdentityResult = await identityRepository.fetch(identity.getId()); - - const noChangeIdentity = noChangeIdentityResult.getValue(); - - expect(noChangeIdentity.toObject()).to.deep.equals(identity.toObject()); - - const transactionalIdentityResult = await identityRepository.fetch(identity.getId(), { - useTransaction: true, - }); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity.toObject()).to.not.deep.equals(identity.toObject()); - - await store.commitTransaction(); - - const committedIdentityResult = await identityRepository.fetch(identity.getId()); - - const committedIdentity = committedIdentityResult.getValue(); - - expect(committedIdentity.toObject()).to.not.deep.equals(identity.toObject()); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/IdentityStoreRepository.spec.js b/packages/js-drive/test/integration/identity/IdentityStoreRepository.spec.js deleted file mode 100644 index dce6fe8f74b..00000000000 --- a/packages/js-drive/test/integration/identity/IdentityStoreRepository.spec.js +++ /dev/null @@ -1,544 +0,0 @@ -const fs = require('fs'); -const Drive = require('@dashevo/rs-drive'); -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const IdentityStoreRepository = require('../../../lib/identity/IdentityStoreRepository'); -const logger = require('../../../lib/util/noopLogger'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('IdentityStoreRepository', () => { - let rsDrive; - let store; - let repository; - let decodeProtocolEntity; - let identity; - let blockInfo; - let publicKeyHashes; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - await rsDrive.createInitialStateStructure(); - - store = new GroveDBStore(rsDrive, logger); - - decodeProtocolEntity = decodeProtocolEntityFactory(); - - repository = new IdentityStoreRepository(store, decodeProtocolEntity); - identity = getIdentityFixture(); - - blockInfo = new BlockInfo(1, 1, Date.now()); - - publicKeyHashes = identity.getPublicKeys().map((k) => k.hash()); - }); - - afterEach(async () => { - await rsDrive.close(); - - fs.rmSync('./db/grovedb_test', { recursive: true, force: true }); - }); - - describe('#create', () => { - it('should create an identity', async () => { - const result = await repository.create( - identity, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedResult = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(fetchedResult.toObject()).to.be.deep.equal(identity.toObject()); - }); - - it('should store identity using transaction', async () => { - await store.startTransaction(); - - await repository.create( - identity, - blockInfo, - { useTransaction: true }, - ); - - const notFoundIdentity = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(notFoundIdentity).to.be.null(); - - const identityTransaction = await rsDrive.fetchIdentity( - identity.getId(), - true, - ); - - expect(identityTransaction.toObject()).to.deep.equal(identity.toObject()); - - await store.commitTransaction(); - - const committedIdentity = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(committedIdentity.toObject()).to.deep.equal(identity.toObject()); - }); - }); - - describe('#updateRevision', () => { - beforeEach(async () => { - await repository.create( - identity, - blockInfo, - ); - }); - - it('should update revision', async () => { - const revision = 2; - - const result = await repository.updateRevision( - identity.getId(), - revision, - blockInfo, - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const fetchedIdentity = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(fetchedIdentity.getRevision()).to.equal(revision); - }); - - it('should remove from balance using transaction', async () => { - await store.startTransaction(); - - const revision = 2; - - await repository.updateRevision( - identity.getId(), - revision, - blockInfo, - { useTransaction: true }, - ); - - const previousIdentity = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(previousIdentity.getRevision()).to.equal(identity.getRevision()); - - const transactionalIdentity = await rsDrive.fetchIdentity( - identity.getId(), - true, - ); - - expect(transactionalIdentity.getRevision()).to.equal(revision); - - await store.commitTransaction(); - - const commitedIdentity = await rsDrive.fetchIdentity( - identity.getId(), - ); - - expect(commitedIdentity.getRevision()).to.equal(revision); - }); - }); - - describe('#fetch', () => { - context('without block info', () => { - it('should fetch null if identity not found', async () => { - const result = await repository.fetch(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch an identity', async () => { - await rsDrive.insertIdentity(identity, blockInfo); - - const result = await repository.fetch(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const storedIdentity = result.getValue(); - - expect(storedIdentity).to.be.an.instanceof(Identity); - expect(storedIdentity.toObject()).to.deep.equal(identity.toObject()); - }); - - it('should fetch an identity using transaction', async () => { - await store.startTransaction(); - - await rsDrive.insertIdentity(identity, blockInfo, true); - - const notFoundIdentityResult = await repository.fetch(identity.getId(), { - useTransaction: false, - }); - - expect(notFoundIdentityResult.getValue()).to.be.null(); - - const transactionalIdentityResult = await repository.fetch(identity.getId(), { - useTransaction: true, - }); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity).to.be.an.instanceof(Identity); - expect(transactionalIdentity.toObject()).to.deep.equal(identity.toObject()); - - await store.commitTransaction(); - - const storedIdentityResult = await repository.fetch(identity.getId()); - - const storedIdentity = storedIdentityResult.getValue(); - - expect(storedIdentity).to.be.an.instanceof(Identity); - expect(storedIdentity.toObject()).to.deep.equal(identity.toObject()); - }); - }); - - context('with block info', () => { - it('should fetch null if identity not found', async () => { - const result = await repository.fetch(identity.getId(), { blockInfo }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - expect(result.getValue()).to.be.null(); - }); - - it('should fetch an identity', async () => { - await rsDrive.insertIdentity(identity, blockInfo); - - const result = await repository.fetch(identity.getId(), { blockInfo }); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(1); - - const storedIdentity = result.getValue(); - - expect(storedIdentity).to.be.an.instanceof(Identity); - expect(storedIdentity.toObject()).to.deep.equal(identity.toObject()); - }); - - it('should fetch an identity using transaction', async () => { - await store.startTransaction(); - - await rsDrive.insertIdentity(identity, blockInfo, true); - - const notFoundIdentityResult = await repository.fetch(identity.getId(), { - blockInfo, - useTransaction: false, - }); - - expect(notFoundIdentityResult.getValue()).to.be.null(); - - const transactionalIdentityResult = await repository.fetch(identity.getId(), { - blockInfo, - useTransaction: true, - }); - - const transactionalIdentity = transactionalIdentityResult.getValue(); - - expect(transactionalIdentity).to.be.an.instanceof(Identity); - expect(transactionalIdentity.toObject()).to.deep.equal(identity.toObject()); - - await store.commitTransaction(); - - const storedIdentityResult = await repository.fetch(identity.getId(), { - blockInfo, - }); - - const storedIdentity = storedIdentityResult.getValue(); - - expect(storedIdentity).to.be.an.instanceof(Identity); - expect(storedIdentity.toObject()).to.deep.equal(identity.toObject()); - }); - }); - }); - - describe('#fetchByPublicKeyHashes', () => { - it('should fetch an identities by public key hashes', async () => { - await rsDrive.insertIdentity(identity, blockInfo); - - const result = await repository.fetchManyByPublicKeyHashes( - publicKeyHashes.concat([Buffer.alloc(20)]), - ); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const fetchedIdentities = result.getValue(); - - for (let i = 0; i < identity.getPublicKeys().length; i++) { - const fetchedIdentity = fetchedIdentities[i]; - - expect(fetchedIdentity).to.be.instanceOf(Identity); - expect(fetchedIdentity).to.deep.equal(identity.toObject()); - } - }); - }); - - describe('#proveManyByPublicKeyHashes', () => { - it('should fetch proof if public key to identities map not found', async () => { - const result = await repository.proveManyByPublicKeyHashes([ - Buffer.alloc(20, 1), - Buffer.alloc(20, 2), - ]); - - expect(result).to.be.instanceOf(StorageResult); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - }); - - it('should return proof', async () => { - await repository.create(identity, blockInfo); - - const result = await repository.proveManyByPublicKeyHashes(publicKeyHashes); - - expect(result).to.be.instanceOf(StorageResult); - - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - }); - - // TODO: Enable when transactions will be supported for queries with proofs - it.skip('should return proof map using transaction', async () => { - await store.startTransaction(); - - await repository.create(identity, blockInfo, { useTransaction: true }); - - // Should return proof of non-existence - let result = await repository.proveManyByPublicKeyHashes(publicKeyHashes); - - expect(result).to.be.instanceOf(StorageResult); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - - // Should return proof of existence - result = await repository.proveManyByPublicKeyHashes( - publicKeyHashes, - { useTransaction: true }, - ); - - expect(result).to.be.instanceOf(StorageResult); - - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - - await store.commitTransaction(); - - // Should return proof of existence - result = await repository.proveManyByPublicKeyHashes(publicKeyHashes); - - expect(result).to.be.instanceOf(StorageResult); - - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.an.instanceOf(Buffer); - expect(result.getValue().length).to.be.greaterThan(0); - }); - }); - - describe('#prove', () => { - it('should return prove if identity does not exist', async () => { - const result = await repository.prove(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof', async () => { - await repository.create(identity, blockInfo); - - const result = await repository.prove(identity.getId()); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - // TODO enable this test when we support transactions - it.skip('should return proof using transaction', async () => { - await store.startTransaction(); - - await store.createTree( - IdentityStoreRepository.TREE_PATH, - identity.getId().toBuffer(), - { useTransaction: true }, - ); - - await store.put( - IdentityStoreRepository.TREE_PATH.concat([identity.getId().toBuffer()]), - IdentityStoreRepository.IDENTITY_KEY, - identity.toBuffer(), - { useTransaction: true }, - ); - - const notFoundProof = await repository.prove(identity.getId(), { - useTransaction: false, - }); - - expect(notFoundProof.getValue()).to.be.null(); - - const transactionalIdentityResult = await repository.prove(identity.getId(), { - useTransaction: true, - }); - - const transactionalProof = transactionalIdentityResult.getValue(); - - expect(transactionalProof).to.be.an.instanceof(Buffer); - expect(transactionalProof.length).to.be.greaterThan(0); - - await store.commitTransaction(); - - const storedIdentityResult = await repository.prove(identity.getId()); - - const storedProof = storedIdentityResult.getValue(); - - expect(storedProof).to.be.an.instanceof(Buffer); - expect(storedProof.length).to.be.greaterThan(0); - }); - }); - - describe('#proveMany', () => { - let identity2; - - beforeEach(async () => { - // Set correct but unique public key data - const data = Buffer.from(identity.getPublicKeys()[0].getData()); - data[data.length - 1] = 2; - - identity2 = new Identity({ - protocolVersion: 1, - id: generateRandomIdentifier().toBuffer(), - publicKeys: [ - { - id: 0, - type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: false, - data, - }, - ], - balance: 10, - revision: 0, - }); - }); - - it('should return proof if identity does not exist', async () => { - await repository.create(identity, blockInfo); - - const result = await repository.proveMany([identity.getId(), identity2.getId()]); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - it('should return proof', async () => { - await repository.create(identity, blockInfo); - await repository.create(identity2, blockInfo); - - const result = await repository.proveMany([identity.getId(), identity2.getId()]); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const proof = result.getValue(); - - expect(proof).to.be.an.instanceof(Buffer); - expect(proof.length).to.be.greaterThan(0); - }); - - // TODO enable this test when we support transactions - it.skip('should return proof using transaction', async () => { - await store.startTransaction(); - - await store.createTree( - IdentityStoreRepository.TREE_PATH, - identity.getId().toBuffer(), - { useTransaction: true }, - ); - - await store.put( - IdentityStoreRepository.TREE_PATH.concat([identity.getId().toBuffer()]), - IdentityStoreRepository.IDENTITY_KEY, - identity.toBuffer(), - { useTransaction: true }, - ); - - const notFoundProof = await repository.proveMany([identity.getId(), identity2.getId()], { - useTransaction: false, - }); - - expect(notFoundProof.getValue()).to.be.null(); - - const transactionalIdentityResult = await repository.proveMany( - [identity.getId(), identity2.getId()], - { useTransaction: true }, - ); - - const transactionalProof = transactionalIdentityResult.getValue(); - - expect(transactionalProof).to.be.an.instanceof(Buffer); - expect(transactionalProof.length).to.be.greaterThan(0); - - await store.commitTransaction(); - - const storedIdentityResult = await repository.proveMany( - [identity.getId(), identity2.getId()], - ); - - const storedProof = storedIdentityResult.getValue(); - - expect(storedProof).to.be.an.instanceof(Buffer); - expect(storedProof.length).to.be.greaterThan(0); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/SpentAssetLockTransactionsRepository.spec.js b/packages/js-drive/test/integration/identity/SpentAssetLockTransactionsRepository.spec.js deleted file mode 100644 index b21ab1687fc..00000000000 --- a/packages/js-drive/test/integration/identity/SpentAssetLockTransactionsRepository.spec.js +++ /dev/null @@ -1,85 +0,0 @@ -const Drive = require('@dashevo/rs-drive'); -const fs = require('fs'); - -const SpentAssetLockTransactionsRepository = require('../../../lib/identity/SpentAssetLockTransactionsRepository'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const GroveDBStore = require('../../../lib/storage/GroveDBStore'); -const logger = require('../../../lib/util/noopLogger'); - -describe('SpentAssetLockTransactionsRepository', () => { - let outPointBuffer; - let repository; - let store; - let rsDrive; - - beforeEach(async () => { - outPointBuffer = Buffer.from([42]); - - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, logger); - - await rsDrive.createInitialStateStructure(); - - repository = new SpentAssetLockTransactionsRepository(store); - }); - - afterEach(async () => { - await rsDrive.close(); - fs.rmSync('./db/grovedb_test', { recursive: true }); - }); - - describe('#store', () => { - it('should store outpoint', async () => { - const result = await repository.store(outPointBuffer); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const placeholderResult = await store.get( - SpentAssetLockTransactionsRepository.TREE_PATH, - outPointBuffer, - ); - - expect(placeholderResult.getValue()).to.deep.equal(Buffer.from([0])); - }); - }); - - describe('#fetch', () => { - it('should return null if outpoint is not present', async () => { - const result = await repository.fetch(outPointBuffer); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should return buffer containing [0]', async () => { - await store.put( - SpentAssetLockTransactionsRepository.TREE_PATH, - outPointBuffer, - Buffer.from([0]), - ); - - const result = await repository.fetch(outPointBuffer); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.deep.equal(Buffer.from([0])); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/masternode/LastSyncedCoreHeightRepository.spec.js b/packages/js-drive/test/integration/identity/masternode/LastSyncedCoreHeightRepository.spec.js deleted file mode 100644 index d9c75f95503..00000000000 --- a/packages/js-drive/test/integration/identity/masternode/LastSyncedCoreHeightRepository.spec.js +++ /dev/null @@ -1,89 +0,0 @@ -const Drive = require('@dashevo/rs-drive'); -const fs = require('fs'); - -const LastSyncedSmlHeightRepository = require('../../../../lib/identity/masternode/LastSyncedCoreHeightRepository'); -const StorageResult = require('../../../../lib/storage/StorageResult'); -const GroveDBStore = require('../../../../lib/storage/GroveDBStore'); -const logger = require('../../../../lib/util/noopLogger'); - -describe('LastSyncedSmlHeightRepository', () => { - let repository; - let store; - let rsDrive; - - beforeEach(async () => { - rsDrive = new Drive('./db/grovedb_test', { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - store = new GroveDBStore(rsDrive, logger); - - repository = new LastSyncedSmlHeightRepository(store); - - // Create initial structure - await rsDrive.createInitialStateStructure(false); - }); - - afterEach(async () => { - await rsDrive.close(); - fs.rmSync('./db/grovedb_test', { recursive: true }); - }); - - describe('#store', () => { - it('should store last synced height', async () => { - const result = await repository.store(1); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - const placeholderResult = await store.get( - LastSyncedSmlHeightRepository.TREE_PATH, - LastSyncedSmlHeightRepository.KEY, - ); - - const encodedValue = placeholderResult.getValue(); - - expect(encodedValue.readUInt32BE()).to.deep.equal(1); - }); - }); - - describe('#fetch', () => { - it('should return null if last synced height is not present', async () => { - const result = await repository.fetch(); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.null(); - }); - - it('should return last synced height', async () => { - const encodedValue = Buffer.alloc(4); - - encodedValue.writeUInt32BE(1); - - await store.put( - LastSyncedSmlHeightRepository.TREE_PATH, - LastSyncedSmlHeightRepository.KEY, - encodedValue, - ); - - const result = await repository.fetch(); - - expect(result).to.be.instanceOf(StorageResult); - expect(result.getOperations().length).to.equal(0); - - expect(result.getValue()).to.be.deep.equal(1); - }); - }); -}); diff --git a/packages/js-drive/test/integration/identity/masternode/synchronizeMasternodeIdentitiesFactory.spec.js b/packages/js-drive/test/integration/identity/masternode/synchronizeMasternodeIdentitiesFactory.spec.js deleted file mode 100644 index 78a548b476c..00000000000 --- a/packages/js-drive/test/integration/identity/masternode/synchronizeMasternodeIdentitiesFactory.spec.js +++ /dev/null @@ -1,1093 +0,0 @@ -const { - asValue, -} = require('awilix'); - -const SimplifiedMNListEntry = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListEntry'); -const { hash } = require('@dashevo/dpp/lib/util/hash'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); - -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const createTestDIContainer = require('../../../../lib/test/createTestDIContainer'); -const createOperatorIdentifier = require('../../../../lib/identity/masternode/createOperatorIdentifier'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); -const createVotingIdentifier = require('../../../../lib/identity/masternode/createVotingIdentifier'); -const getSystemIdentityPublicKeysFixture = require('../../../../lib/test/fixtures/getSystemIdentityPublicKeysFixture'); - -/** - * @param {IdentityStoreRepository} identityRepository - * @param {IdentityPublicKeyStoreRepository} identityPublicKeyRepository - * @param {getWithdrawPubKeyTypeFromPayoutScript} getWithdrawPubKeyTypeFromPayoutScript - * @param {getPublicKeyFromPayoutScript} getPublicKeyFromPayoutScript - * @returns {expectOperatorIdentity} - */ -function expectOperatorIdentityFactory( - identityRepository, - identityPublicKeyRepository, - getWithdrawPubKeyTypeFromPayoutScript, - getPublicKeyFromPayoutScript, -) { - /** - * @typedef {expectOperatorIdentity} - * @param {SimplifiedMNListEntry} smlEntry - * @param {Address} [previousPayoutAddress] - * @param {Address} [payoutAddress] - * @returns {Promise} - */ - async function expectOperatorIdentity( - smlEntry, - previousPayoutAddress, - payoutAddress, - ) { - // Validate operator identity - - const operatorIdentifier = createOperatorIdentifier(smlEntry); - - const operatorIdentityResult = await identityRepository.fetch( - operatorIdentifier, - { useTransaction: true }, - ); - - const operatorIdentity = operatorIdentityResult.getValue(); - - expect(operatorIdentity).to.exist(); - - // Validate operator public keys - - const operatorPubKey = Buffer.from(smlEntry.pubKeyOperator, 'hex'); - - let publicKeysNum = 1; - if (payoutAddress) { - publicKeysNum += 1; - } - if (previousPayoutAddress) { - publicKeysNum += 1; - } - - expect(operatorIdentity.getPublicKeys()) - .to - .have - .lengthOf(publicKeysNum); - - const firstOperatorMasternodePublicKey = operatorIdentity.getPublicKeyById(0); - expect(firstOperatorMasternodePublicKey.getType()) - .to - .equal(IdentityPublicKey.TYPES.BLS12_381); - expect(firstOperatorMasternodePublicKey.getData()) - .to - .deep - .equal(operatorPubKey); - - const firstOperatorIdentityByPublicKeyHashResult = await identityRepository - .fetchByPublicKeyHash(firstOperatorMasternodePublicKey.hash(), { useTransaction: true }); - - const firstOperatorIdentityByPublicKeyHash = firstOperatorIdentityByPublicKeyHashResult - .getValue(); - - expect(firstOperatorIdentityByPublicKeyHash).to.be.not.null(); - expect(firstOperatorIdentityByPublicKeyHash.getId()) - .to - .deep - .equal(operatorIdentifier); - - let i = 0; - - if (previousPayoutAddress) { - i += 1; - const payoutScript = new Script(previousPayoutAddress); - const publicKeyType = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - const payoutPublicKey = operatorIdentity.getPublicKeyById(i); - expect(payoutPublicKey.getType()).to.equal(publicKeyType); - expect(payoutPublicKey.getData()).to.deep.equal( - getPublicKeyFromPayoutScript(payoutScript, publicKeyType), - ); - - const masternodeIdentityByPayoutPublicKeyHashResult = await identityPublicKeyRepository - .fetch(payoutPublicKey.hash(), { useTransaction: true }); - - const masternodeIdentityByPayoutPublicKeyHash = masternodeIdentityByPayoutPublicKeyHashResult - .getValue(); - - expect(masternodeIdentityByPayoutPublicKeyHash).to.have.lengthOf(1); - expect(masternodeIdentityByPayoutPublicKeyHash[0].toBuffer()) - .to.deep.equal(operatorIdentifier); - } - - if (payoutAddress) { - i += 1; - const payoutScript = new Script(payoutAddress); - const publicKeyType = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - const payoutPublicKey = operatorIdentity.getPublicKeyById(i); - expect(payoutPublicKey.getType()).to.equal(publicKeyType); - expect(payoutPublicKey.getData()).to.deep.equal( - getPublicKeyFromPayoutScript(payoutScript, publicKeyType), - ); - - const masternodeIdentityByPayoutPublicKeyHashResult = await identityRepository - .fetchByPublicKeyHash(payoutPublicKey.hash(), { useTransaction: true }); - - const masternodeIdentityByPayoutPublicKeyHash = masternodeIdentityByPayoutPublicKeyHashResult - .getValue(); - - expect(masternodeIdentityByPayoutPublicKeyHash).to.be.not.null(); - expect(masternodeIdentityByPayoutPublicKeyHash.getId()) - .to.deep.equal(operatorIdentifier); - } - } - - return expectOperatorIdentity; -} - -/** - * @param {IdentityStoreRepository} identityRepository - * @returns {expectVotingIdentity} - */ -function expectVotingIdentityFactory( - identityRepository, -) { - /** - * @typedef {expectVotingIdentity} - * @param {SimplifiedMNListEntry} smlEntry - * @param {Buffer} proRegTx - * @returns {Promise} - */ - async function expectVotingIdentity( - smlEntry, - proRegTx, - ) { - // Validate voting identity - - const votingIdentifier = createVotingIdentifier(smlEntry); - - const votingIdentityResult = await identityRepository.fetch(votingIdentifier, { - useTransaction: true, - }); - - const votingIdentity = votingIdentityResult.getValue(); - - expect(votingIdentity) - .to - .exist(); - - // Validate voting public keys - - expect(votingIdentity.getPublicKeys()) - .to - .have - .lengthOf(1); - - const masternodePublicKey = votingIdentity.getPublicKeyById(0); - expect(masternodePublicKey.getType()).to.equal(IdentityPublicKey.TYPES.ECDSA_HASH160); - expect(masternodePublicKey.getData()).to.deep.equal( - Buffer.from(proRegTx.extraPayload.keyIDVoting, 'hex').reverse(), - ); - - const masternodeIdentityByPublicKeyHashResult = await identityRepository - .fetchByPublicKeyHash(masternodePublicKey.hash(), { - useTransaction: true, - }); - - const masternodeIdentityByPublicKeyHash = masternodeIdentityByPublicKeyHashResult.getValue(); - - expect(masternodeIdentityByPublicKeyHash).to.be.not.null(); - expect(masternodeIdentityByPublicKeyHash.getId()) - .to.deep.equal(votingIdentifier); - } - - return expectVotingIdentity; -} - -/** - * @param {IdentityStoreRepository} identityRepository - * @param {IdentityPublicKeyStoreRepository} identityPublicKeyRepository - * @param {getWithdrawPubKeyTypeFromPayoutScript} getWithdrawPubKeyTypeFromPayoutScript - * @param {getPublicKeyFromPayoutScript} getPublicKeyFromPayoutScript - * @returns {expectMasternodeIdentity} - */ -function expectMasternodeIdentityFactory( - identityRepository, - identityPublicKeyRepository, - getWithdrawPubKeyTypeFromPayoutScript, - getPublicKeyFromPayoutScript, -) { - /** - * @typedef {expectMasternodeIdentity} - * @param {SimplifiedMNListEntry} smlEntry - * @param {Object} proRegTx - * @param {Address} [previousPayoutAddress] - * @param {Address} [payoutAddress] - * @returns {Promise} - */ - async function expectMasternodeIdentity( - smlEntry, - proRegTx, - previousPayoutAddress, - payoutAddress, - ) { - const masternodeIdentifier = Identifier.from( - Buffer.from(smlEntry.proRegTxHash, 'hex'), - ); - - const masternodeIdentityResult = await identityRepository.fetch( - masternodeIdentifier, - { useTransaction: true }, - ); - - const masternodeIdentity = masternodeIdentityResult.getValue(); - - expect(masternodeIdentity).to.be.not.null(); - - // Validate masternode identity public keys - let publicKeysNum = 1; - if (payoutAddress) { - publicKeysNum += 1; - } - if (previousPayoutAddress) { - publicKeysNum += 1; - } - - expect(masternodeIdentity.getPublicKeys()).to.have.lengthOf(publicKeysNum); - - const masternodePublicKey = masternodeIdentity.getPublicKeyById(0); - expect(masternodePublicKey.getType()).to.equal(IdentityPublicKey.TYPES.ECDSA_HASH160); - expect(masternodePublicKey.getData()).to.deep.equal( - Buffer.from(proRegTx.extraPayload.keyIDOwner, 'hex').reverse(), - ); - - const masternodeIdentityByPublicKeyHashResult = await identityRepository - .fetchManyByPublicKeyHashes([masternodePublicKey.hash()], { useTransaction: true }); - - const masternodeIdentityByPublicKeyHash = masternodeIdentityByPublicKeyHashResult.getValue(); - - expect(masternodeIdentityByPublicKeyHash).to.have.lengthOf(1); - expect(masternodeIdentityByPublicKeyHash[0].getId()) - .to.deep.equal(masternodeIdentifier); - - let i = 0; - - if (previousPayoutAddress) { - i += 1; - const payoutScript = new Script(previousPayoutAddress); - const publicKeyType = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - const payoutPublicKey = masternodeIdentity.getPublicKeyById(i); - expect(payoutPublicKey.getType()).to.equal(publicKeyType); - expect(payoutPublicKey.getData()).to.deep.equal( - getPublicKeyFromPayoutScript(payoutScript, publicKeyType), - ); - - const masternodeIdentityByPayoutPublicKeyHashResult = await identityRepository - .fetchByPublicKeyHash(payoutPublicKey.hash(), { useTransaction: true }); - - const masternodeIdentityByPayoutPublicKeyHash = masternodeIdentityByPayoutPublicKeyHashResult - .getValue(); - - expect(masternodeIdentityByPayoutPublicKeyHash).to.not.be.null(); - expect(masternodeIdentityByPayoutPublicKeyHash.getId()) - .to.deep.equal(masternodeIdentifier); - } - - if (payoutAddress) { - i += 1; - const payoutScript = new Script(payoutAddress); - const publicKeyType = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - const payoutPublicKey = masternodeIdentity.getPublicKeyById(i); - expect(payoutPublicKey.getType()).to.equal(publicKeyType); - expect(payoutPublicKey.getData()).to.deep.equal( - getPublicKeyFromPayoutScript(payoutScript, publicKeyType), - ); - - const masternodeIdentityByPayoutPublicKeyHashResult = await identityRepository - .fetchByPublicKeyHash(payoutPublicKey.hash(), { useTransaction: true }); - - const masternodeIdentityByPayoutPublicKeyHash = masternodeIdentityByPayoutPublicKeyHashResult - .getValue(); - - expect(masternodeIdentityByPayoutPublicKeyHash).to.not.be.null(); - expect(masternodeIdentityByPayoutPublicKeyHash.getId()) - .to.deep.equal(masternodeIdentifier); - } - } - - return expectMasternodeIdentity; -} - -/** - * @param {GroveDBStore} groveDBStore - * @returns {expectDeterministicAppHash} - */ -function expectDeterministicAppHashFactory(groveDBStore) { - /** - * @typedef {expectDeterministicAppHash} - * @param {string} appHash - * @returns {Promise} - */ - async function expectDeterministicAppHash(appHash) { - const actualAppHash = await groveDBStore.getRootHash({ useTransaction: true }); - - const actualAppHashHex = actualAppHash.toString('hex'); - - expect(actualAppHashHex).to.deep.equal(appHash); - } - - return expectDeterministicAppHash; -} - -// TODO: Enable keys when we have support of non unique keys in DPP -describe.skip('synchronizeMasternodeIdentitiesFactory', function main() { - this.timeout(10000); - let container; - let coreHeight; - let fetchSimplifiedMNListMock; - let fetchedSimplifiedMNList; - let fetchTransactionMock; - let smlStoreMock; - let smlFixture; - let newSmlFixture; - let transaction1; - let transaction2; - let transaction3; - let synchronizeMasternodeIdentities; - let rewardsDataContract; - let identityRepository; - let documentRepository; - let identityPublicKeyRepository; - let expectOperatorIdentity; - let expectVotingIdentity; - let expectMasternodeIdentity; - let expectDeterministicAppHash; - let firstSyncAppHash; - let blockInfo; - - beforeEach(async function beforeEach() { - coreHeight = 3; - firstSyncAppHash = 'c55de453e3ea4481f20225efdc12d671f715f0618cf3084bb32e56e75123bfdd'; - blockInfo = new BlockInfo(10, 0, 1668702100799); - - container = await createTestDIContainer(); - - // Mock Core RPC - - fetchedSimplifiedMNList = { - mnList: [], - }; - - fetchSimplifiedMNListMock = this.sinon.stub().resolves(fetchedSimplifiedMNList); - - container.register('fetchSimplifiedMNList', asValue(fetchSimplifiedMNListMock)); - - // Mock SML - - smlFixture = [ - new SimplifiedMNListEntry({ - proRegTxHash: 'a2c9b34ef525271d84f70a0d4d2c107e8a2f81cd4d8256dc7b3911ed253d5611', - confirmedHash: '29ff8afb463604ba7d984b483e92dfefa4e80e12de3acae6d75f9b910df9eab6', - service: '192.168.65.2:20201', - pubKeyOperator: 'a5ad6d8cad7b233210b718a5fc9ec3cea18aeebe38b2e3122deb581e430aa28875fe7336c283871db42808f8d4107745', - votingAddress: 'yRXtaRmQ7LCmT5XcgzQdLwPEf31dycBaeY', - isValid: true, - payoutAddress: 'yR843jN58m5dubmQjfUmKDDJMJzNatFV9M', - payoutOperatorAddress: 'yNjsnYM16J5NZPA2P8BKJG3MKfUD7XHAFE', - nType: 0, - }), - new SimplifiedMNListEntry({ - proRegTxHash: 'f5ec54aed788c434da2fc535ea6b125ec6fc54e58bc0a00a005d1a8d5e477a90', - confirmedHash: '53125505b0e9d11b371cf3e12c92d164296dfa215fde6201d28ea44bed992187', - service: '192.168.65.2:20101', - pubKeyOperator: '951a3208ba531ea75aedd2dc0a9efc75f2c4d9492f1ee0a989b593bcd9722b1a101774d80a426552a9f91d24eb55af6e', - votingAddress: 'yYH1rgZsgvkmT8bSSSw1cKCjyVPnFpTBCw', - isValid: true, - payoutAddress: 'ycL7L4mhYoaZdm9TH85svvpfeKtdfo249u', - nType: 0, - }), - ]; - - newSmlFixture = [ - new SimplifiedMNListEntry({ - proRegTxHash: '1c81a5faa2c0e0d96eb59c58a10fcbc87f431bb6cd880d960b43b269e682d2d2', - confirmedHash: '03cc2acc135ab51304d3cff42215c7a8041902fa3f19451d5562a03b38143e8f', - service: '192.168.65.2:20001', - pubKeyOperator: '96f83eedc8a7b87663e591987f051ce341a6fb88989322c64bbbf56d205e4e77d2cb7d839d8b4106a8a1f5d5cf7cfa57', - votingAddress: 'ybJfuKs59MJWkPEnS8qNmtvdisHrCy7Njn', - isValid: true, - payoutAddress: '7UkJidhNjEPJCQnCTXeaJKbJmL4JuyV66w', - payoutOperatorAddress: 'yPDBTHAjPwJfZSSQYczccA78XRS2tZ5fZF', - nType: 0, - }), - ]; - - smlStoreMock = { - getSMLbyHeight: this.sinon.stub().returns({ mnList: smlFixture }), - }; - - const simplifiedMasternodeListMock = { - getStore: this.sinon.stub().returns(smlStoreMock), - }; - - container.register('simplifiedMasternodeList', asValue(simplifiedMasternodeListMock)); - - // Mock fetchTransaction - - fetchTransactionMock = this.sinon.stub(); - - transaction1 = { - extraPayload: { - operatorReward: 100, - keyIDOwner: Buffer.alloc(20).fill('a').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('b').toString('hex'), - }, - }; - - transaction2 = { - extraPayload: { - operatorReward: 0, - keyIDOwner: Buffer.alloc(20).fill('c').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('d').toString('hex'), - }, - }; - - transaction3 = { - extraPayload: { - operatorReward: 200, - keyIDOwner: Buffer.alloc(20).fill('e').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('f').toString('hex'), - }, - }; - - fetchTransactionMock.withArgs('a2c9b34ef525271d84f70a0d4d2c107e8a2f81cd4d8256dc7b3911ed253d5611').resolves(transaction1); - fetchTransactionMock.withArgs('f5ec54aed788c434da2fc535ea6b125ec6fc54e58bc0a00a005d1a8d5e477a90').resolves(transaction2); - fetchTransactionMock.withArgs('1c81a5faa2c0e0d96eb59c58a10fcbc87f431bb6cd880d960b43b269e682d2d2').resolves(transaction3); - - container.register('fetchTransaction', asValue(fetchTransactionMock)); - - const groveDBStore = container.resolve('groveDBStore'); - await groveDBStore.startTransaction(); - - /** - * @type {Drive} - */ - const rsDrive = container.resolve('rsDrive'); - await rsDrive.getAbci().initChain({ - genesisTimeMs: 0, - systemIdentityPublicKeys: getSystemIdentityPublicKeysFixture(), - }, true); - - const masternodeRewardSharesContractId = container.resolve('masternodeRewardSharesContractId'); - - [rewardsDataContract] = await rsDrive.fetchContract(masternodeRewardSharesContractId, 0, true); - - /** - * @type {synchronizeMasternodeIdentities} - */ - synchronizeMasternodeIdentities = container.resolve('synchronizeMasternodeIdentities'); - - identityRepository = container.resolve('identityRepository'); - documentRepository = container.resolve('documentRepository'); - identityPublicKeyRepository = container.resolve('identityPublicKeyRepository'); - const getWithdrawPubKeyTypeFromPayoutScript = container.resolve('getWithdrawPubKeyTypeFromPayoutScript'); - const getPublicKeyFromPayoutScript = container.resolve('getPublicKeyFromPayoutScript'); - - expectOperatorIdentity = expectOperatorIdentityFactory( - identityRepository, - identityPublicKeyRepository, - getWithdrawPubKeyTypeFromPayoutScript, - getPublicKeyFromPayoutScript, - ); - - expectVotingIdentity = expectVotingIdentityFactory( - identityRepository, - ); - - expectMasternodeIdentity = expectMasternodeIdentityFactory( - identityRepository, - identityPublicKeyRepository, - getWithdrawPubKeyTypeFromPayoutScript, - getPublicKeyFromPayoutScript, - ); - - expectDeterministicAppHash = expectDeterministicAppHashFactory( - container.resolve('groveDBStore'), - ); - }); - - afterEach(async () => { - if (container) { - await container.dispose(); - } - }); - - it('should create identities for all masternodes on the first sync', async () => { - const result = await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - expect(result.fromHeight).to.be.equal(0); - expect(result.toHeight).to.be.equal(3); - expect(result.createdEntities).to.have.lengthOf(6); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - await expectDeterministicAppHash(firstSyncAppHash); - - /** - * Validate first masternode - */ - - // Masternode identity should be created - - await expectMasternodeIdentity( - smlFixture[0], - transaction1, - undefined, - Address.fromString(smlFixture[0].payoutAddress), - ); - - // voting identity should be created - await expectVotingIdentity( - smlFixture[0], - transaction1, - ); - - // Operator identity should be created - - await expectOperatorIdentity(smlFixture[0]); - - // Masternode reward shares should be created - - const firstMasternodeIdentifier = Identifier.from( - Buffer.from(smlFixture[0].proRegTxHash, 'hex'), - ); - - const firstOperatorIdentifier = createOperatorIdentifier(smlFixture[0]); - - let documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', firstMasternodeIdentifier], - ['payToId', '==', firstOperatorIdentifier], - ], - useTransaction: true, - }, - ); - - let documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(1); - - const expectedDocumentId = Identifier.from( - hash( - Buffer.concat([ - firstMasternodeIdentifier, - firstOperatorIdentifier, - ]), - ), - ); - - expect(documents[0].getId()).to.deep.equal(expectedDocumentId); - expect(documents[0].getOwnerId()).to.deep.equal(firstMasternodeIdentifier); - expect(documents[0].get('percentage')).to.equal(100); - expect(documents[0].get('payToId')).to.deep.equal(firstOperatorIdentifier); - - /** - * Validate second masternode - */ - - // Masternode identity should be created - - await expectMasternodeIdentity( - smlFixture[1], - transaction2, - undefined, - Address.fromString(smlFixture[1].payoutAddress), - ); - - // Voting identity should be created - await expectVotingIdentity( - smlFixture[1], - transaction2, - ); - - // Operator identity shouldn't be created - - const secondOperatorPubKey = Buffer.from(smlFixture[1].pubKeyOperator, 'hex'); - - const secondOperatorIdentifier = Identifier.from( - hash( - Buffer.concat([ - Buffer.from(smlFixture[1].proRegTxHash, 'hex'), - secondOperatorPubKey, - ]), - ), - ); - - const secondOperatorIdentityResult = await identityRepository.fetch( - secondOperatorIdentifier, - { useTransaction: true }, - ); - - const secondOperatorIdentity = secondOperatorIdentityResult.getValue(); - - expect(secondOperatorIdentity).to.be.null(); - - // Masternode reward shares shouldn't be created - - const secondMasternodeIdentifier = Identifier.from( - Buffer.from(smlFixture[1].proRegTxHash, 'hex'), - ); - - documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', secondMasternodeIdentifier], - ['payToId', '==', secondOperatorIdentifier], - ], - useTransaction: true, - }, - ); - - documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(0); - }); - - it('should sync identities if the gap between coreHeight and lastSyncedCoreHeight > smlMaxListsLimit', async () => { - // Sync initial list - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - await expectDeterministicAppHash(firstSyncAppHash); - - const nextCoreHeight = coreHeight + 42; - - // Mock SML - - smlStoreMock.getSMLbyHeight.withArgs(nextCoreHeight).returns({ - mnList: smlFixture.concat(newSmlFixture), - }); - - fetchedSimplifiedMNList.mnList = smlFixture; - - // Second call - - const result = await synchronizeMasternodeIdentities(nextCoreHeight, blockInfo); - - expect(result.fromHeight).to.be.equal(3); - expect(result.toHeight).to.be.equal(45); - expect(result.createdEntities).to.have.lengthOf(4); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - // Nothing happened - - await expectDeterministicAppHash('a789fe73ceea6769634b98ae82dddad5013c4711b2a8353d2150b813fb953cb3'); - - // Core RPC should be called - - expect(fetchSimplifiedMNListMock).to.have.been.calledOnceWithExactly(1, coreHeight); - }); - - it('should create masternode identities if new masternode appeared', async () => { - // Sync initial list - - const result = await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - expect(result.fromHeight).to.be.equal(0); - expect(result.toHeight).to.be.equal(coreHeight); - expect(result.createdEntities).to.have.lengthOf(6); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - await expectDeterministicAppHash(firstSyncAppHash); - - // Mock SML - - smlStoreMock.getSMLbyHeight.withArgs(coreHeight + 1).returns( - { mnList: smlFixture.concat(newSmlFixture) }, - ); - - // Second call - - const result2 = await synchronizeMasternodeIdentities(coreHeight + 1, blockInfo); - - expect(result2.fromHeight).to.be.equal(3); - expect(result2.toHeight).to.be.equal(4); - expect(result2.createdEntities).to.have.lengthOf(4); - expect(result2.updatedEntities).to.have.lengthOf(0); - expect(result2.removedEntities).to.have.lengthOf(0); - - await expectDeterministicAppHash('b58bc0499156caea9b930ab0e357f56b20bb191bc7ba97a2eb8941d9ba7a8183'); - - // New masternode identity should be created - - await expectMasternodeIdentity( - newSmlFixture[0], - transaction3, - undefined, - Address.fromString(newSmlFixture[0].payoutAddress), - ); - - // New voting identity should be created - - await expectVotingIdentity( - newSmlFixture[0], - transaction3, - ); - - // New operator should be created - - await expectOperatorIdentity(newSmlFixture[0]); - - // Masternode reward shares should be created - - const newMasternodeIdentifier = Identifier.from( - Buffer.from(newSmlFixture[0].proRegTxHash, 'hex'), - ); - - const newOperatorIdentifier = createOperatorIdentifier(newSmlFixture[0]); - - const documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', newMasternodeIdentifier], - ['payToId', '==', newOperatorIdentifier], - ], - useTransaction: true, - }, - ); - - const documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(1); - - const expectedDocumentId = Identifier.from( - hash( - Buffer.concat([ - newMasternodeIdentifier, - newOperatorIdentifier, - ]), - ), - ); - - expect(documents[0].getId()).to.deep.equal(expectedDocumentId); - expect(documents[0].getOwnerId()).to.deep.equal(newMasternodeIdentifier); - expect(documents[0].get('percentage')).to.equal(200); - expect(documents[0].get('payToId')).to.deep.equal(newOperatorIdentifier); - }); - - it('should remove reward shares if masternode disappeared', async () => { - // Sync initial list - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - await expectDeterministicAppHash(firstSyncAppHash); - - // Mock SML - - smlStoreMock.getSMLbyHeight.withArgs(coreHeight + 1).returns( - { mnList: [smlFixture[1]] }, - ); - - // Second call - - const result = await synchronizeMasternodeIdentities(coreHeight + 1, blockInfo); - - expect(result.fromHeight).to.be.equal(3); - expect(result.toHeight).to.be.equal(4); - expect(result.createdEntities).to.have.lengthOf(0); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(1); - - await expectDeterministicAppHash('ea28d7339efd80984e53bd06b0d3708611f24862f401997e9cd69328af6a54c2'); - - // Masternode identity should stay - - await expectMasternodeIdentity( - smlFixture[0], - transaction1, - undefined, - Address.fromString(smlFixture[0].payoutAddress), - ); - - // Voting identity should stay - - await expectVotingIdentity( - smlFixture[0], - transaction1, - ); - - // Operator identity should stay - - await expectOperatorIdentity(smlFixture[0]); - - // Masternode reward shares should be removed - - const removedMasternodeIdentifier = Buffer.from(smlFixture[0].proRegTxHash, 'hex'); - - const documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', removedMasternodeIdentifier], - ], - useTransaction: true, - }, - ); - - const documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(0); - }); - - it('should remove reward shares if masternode is not valid', async () => { - // Sync initial list - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - await expectDeterministicAppHash(firstSyncAppHash); - - // Mock SML - - const invalidSmlEntry = smlFixture[0].copy(); - invalidSmlEntry.isValid = false; - - smlStoreMock.getSMLbyHeight.withArgs(coreHeight + 1).returns( - { mnList: [smlFixture[1], invalidSmlEntry] }, - ); - - // Second call - - const result = await synchronizeMasternodeIdentities(coreHeight + 1, blockInfo); - - expect(result.fromHeight).to.be.equal(3); - expect(result.toHeight).to.be.equal(4); - expect(result.createdEntities).to.have.lengthOf(0); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(1); - - await expectDeterministicAppHash('ea28d7339efd80984e53bd06b0d3708611f24862f401997e9cd69328af6a54c2'); - - const invalidMasternodeIdentifier = Identifier.from( - Buffer.from(invalidSmlEntry.proRegTxHash, 'hex'), - ); - - // Masternode reward shares should be removed - - const documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', invalidMasternodeIdentifier], - ], - useTransaction: true, - }, - ); - - const documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(0); - }); - - it('should create operator identity and reward shares if PubKeyOperator was changed', async () => { - // Initial sync - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - await expectDeterministicAppHash(firstSyncAppHash); - - // Mock SML - - const changedSmlEntry = smlFixture[0].copy(); - changedSmlEntry.pubKeyOperator = '96f83eedc8a7b87663e591987f051ce341a6fb88989322c64bbbf56d205e4e77d2cb7d839d8b4106a8a1f5d5cf7cfa57'; - - smlStoreMock.getSMLbyHeight.withArgs(coreHeight + 1).returns( - { mnList: [smlFixture[1], changedSmlEntry] }, - ); - - // Second call - - const result = await synchronizeMasternodeIdentities(coreHeight + 1, blockInfo); - - expect(result.fromHeight).to.be.equal(3); - expect(result.toHeight).to.be.equal(4); - expect(result.createdEntities).to.have.lengthOf(2); - expect(result.updatedEntities).to.have.lengthOf(1); - expect(result.removedEntities).to.have.lengthOf(1); - - await expectDeterministicAppHash('d80a3bbf5e699a0295e4ba734e3729d12bef3001bdd9cdd295673832d05454cf'); - - // Masternode identity should stay - - await expectMasternodeIdentity( - smlFixture[0], - transaction1, - undefined, - Address.fromString(smlFixture[0].payoutAddress), - ); - - // Previous voting identity should stay - - await expectVotingIdentity( - smlFixture[0], - transaction1, - ); - - // Previous operator identity should stay - - await expectOperatorIdentity(smlFixture[0]); - - // New operator identity should be created - - await expectOperatorIdentity(changedSmlEntry); - - // Only new masternode reward shares should exist - - const changedMasternodeIdentifier = Identifier.from( - Buffer.from(changedSmlEntry.proRegTxHash, 'hex'), - ); - - const documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', changedMasternodeIdentifier], - ], - useTransaction: true, - }, - ); - - const documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(1); - - const [document] = documents; - - const newOperatorIdentifier = createOperatorIdentifier(changedSmlEntry); - - expect(document.get('payToId')).to.deep.equal(newOperatorIdentifier); - }); - - it('should handle changed payout, voting and operator payout addresses', async () => { - // Sync initial list - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - - await expectDeterministicAppHash(firstSyncAppHash); - - // Mock SML - - const changedSmlEntry = smlFixture[0].copy(); - changedSmlEntry.payoutAddress = 'yMLrhooXyJtpV3R2ncsxvkrh6wRennNPoG'; - changedSmlEntry.operatorPayoutAddress = 'yT8DDY5NkX4ZtBkUVz7y1RgzbakCnMPogh'; - - smlStoreMock.getSMLbyHeight.withArgs(coreHeight + 1).returns( - { mnList: [smlFixture[1], changedSmlEntry] }, - ); - - // Second call - - await synchronizeMasternodeIdentities(coreHeight + 1, blockInfo); - - await expectDeterministicAppHash('cfc8c439d00c2afab01594dc699ef71c8b23cff66b0302794d3c6b88c44d687c'); - - // Masternode identity should contain new public key - - await expectMasternodeIdentity( - smlFixture[0], - transaction1, - Address.fromString(smlFixture[0].payoutAddress), - Address.fromString(changedSmlEntry.payoutAddress), - ); - - // Previous voting identity should stay - - await expectVotingIdentity( - smlFixture[0], - transaction1, - ); - - // Previous operator identity should stay - - await expectOperatorIdentity( - smlFixture[0], - undefined, - Address.fromString(changedSmlEntry.operatorPayoutAddress), - ); - - // New operator identity should be created - - await expectOperatorIdentity( - changedSmlEntry, - undefined, - Address.fromString(changedSmlEntry.operatorPayoutAddress), - ); - - // new voting Identity should exist - await expectVotingIdentity( - changedSmlEntry, - transaction1, - ); - - // Only new masternode reward shares should exist - - const changedMasternodeIdentifier = Identifier.from( - Buffer.from(changedSmlEntry.proRegTxHash, 'hex'), - ); - - const documentsResult = await documentRepository.find( - rewardsDataContract, - 'rewardShare', - { - where: [ - ['$ownerId', '==', changedMasternodeIdentifier], - ], - useTransaction: true, - }, - ); - - const documents = documentsResult.getValue(); - - expect(documents).to.have.lengthOf(1); - - const [document] = documents; - - const newOperatorIdentifier = createOperatorIdentifier(changedSmlEntry); - - expect(document.get('payToId')).to.deep.equal(newOperatorIdentifier); - }); - - it('should not create voting Identity if owner and voting keys are the same', async () => { - transaction1 = { - extraPayload: { - operatorReward: 100, - keyIDOwner: Buffer.alloc(20).fill('a').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('a').toString('hex'), - }, - }; - - fetchTransactionMock.withArgs('a2c9b34ef525271d84f70a0d4d2c107e8a2f81cd4d8256dc7b3911ed253d5611').resolves(transaction1); - - // Initial sync - - await synchronizeMasternodeIdentities(coreHeight, blockInfo); - await expectDeterministicAppHash('7a5729e3511c5cc98e8452faa6132f0d600e04fef85df0f95f56e59c776de170'); - const votingIdentifier = createVotingIdentifier(smlFixture[0]); - - const votingIdentityResult = await identityRepository.fetch( - votingIdentifier, - { useTransaction: true }, - ); - - expect(votingIdentityResult.isNull()).to.be.true(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/closeAbciServerFactory.spec.js b/packages/js-drive/test/unit/abci/closeAbciServerFactory.spec.js deleted file mode 100644 index 37f0f6b4d0e..00000000000 --- a/packages/js-drive/test/unit/abci/closeAbciServerFactory.spec.js +++ /dev/null @@ -1,29 +0,0 @@ -const closeAbciServerFactory = require('../../../lib/abci/closeAbciServerFactory'); - -describe('closeAbciServerFactory', () => { - let closeAbciServer; - let abciServerMock; - - beforeEach(function beforeEach() { - abciServerMock = { - close: this.sinon.spy((resolve) => { - resolve(); - }), - listening: true, - }; - - closeAbciServer = closeAbciServerFactory(abciServerMock); - }); - - it('should close server if it\'s listening', async () => { - await closeAbciServer(); - - expect(abciServerMock.close).to.be.calledOnce(); - }); - - it('should not close server if not listening', async () => { - abciServerMock.listening = false; - - expect(abciServerMock.close).to.not.be.called(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/errors/enrichErrorWithContextLoggerFactory.spec.js b/packages/js-drive/test/unit/abci/errors/enrichErrorWithContextLoggerFactory.spec.js deleted file mode 100644 index d182a4caf3b..00000000000 --- a/packages/js-drive/test/unit/abci/errors/enrichErrorWithContextLoggerFactory.spec.js +++ /dev/null @@ -1,38 +0,0 @@ -const { AsyncLocalStorage } = require('node:async_hooks'); -const enrichErrorWithContextLoggerFactory = require('../../../../lib/abci/errors/enrichErrorWithContextLoggerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); - -describe('enrichErrorWithContextLoggerFactory', () => { - let enrichErrorWithContextLogger; - let loggerMock; - let asyncLocalStorage; - - beforeEach(function beforeEach() { - loggerMock = new LoggerMock(this.sinon); - - asyncLocalStorage = new AsyncLocalStorage(); - - enrichErrorWithContextLogger = enrichErrorWithContextLoggerFactory(asyncLocalStorage); - }); - - it('should add contextLogger from BlockExecutionContext to thrown error', async () => { - const error = new Error('my error'); - - const method = async () => { - asyncLocalStorage.getStore().set('logger', loggerMock); - - throw error; - }; - - const methodHandler = enrichErrorWithContextLogger(method); - - try { - await methodHandler(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.equal(error); - expect(e.contextLogger).to.equal(loggerMock); - } - }); -}); diff --git a/packages/js-drive/test/unit/abci/errors/wrapInErrorHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/errors/wrapInErrorHandlerFactory.spec.js deleted file mode 100644 index cfda8a6f1d8..00000000000 --- a/packages/js-drive/test/unit/abci/errors/wrapInErrorHandlerFactory.spec.js +++ /dev/null @@ -1,109 +0,0 @@ -const SomeConsensusError = require('@dashevo/dpp/lib/test/mocks/SomeConsensusError'); -const wrapInErrorHandlerFactory = require('../../../../lib/abci/errors/wrapInErrorHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const InternalAbciError = require('../../../../lib/abci/errors/InternalAbciError'); -const InvalidArgumentAbciError = require('../../../../lib/abci/errors/InvalidArgumentAbciError'); -const VerboseInternalAbciError = require('../../../../lib/abci/errors/VerboseInternalAbciError'); -const DPPValidationAbciError = require('../../../../lib/abci/errors/DPPValidationAbciError'); - -describe('wrapInErrorHandlerFactory', () => { - let loggerMock; - let methodMock; - let request; - let handler; - let wrapInErrorHandler; - - beforeEach(function beforeEach() { - request = { - tx: Buffer.alloc(0), - }; - - loggerMock = new LoggerMock(this.sinon); - - wrapInErrorHandler = wrapInErrorHandlerFactory(loggerMock, true); - methodMock = this.sinon.stub(); - - handler = wrapInErrorHandler( - methodMock, - ); - }); - - it('should respond with internal error code if any Error is thrown in handler and respondWithInternalError enabled', async () => { - handler = wrapInErrorHandler( - methodMock, { respondWithInternalError: true }, - ); - - const error = new Error('Custom error'); - - methodMock.throws(error); - - const response = await handler(request); - - const expectedError = new InternalAbciError(error); - - expect(response).to.deep.equal(expectedError.getAbciResponse()); - }); - - it('should respond with internal error code if an InternalAbciError is thrown in handler and respondWithInternalError enabled', async () => { - handler = wrapInErrorHandler( - methodMock, { respondWithInternalError: true }, - ); - - const data = { sample: 'data' }; - const error = new InternalAbciError(new Error(), data); - - methodMock.throws(error); - - const response = await handler(request); - - expect(response).to.deep.equal(error.getAbciResponse()); - }); - - it('should respond with invalid argument error if it is thrown in handler', async () => { - const data = { sample: 'data' }; - const error = new InvalidArgumentAbciError('test', data); - - methodMock.throws(error); - - const response = await handler(request); - - expect(response).to.deep.equal(error.getAbciResponse()); - }); - - it('should respond with verbose error containing message and stack in debug mode', async () => { - wrapInErrorHandler = wrapInErrorHandlerFactory(loggerMock, false); - - const error = new Error('Custom error'); - - methodMock.throws(error); - - handler = wrapInErrorHandler( - methodMock, { respondWithInternalError: true }, - ); - - const response = await handler(request); - - const expectedError = new VerboseInternalAbciError( - new InternalAbciError(error), - ); - - expect(response).to.deep.equal(expectedError.getAbciResponse()); - }); - - it('should respond with error if method throws DPPValidationAbciError', async () => { - const dppValidationError = new DPPValidationAbciError( - 'Some error', - new SomeConsensusError('Consensus error'), - ); - - methodMock.throws(dppValidationError); - - handler = wrapInErrorHandler( - methodMock, { respondWithInternalError: true }, - ); - - const response = await handler(request); - - expect(response).to.deep.equal(dppValidationError.getAbciResponse()); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/checkTxHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/checkTxHandlerFactory.spec.js deleted file mode 100644 index fd4a5621278..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/checkTxHandlerFactory.spec.js +++ /dev/null @@ -1,54 +0,0 @@ -const { - tendermint: { - abci: { - ResponseCheckTx, - }, - }, -} = require('@dashevo/abci/types'); - -const getIdentityCreateTransitionFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityCreateTransitionFixture'); - -const checkTxHandlerFactory = require('../../../../lib/abci/handlers/checkTxHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); - -describe('checkTxHandlerFactory', () => { - let checkTxHandler; - let request; - let stateTransitionFixture; - let unserializeStateTransitionMock; - let loggerMock; - let createContextLoggerMock; - - beforeEach(function beforeEach() { - stateTransitionFixture = getIdentityCreateTransitionFixture(); - - request = { - tx: stateTransitionFixture.toBuffer(), - }; - - unserializeStateTransitionMock = this.sinon.stub() - .resolves(stateTransitionFixture); - - loggerMock = new LoggerMock(this.sinon); - createContextLoggerMock = this.sinon.stub(); - - checkTxHandler = checkTxHandlerFactory( - unserializeStateTransitionMock, - createContextLoggerMock, - loggerMock, - ); - }); - - it('should validate a State Transition and return response', async () => { - const response = await checkTxHandler(request); - - expect(response).to.be.an.instanceOf(ResponseCheckTx); - expect(response.code).to.equal(0); - - expect(unserializeStateTransitionMock).to.be.calledOnceWith(request.tx); - - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - abciMethod: 'checkTx', - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/extendVoteHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/extendVoteHandlerFactory.spec.js deleted file mode 100644 index 3d646e40a31..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/extendVoteHandlerFactory.spec.js +++ /dev/null @@ -1,68 +0,0 @@ -const { - tendermint: { - abci: { - ResponseExtendVote, - }, - }, -} = require('@dashevo/abci/types'); - -const { hash } = require('@dashevo/dpp/lib/util/hash'); - -const extendVoteHandlerFactory = require('../../../../lib/abci/handlers/extendVoteHandlerFactory'); - -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); - -describe('extendVoteHandlerFactory', () => { - let extendVoteHandler; - let blockExecutionContextMock; - let createContextLoggerMock; - let loggerMock; - - beforeEach(function beforeEach() { - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - loggerMock = new LoggerMock(this.sinon); - - blockExecutionContextMock.getContextLogger.returns(loggerMock); - - blockExecutionContextMock.getWithdrawalTransactionsMap.returns({}); - - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - extendVoteHandler = extendVoteHandlerFactory( - blockExecutionContextMock, - createContextLoggerMock, - ); - }); - - it('should return ResponseExtendVote with vote extensions if withdrawal transactions are present', async () => { - const [txOneBytes, txTwoBytes] = [ - Buffer.alloc(32, 0), - Buffer.alloc(32, 1), - ]; - - blockExecutionContextMock.getWithdrawalTransactionsMap.returns({ - [hash(txOneBytes).toString('hex')]: txOneBytes, - [hash(txTwoBytes).toString('hex')]: txTwoBytes, - }); - - const result = await extendVoteHandler(); - - expect(result).to.be.an.instanceOf(ResponseExtendVote); - expect(result.voteExtensions).to.deep.equal([ - { - type: 1, - extension: hash(txOneBytes), - }, - { - type: 1, - extension: hash(txTwoBytes), - }, - ]); - - expect(createContextLoggerMock).to.be.calledOnceWith(loggerMock, { - abciMethod: 'extendVote', - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/finalizeBlockHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/finalizeBlockHandlerFactory.spec.js deleted file mode 100644 index fe254bd9555..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/finalizeBlockHandlerFactory.spec.js +++ /dev/null @@ -1,217 +0,0 @@ -const { - tendermint: { - abci: { - ResponseFinalizeBlock, - RequestProcessProposal, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const { hash } = require('@dashevo/dpp/lib/util/hash'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const finalizeBlockHandlerFactory = require('../../../../lib/abci/handlers/finalizeBlockHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); -const GroveDBStoreMock = require('../../../../lib/test/mock/GroveDBStoreMock'); -const BlockExecutionContextRepositoryMock = require('../../../../lib/test/mock/BlockExecutionContextRepositoryMock'); - -describe('finalizeBlockHandlerFactory', () => { - let finalizeBlockHandler; - let executionTimerMock; - let latestBlockExecutionContextMock; - let loggerMock; - let requestMock; - let appHash; - let groveDBStoreMock; - let blockExecutionContextRepositoryMock; - let dataContract; - let proposalBlockExecutionContextMock; - let round; - let block; - let processProposalMock; - let broadcastWithdrawalTransactions; - let createContextLoggerMock; - - beforeEach(function beforeEach() { - round = 0; - appHash = Buffer.alloc(0); - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - latestBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - loggerMock = new LoggerMock(this.sinon); - executionTimerMock = { - clearTimer: this.sinon.stub(), - startTimer: this.sinon.stub(), - stopTimer: this.sinon.stub(), - }; - - const commit = {}; - - const height = new Long(42); - - const time = { - seconds: Math.ceil(new Date().getTime() / 1000), - }; - - const coreChainLockedHeight = 10; - - block = { - header: { - time, - version: { - app: Long.fromInt(1), - }, - proposerProTxHash: Uint8Array.from([1, 2, 3, 4]), - coreChainLockedHeight, - }, - data: { - txs: new Array(3).fill(Buffer.alloc(5, 0)), - }, - }; - - requestMock = { - commit, - height, - time, - coreChainLockedHeight, - round, - block, - }; - - dataContract = getDataContractFixture(); - - proposalBlockExecutionContextMock.getHeight.returns(new Long(42)); - proposalBlockExecutionContextMock.getRound.returns(round); - proposalBlockExecutionContextMock.getDataContracts.returns([dataContract]); - proposalBlockExecutionContextMock.getEpochInfo.returns({ - currentEpochIndex: 1, - }); - proposalBlockExecutionContextMock.getTimeMs.returns((new Date()).getTime()); - - groveDBStoreMock = new GroveDBStoreMock(this.sinon); - groveDBStoreMock.getRootHash.resolves(appHash); - - blockExecutionContextRepositoryMock = new BlockExecutionContextRepositoryMock( - this.sinon, - ); - - processProposalMock = this.sinon.stub(); - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - broadcastWithdrawalTransactions = this.sinon.stub(); - - finalizeBlockHandler = finalizeBlockHandlerFactory( - groveDBStoreMock, - blockExecutionContextRepositoryMock, - loggerMock, - executionTimerMock, - latestBlockExecutionContextMock, - proposalBlockExecutionContextMock, - processProposalMock, - broadcastWithdrawalTransactions, - createContextLoggerMock, - ); - }); - - it('should commit db transactions, create document dbs and return ResponseFinalizeBlock', async () => { - const result = await finalizeBlockHandler(requestMock); - - expect(result).to.be.an.instanceOf(ResponseFinalizeBlock); - - expect(executionTimerMock.stopTimer).to.be.calledOnceWithExactly('blockExecution'); - - expect(proposalBlockExecutionContextMock.reset).to.be.calledOnce(); - - expect(blockExecutionContextRepositoryMock.store).to.be.calledOnceWithExactly( - proposalBlockExecutionContextMock, - { - useTransaction: true, - }, - ); - - expect(groveDBStoreMock.commitTransaction).to.be.calledOnceWithExactly(); - - expect(latestBlockExecutionContextMock.populate).to.be.calledOnce(); - expect(processProposalMock).to.be.not.called(); - - expect(broadcastWithdrawalTransactions).to.have.been.calledOnceWith( - proposalBlockExecutionContextMock, - undefined, - undefined, - ); - - expect(createContextLoggerMock).to.be.calledOnceWithExactly( - loggerMock, { - height: '42', - round, - abciMethod: 'finalizeBlock', - }, - ); - }); - - it('should send withdrawal transaction if vote extensions are present', async () => { - const [txOneBytes, txTwoBytes] = [ - Buffer.alloc(32, 0), - Buffer.alloc(32, 1), - ]; - - proposalBlockExecutionContextMock.getWithdrawalTransactionsMap.returns({ - [hash(txOneBytes).toString('hex')]: txOneBytes, - [hash(txTwoBytes).toString('hex')]: txTwoBytes, - }); - - const thresholdVoteExtensions = [ - { - extension: hash(txOneBytes), - signature: Buffer.alloc(96, 3), - }, - { - extension: hash(txTwoBytes), - signature: Buffer.alloc(96, 4), - }, - ]; - - requestMock.commit = { thresholdVoteExtensions }; - - await finalizeBlockHandler(requestMock); - - expect(processProposalMock).to.be.not.called(); - expect(createContextLoggerMock).to.be.calledOnceWithExactly( - loggerMock, { - height: '42', - round, - abciMethod: 'finalizeBlock', - }, - ); - }); - - it('should call processProposal if round is not equal to execution context', async () => { - proposalBlockExecutionContextMock.getRound.returns(round + 1); - - const result = await finalizeBlockHandler(requestMock); - - expect(result).to.be.an.instanceOf(ResponseFinalizeBlock); - - const processProposalRequest = new RequestProcessProposal({ - height: requestMock.height, - txs: block.data.txs, - coreChainLockedHeight: block.header.coreChainLockedHeight, - version: block.header.version, - proposedLastCommit: requestMock.commit, - time: block.header.time, - proposerProTxHash: block.header.proposerProTxHash, - round, - }); - - expect(processProposalMock).to.be.calledOnceWithExactly(processProposalRequest, loggerMock); - expect(createContextLoggerMock).to.be.calledOnceWithExactly( - loggerMock, { - height: '42', - round, - abciMethod: 'finalizeBlock', - }, - ); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/infoHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/infoHandlerFactory.spec.js deleted file mode 100644 index c97411142b7..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/infoHandlerFactory.spec.js +++ /dev/null @@ -1,129 +0,0 @@ -const Long = require('long'); - -const { - tendermint: { - abci: { - ResponseInfo, - }, - }, -} = require('@dashevo/abci/types'); - -const infoHandlerFactory = require('../../../../lib/abci/handlers/infoHandlerFactory'); - -const packageJson = require('../../../../package.json'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); - -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); -const GroveDBStoreMock = require('../../../../lib/test/mock/GroveDBStoreMock'); -const BlockExecutionContextRepositoryMock = require('../../../../lib/test/mock/BlockExecutionContextRepositoryMock'); - -describe('infoHandlerFactory', () => { - let protocolVersion; - let lastBlockHeight; - let lastBlockAppHash; - let infoHandler; - let updateSimplifiedMasternodeListMock; - let lastCoreChainLockedHeight; - let loggerMock; - let blockExecutionContextMock; - let blockExecutionContextRepositoryMock; - let groveDBStoreMock; - let createContextLoggerMock; - - beforeEach(function beforeEach() { - lastBlockHeight = Long.fromInt(0); - lastBlockAppHash = Buffer.alloc(0); - protocolVersion = Long.fromInt(1); - lastCoreChainLockedHeight = 0; - - updateSimplifiedMasternodeListMock = this.sinon.stub(); - - loggerMock = new LoggerMock(this.sinon); - - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - blockExecutionContextMock.getHeight.returns(lastBlockHeight); - blockExecutionContextMock.getCoreChainLockedHeight.returns(lastCoreChainLockedHeight); - blockExecutionContextRepositoryMock = new BlockExecutionContextRepositoryMock( - this.sinon, - ); - groveDBStoreMock = new GroveDBStoreMock(this.sinon); - - blockExecutionContextRepositoryMock.fetch.resolves(blockExecutionContextMock); - - groveDBStoreMock.getRootHash.resolves(lastBlockAppHash); - - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - infoHandler = infoHandlerFactory( - blockExecutionContextMock, - blockExecutionContextRepositoryMock, - protocolVersion, - updateSimplifiedMasternodeListMock, - loggerMock, - groveDBStoreMock, - createContextLoggerMock, - ); - }); - - it('should return respond with genesis heights and app hash on the first run', async () => { - blockExecutionContextRepositoryMock.fetch.resolves(blockExecutionContextMock); - blockExecutionContextMock.getHeight.returns(null); - blockExecutionContextMock.isEmpty.returns(true); - - const response = await infoHandler(); - - expect(response).to.be.an.instanceOf(ResponseInfo); - - expect(response).to.deep.include({ - version: packageJson.version, - appVersion: protocolVersion, - lastBlockHeight, - lastBlockAppHash, - }); - - expect(blockExecutionContextRepositoryMock.fetch).to.be.calledOnce(); - expect(blockExecutionContextMock.populate).to.not.be.called(); - expect(blockExecutionContextMock.getHeight).to.not.be.called(); - expect(blockExecutionContextMock.getCoreChainLockedHeight).to.not.be.called(); - expect(updateSimplifiedMasternodeListMock).to.not.be.called(); - expect(groveDBStoreMock.getRootHash).to.be.calledOnce(); - expect(createContextLoggerMock).to.be.calledOnceWithExactly( - loggerMock, { - abciMethod: 'info', - }, - ); - }); - - it('should populate context and update SML on subsequent runs', async () => { - const response = await infoHandler(); - - expect(response).to.be.an.instanceOf(ResponseInfo); - - expect(ResponseInfo.toObject(response)).to.deep.equal({ - version: packageJson.version, - appVersion: protocolVersion, - lastBlockHeight, - lastBlockAppHash, - }); - - expect(blockExecutionContextMock.getHeight).to.be.calledOnce(); - - expect(updateSimplifiedMasternodeListMock).to.be.calledOnceWithExactly( - lastCoreChainLockedHeight, - { - logger: loggerMock, - }, - ); - expect(createContextLoggerMock).to.be.calledTwice(); - expect(createContextLoggerMock.getCall(0)).to.be.calledWithExactly( - loggerMock, { - abciMethod: 'info', - }, - ); - expect(createContextLoggerMock.getCall(1)).to.be.calledWithExactly( - loggerMock, { - height: lastBlockHeight.toString(), - }, - ); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/initChainHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/initChainHandlerFactory.spec.js deleted file mode 100644 index 99c3807aea8..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/initChainHandlerFactory.spec.js +++ /dev/null @@ -1,164 +0,0 @@ -const Long = require('long'); - -const { - tendermint: { - abci: { - ResponseInitChain, - ValidatorSetUpdate, - }, - types: { - CoreChainLock, - }, - }, -} = require('@dashevo/abci/types'); - -const initChainHandlerFactory = require('../../../../lib/abci/handlers/initChainHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const GroveDBStoreMock = require('../../../../lib/test/mock/GroveDBStoreMock'); -const millisToProtoTimestamp = require('../../../../lib/util/millisToProtoTimestamp'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); -const getSystemIdentityPublicKeysFixture = require('../../../../lib/test/fixtures/getSystemIdentityPublicKeysFixture'); -const protoTimestampToMillis = require('../../../../lib/util/protoTimestampToMillis'); - -describe('initChainHandlerFactory', () => { - let initChainHandler; - let updateSimplifiedMasternodeListMock; - let initialCoreChainLockedHeight; - let validatorSetMock; - let createValidatorSetUpdateMock; - let loggerMock; - let validatorSetUpdate; - let synchronizeMasternodeIdentitiesMock; - let groveDBStoreMock; - let appHashFixture; - let rsAbciMock; - let createCoreChainLockUpdateMock; - let coreChainLockUpdate; - let createContextLoggerMock; - let genesisTimeMs; - let systemIdentityPublicKeysFixture; - - beforeEach(function beforeEach() { - initialCoreChainLockedHeight = 1; - - appHashFixture = Buffer.alloc(0); - - genesisTimeMs = Date.now(); - - updateSimplifiedMasternodeListMock = this.sinon.stub(); - - const quorumHash = Buffer.alloc(64).fill(1).toString('hex'); - validatorSetMock = { - initialize: this.sinon.stub(), - getQuorum: this.sinon.stub().returns({ - quorumHash, - }), - }; - - validatorSetUpdate = new ValidatorSetUpdate(); - - createValidatorSetUpdateMock = this.sinon.stub().returns(validatorSetUpdate); - synchronizeMasternodeIdentitiesMock = this.sinon.stub().resolves({ - createdEntities: [], - updatedEntities: [], - removedEntities: [], - fromHeight: 1, - toHeight: 42, - }); - - loggerMock = new LoggerMock(this.sinon); - - rsAbciMock = { - initChain: this.sinon.stub(), - }; - - groveDBStoreMock = new GroveDBStoreMock(this.sinon); - groveDBStoreMock.getRootHash.resolves(appHashFixture); - - coreChainLockUpdate = new CoreChainLock({ - coreBlockHeight: 42, - coreBlockHash: '1528e523f4c20fa84ba70dd96372d34e00ce260f357d53ad1a8bc892ebf20e2d', - signature: '1897ce8f54d2070f44ca5c29983b68b391e8137c25e44f67416e579f3e3bdfef7b4fd22db7818399147e52907998857b0fbc8edfdc40a64f2c7df0e88544d31d12ca8c15e73d50dda25ca23f754ed3f789ed4bcb392161995f464017c10df404', - }); - - createCoreChainLockUpdateMock = this.sinon.stub().resolves(coreChainLockUpdate); - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - systemIdentityPublicKeysFixture = getSystemIdentityPublicKeysFixture(); - - initChainHandler = initChainHandlerFactory( - updateSimplifiedMasternodeListMock, - initialCoreChainLockedHeight, - validatorSetMock, - createValidatorSetUpdateMock, - synchronizeMasternodeIdentitiesMock, - loggerMock, - groveDBStoreMock, - rsAbciMock, - createCoreChainLockUpdateMock, - createContextLoggerMock, - systemIdentityPublicKeysFixture, - ); - }); - - it('should initialize the chain', async () => { - const request = { - initialHeight: Long.fromInt(1), - chainId: 'test', - time: millisToProtoTimestamp(genesisTimeMs), - }; - - const blockInfo = new BlockInfo(0, 0, protoTimestampToMillis(request.time)); - - const response = await initChainHandler(request); - - expect(response).to.be.an.instanceOf(ResponseInitChain); - expect(response.validatorSetUpdate).to.be.equal(validatorSetUpdate); - expect(response.initialCoreHeight).to.be.equal(initialCoreChainLockedHeight); - expect(response.appHash).to.deep.equal(appHashFixture); - - // Update SML - - expect(updateSimplifiedMasternodeListMock).to.be.calledOnceWithExactly( - initialCoreChainLockedHeight, - { - logger: loggerMock, - }, - ); - - // Create initial state - - expect(groveDBStoreMock.startTransaction).to.be.calledOnce(); - - expect(rsAbciMock.initChain).to.be.calledOnceWithExactly({ - genesisTimeMs: protoTimestampToMillis(request.time), - systemIdentityPublicKeys: systemIdentityPublicKeysFixture, - }, true); - - expect(synchronizeMasternodeIdentitiesMock).to.be.calledOnceWithExactly( - initialCoreChainLockedHeight, - blockInfo, - ); - - expect(groveDBStoreMock.commitTransaction).to.be.calledOnce(); - - expect(groveDBStoreMock.getRootHash).to.be.calledOnce(); - - // Initialize VS - - expect(validatorSetMock.initialize).to.be.calledOnceWithExactly( - initialCoreChainLockedHeight, - ); - - expect(validatorSetMock.getQuorum).to.be.calledOnce(); - - expect(createValidatorSetUpdateMock).to.be.calledOnceWithExactly(validatorSetMock); - - expect(createCoreChainLockUpdateMock) - .to.be.calledOnceWithExactly(initialCoreChainLockedHeight, 0, loggerMock); - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - height: request.initialHeight.toString(), - abciMethod: 'initChain', - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/prepareProposalHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/prepareProposalHandlerFactory.spec.js deleted file mode 100644 index 61b9a4bf56a..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/prepareProposalHandlerFactory.spec.js +++ /dev/null @@ -1,232 +0,0 @@ -const { - tendermint: { - abci: { - ResponsePrepareProposal, - ValidatorSetUpdate, - }, - types: { - ConsensusParams, - CoreChainLock, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const prepareProposalHandlerFactory = require('../../../../lib/abci/handlers/prepareProposalHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); - -describe('prepareProposalHandlerFactory', () => { - let prepareProposalHandler; - let request; - let deliverTxMock; - let loggerMock; - let beginBlockMock; - let endBlockMock; - let updateCoreChainLockMock; - let appHash; - let consensusParamUpdates; - let validatorSetUpdate; - let coreChainLockUpdate; - let endBlockResult; - let proposalBlockExecutionContextMock; - let round; - let executionTimerMock; - let createContextLoggerMock; - let quorumHash; - - beforeEach(function beforeEach() { - round = 1; - appHash = Buffer.alloc(1, 1); - coreChainLockUpdate = new CoreChainLock({ - coreBlockHeight: 42, - coreBlockHash: '1528e523f4c20fa84ba70dd96372d34e00ce260f357d53ad1a8bc892ebf20e2d', - signature: '1897ce8f54d2070f44ca5c29983b68b391e8137c25e44f67416e579f3e3bdfef7b4fd22db7818399147e52907998857b0fbc8edfdc40a64f2c7df0e88544d31d12ca8c15e73d50dda25ca23f754ed3f789ed4bcb392161995f464017c10df404', - }); - - consensusParamUpdates = new ConsensusParams({ - block: { - maxBytes: 1, - maxGas: 2, - }, - evidence: { - maxAgeDuration: null, - maxAgeNumBlocks: 1, - maxBytes: 2, - }, - version: { - appVersion: 1, - }, - }); - - validatorSetUpdate = new ValidatorSetUpdate(); - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - loggerMock = new LoggerMock(this.sinon); - - endBlockResult = { - consensusParamUpdates, - appHash, - validatorSetUpdate, - }; - - beginBlockMock = this.sinon.stub(); - - deliverTxMock = this.sinon.stub().resolves({ - code: 0, - fees: { - processingFee: 10, - storageFee: 100, - refundsPerEpoch: { - 1: 15, - }, - }, - }); - - endBlockMock = this.sinon.stub().resolves( - endBlockResult, - ); - - updateCoreChainLockMock = this.sinon.stub().resolves(coreChainLockUpdate); - - executionTimerMock = { - getTimer: this.sinon.stub().returns(0.1), - }; - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - prepareProposalHandler = prepareProposalHandlerFactory( - deliverTxMock, - loggerMock, - proposalBlockExecutionContextMock, - beginBlockMock, - endBlockMock, - updateCoreChainLockMock, - executionTimerMock, - createContextLoggerMock, - ); - - const maxTxBytes = 42; - const txs = new Array(3).fill(Buffer.alloc(5, 0)); - - const height = new Long(42); - - const time = { - seconds: Math.ceil(new Date().getTime() / 1000), - }; - - const version = { - app: Long.fromInt(1), - }; - - const proposerProTxHash = Uint8Array.from([1, 2, 3, 4]); - - const proposedAppVersion = Long.fromInt(1); - - const coreChainLockedHeight = 10; - - const localLastCommit = {}; - - quorumHash = Buffer.alloc(32, 0); - - request = { - height, - maxTxBytes, - txs, - coreChainLockedHeight, - version, - localLastCommit, - time, - proposerProTxHash, - proposedAppVersion, - round, - quorumHash, - }; - }); - - it('should return proposal', async () => { - const result = await prepareProposalHandler(request); - - expect(result).to.be.an.instanceOf(ResponsePrepareProposal); - - const txRecords = request.txs.map((tx) => ({ - tx, - action: 1, - })); - - expect(result).to.be.an.instanceOf(ResponsePrepareProposal); - expect(result.appHash).to.be.equal(appHash); - expect(result.txResults).to.be.deep.equal(new Array(3).fill({ code: 0 })); - expect(result.consensusParamUpdates).to.be.equal(consensusParamUpdates); - expect(result.validatorSetUpdate).to.be.equal(validatorSetUpdate); - expect(result.coreChainLockUpdate).to.be.equal(coreChainLockUpdate); - expect(result.txRecords).to.be.deep.equal(txRecords); - - expect(beginBlockMock).to.be.calledOnceWithExactly( - { - lastCommitInfo: request.localLastCommit, - height: request.height, - coreChainLockedHeight: request.coreChainLockedHeight, - version: request.version, - time: request.time, - proposerProTxHash: Buffer.from(request.proposerProTxHash), - proposedAppVersion: request.proposedAppVersion, - round, - quorumHash, - }, - loggerMock, - ); - - expect(deliverTxMock).to.be.calledThrice(); - - expect(updateCoreChainLockMock).to.be.calledOnceWithExactly( - request.coreChainLockedHeight, - round, - loggerMock, - ); - - expect(endBlockMock).to.be.calledOnceWithExactly( - { - height: request.height, - round, - fees: { - processingFee: 10 * 3, - storageFee: 100 * 3, - refundsPerEpoch: { - 1: 15 * 3, - }, - }, - coreChainLockedHeight: request.coreChainLockedHeight, - }, - loggerMock, - ); - - expect(proposalBlockExecutionContextMock.setPrepareProposalResult).to.be.calledOnceWithExactly({ - appHash, - txResults: new Array(3).fill({ code: 0 }), - consensusParamUpdates, - validatorSetUpdate, - }); - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - height: '42', - round, - abciMethod: 'prepareProposal', - }); - }); - - it('should cut txs that are not fit into the size limit', async () => { - request.maxTxBytes = 9; - - const result = await prepareProposalHandler(request); - - expect(result).to.be.an.instanceOf(ResponsePrepareProposal); - expect(result.txRecords).to.have.lengthOf(1); - expect(result.txRecords).to.deep.equal( - [{ - tx: request.txs[0], - action: 1, - }], - ); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/processProposalHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/processProposalHandlerFactory.spec.js deleted file mode 100644 index ccb4b0deb5f..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/processProposalHandlerFactory.spec.js +++ /dev/null @@ -1,160 +0,0 @@ -const { - tendermint: { - abci: { - ResponseProcessProposal, - ValidatorSetUpdate, - }, - types: { - ConsensusParams, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const processProposalHandlerFactory = require('../../../../lib/abci/handlers/processProposalHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); - -describe('processProposalHandlerFactory', () => { - let processProposalHandler; - let request; - let loggerMock; - let verifyChainLockMock; - let coreChainLockUpdate; - let processProposalMock; - let round; - let appHash; - let proposalBlockExecutionContextMock; - let consensusParamUpdates; - let validatorSetUpdate; - let createContextLoggerMock; - - beforeEach(function beforeEach() { - round = 0; - - appHash = Buffer.alloc(1, 1); - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - consensusParamUpdates = new ConsensusParams({ - block: { - maxBytes: 1, - maxGas: 2, - }, - evidence: { - maxAgeDuration: null, - maxAgeNumBlocks: 1, - maxBytes: 2, - }, - version: { - appVersion: 1, - }, - }); - validatorSetUpdate = new ValidatorSetUpdate(); - - loggerMock = new LoggerMock(this.sinon); - - verifyChainLockMock = this.sinon.stub().resolves(true); - - processProposalMock = this.sinon.stub().resolves(new ResponseProcessProposal({ status: 1 })); - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - processProposalHandler = processProposalHandlerFactory( - loggerMock, - verifyChainLockMock, - processProposalMock, - proposalBlockExecutionContextMock, - createContextLoggerMock, - ); - - const txs = new Array(3).fill(Buffer.alloc(5, 0)); - - const height = new Long(42); - - const time = { - seconds: Math.ceil(new Date().getTime() / 1000), - }; - const version = { - app: Long.fromInt(1), - }; - const proposerProTxHash = Uint8Array.from([1, 2, 3, 4]); - const coreChainLockedHeight = 10; - const proposedLastCommit = {}; - - coreChainLockUpdate = { - coreBlockHeight: 42, - coreBlockHash: '1528e523f4c20fa84ba70dd96372d34e00ce260f357d53ad1a8bc892ebf20e2d', - signature: '1897ce8f54d2070f44ca5c29983b68b391e8137c25e44f67416e579f3e3bdfef7b4fd22db7818399147e52907998857b0fbc8edfdc40a64f2c7df0e88544d31d12ca8c15e73d50dda25ca23f754ed3f789ed4bcb392161995f464017c10df404', - }; - - request = { - round, - height, - txs, - coreChainLockedHeight, - version, - proposedLastCommit, - time, - proposerProTxHash, - coreChainLockUpdate, - }; - }); - - it('should return ResponseProcessProposal', async () => { - const result = await processProposalHandler(request); - - expect(result).to.be.an.instanceOf(ResponseProcessProposal); - - expect(result.status).to.equal(1); - - expect(processProposalMock).to.be.calledOnceWithExactly(request, loggerMock); - - expect(verifyChainLockMock).to.be.calledOnceWithExactly( - coreChainLockUpdate, - ); - }); - - it('should return rejected ResponseProcessProposal if chainlock can\'t be verified', async () => { - verifyChainLockMock.resolves(false); - - const result = await processProposalHandler(request); - - expect(result).to.be.an.instanceOf(ResponseProcessProposal); - expect(result.status).to.equal(2); - - expect(processProposalMock).to.not.be.called(); - }); - - it('should return already prepared result for this height and round', async () => { - proposalBlockExecutionContextMock.getHeight.returns(request.height); - proposalBlockExecutionContextMock.getRound.returns(request.round); - - proposalBlockExecutionContextMock.getPrepareProposalResult.returns({ - appHash, - txResults: new Array(3).fill({ code: 0 }), - consensusParamUpdates, - validatorSetUpdate, - }); - - const result = await processProposalHandler(request); - - expect(proposalBlockExecutionContextMock.getPrepareProposalResult).to.be.calledOnce(); - - expect(result).to.be.an.instanceOf(ResponseProcessProposal); - expect(result.status).to.equal(1); - expect(result.appHash).to.equal(appHash); - expect(result.txResults).to.be.deep.equal(new Array(3).fill({ code: 0 })); - expect(result.consensusParamUpdates).to.be.equal(consensusParamUpdates); - expect(result.validatorSetUpdate).to.be.equal(validatorSetUpdate); - - expect(processProposalMock).to.not.be.called(); - - expect(verifyChainLockMock).to.not.be.called(); - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - height: '42', - round, - abciMethod: 'processProposal', - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/beginBlockFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/beginBlockFactory.spec.js deleted file mode 100644 index c91301cc649..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/beginBlockFactory.spec.js +++ /dev/null @@ -1,278 +0,0 @@ -const Long = require('long'); -const { - tendermint: { - version: { - Consensus, - }, - }, -} = require('@dashevo/abci/types'); - -const { hash } = require('@dashevo/dpp/lib/util/hash'); - -const beginBlockFactory = require('../../../../../lib/abci/handlers/proposal/beginBlockFactory'); - -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const NotSupportedNetworkProtocolVersionError = require('../../../../../lib/abci/handlers/errors/NotSupportedNetworkProtocolVersionError'); -const NetworkProtocolVersionIsNotSetError = require('../../../../../lib/abci/handlers/errors/NetworkProtocolVersionIsNotSetError'); -const GroveDBStoreMock = require('../../../../../lib/test/mock/GroveDBStoreMock'); -const millisToProtoTimestamp = require('../../../../../lib/util/millisToProtoTimestamp'); -const protoTimestampToMillis = require('../../../../../lib/util/protoTimestampToMillis'); -const BlockInfo = require('../../../../../lib/blockExecution/BlockInfo'); - -describe('beginBlockFactory', () => { - let protocolVersion; - let beginBlock; - let request; - let blockHeight; - let coreChainLockedHeight; - let updateSimplifiedMasternodeListMock; - let waitForChainLockedHeightMock; - let loggerMock; - let lastCommitInfo; - let dppMock; - let transactionalDppMock; - let synchronizeMasternodeIdentitiesMock; - let groveDBStoreMock; - let version; - let rsAbciMock; - let proposerProTxHash; - let proposedAppVersion; - let round; - let executionTimerMock; - let latestBlockExecutionContextMock; - let proposalBlockExecutionContextMock; - let rsResponseMock; - let blockInfo; - let timeMs; - let epochInfo; - let time; - let lastSyncedCoreHeightRepositoryMock; - let simplifyMasternodeListMock; - let validMasternodesListLength; - - beforeEach(function beforeEach() { - round = 0; - protocolVersion = Long.fromInt(1); - proposedAppVersion = Long.fromInt(1); - blockHeight = Long.fromNumber(1); - time = millisToProtoTimestamp(Date.now()); - timeMs = protoTimestampToMillis(time); - epochInfo = { - currentEpochIndex: 1, - isEpochChange: false, - }; - blockInfo = new BlockInfo( - blockHeight.toNumber(), - epochInfo.currentEpochIndex, - timeMs, - ); - - latestBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - proposalBlockExecutionContextMock.isEmpty.returns(true); - proposalBlockExecutionContextMock.getHeight.returns(blockHeight); - proposalBlockExecutionContextMock.getEpochInfo.returns(epochInfo); - proposalBlockExecutionContextMock.getTimeMs.returns(timeMs); - - loggerMock = new LoggerMock(this.sinon); - - dppMock = { - setProtocolVersion: this.sinon.stub(), - }; - transactionalDppMock = { - setProtocolVersion: this.sinon.stub(), - }; - - executionTimerMock = { - clearTimer: this.sinon.stub(), - startTimer: this.sinon.stub(), - stopTimer: this.sinon.stub(), - }; - - updateSimplifiedMasternodeListMock = this.sinon.stub().resolves(false); - waitForChainLockedHeightMock = this.sinon.stub(); - synchronizeMasternodeIdentitiesMock = this.sinon.stub().resolves({ - createdEntities: [], - updatedEntities: [], - removedEntities: [], - fromHeight: 1, - toHeight: 42, - }); - - groveDBStoreMock = new GroveDBStoreMock(this.sinon); - - rsResponseMock = { - epochInfo, - }; - - rsAbciMock = { - blockBegin: this.sinon.stub().resolves(rsResponseMock), - }; - - lastSyncedCoreHeightRepositoryMock = { - fetch: this.sinon.stub().resolves({ - getValue: () => undefined, - }), - }; - - validMasternodesListLength = 400; - - simplifyMasternodeListMock = { - getStore() { - return { - getCurrentSML() { - return { - getValidMasternodesList() { - return validMasternodesListLength; - }, - }; - }, - }; - }, - }; - - beginBlock = beginBlockFactory( - groveDBStoreMock, - latestBlockExecutionContextMock, - proposalBlockExecutionContextMock, - protocolVersion, - dppMock, - transactionalDppMock, - updateSimplifiedMasternodeListMock, - waitForChainLockedHeightMock, - synchronizeMasternodeIdentitiesMock, - rsAbciMock, - executionTimerMock, - lastSyncedCoreHeightRepositoryMock, - simplifyMasternodeListMock, - ); - - lastCommitInfo = {}; - - version = Consensus.fromObject({ - app: protocolVersion, - }); - - proposerProTxHash = Buffer.alloc(32, 1); - - request = { - height: blockHeight, - lastCommitInfo, - coreChainLockedHeight, - version, - time: millisToProtoTimestamp(timeMs), - proposerProTxHash, - proposedAppVersion, - round, - }; - }); - - it('should reset previous block state and prepare everything for for a next one', async () => { - await beginBlock(request, loggerMock); - - // Wait for chain locked core block height - expect(waitForChainLockedHeightMock).to.be.calledOnceWithExactly(coreChainLockedHeight); - - // Set current protocol version - expect(dppMock.setProtocolVersion).to.have.been.calledOnceWithExactly( - protocolVersion.toNumber(), - ); - expect(transactionalDppMock.setProtocolVersion).to.have.been.calledOnceWithExactly( - protocolVersion.toNumber(), - ); - - // Start new transaction - expect(groveDBStoreMock.startTransaction).to.be.calledOnceWithExactly(); - - // Update SML - expect(updateSimplifiedMasternodeListMock).to.be.calledOnceWithExactly( - coreChainLockedHeight, { logger: loggerMock }, - ); - - expect(synchronizeMasternodeIdentitiesMock).to.not.been.called(); - - expect(executionTimerMock.clearTimer).to.be.calledTwice(); - expect(executionTimerMock.clearTimer.getCall(1)).to.be.calledWithExactly('roundExecution'); - expect(executionTimerMock.clearTimer.getCall(0)).to.be.calledWithExactly('blockExecution'); - - expect(executionTimerMock.startTimer).to.be.calledTwice(); - expect(executionTimerMock.startTimer.getCall(1)).to.be.calledWithExactly('roundExecution'); - expect(executionTimerMock.startTimer.getCall(0)).to.be.calledWithExactly('blockExecution'); - - expect(proposalBlockExecutionContextMock.setContextLogger) - .to.be.calledOnceWithExactly(loggerMock); - expect(proposalBlockExecutionContextMock.setHeight) - .to.be.calledOnceWithExactly(blockHeight); - expect(proposalBlockExecutionContextMock.setVersion) - .to.be.calledOnceWithExactly(version); - expect(proposalBlockExecutionContextMock.setProposedAppVersion) - .to.be.calledOnceWithExactly(proposedAppVersion); - expect(proposalBlockExecutionContextMock.setTimeMs) - .to.be.calledOnceWithExactly(timeMs); - expect(proposalBlockExecutionContextMock.setCoreChainLockedHeight) - .to.be.calledOnceWithExactly(coreChainLockedHeight); - expect(proposalBlockExecutionContextMock.setLastCommitInfo) - .to.be.calledOnceWithExactly(lastCommitInfo); - expect(proposalBlockExecutionContextMock.setEpochInfo) - .to.be.calledOnceWithExactly(epochInfo); - }); - - it('should synchronize masternode identities if SML is updated', async () => { - updateSimplifiedMasternodeListMock.resolves(true); - - await beginBlock(request, loggerMock); - - expect(synchronizeMasternodeIdentitiesMock).to.have.been.calledOnceWithExactly( - coreChainLockedHeight, - blockInfo, - ); - }); - - it('should throw NotSupportedNetworkProtocolVersionError if protocol version is not supported', async () => { - request.version.app = Long.fromInt(42); - - try { - await beginBlock(request, loggerMock); - - expect.fail('should throw NotSupportedNetworkProtocolVersionError'); - } catch (e) { - expect(e).to.be.instanceOf(NotSupportedNetworkProtocolVersionError); - expect(e.getNetworkProtocolVersion()).to.equal(request.version.app); - expect(e.getLatestProtocolVersion()).to.equal(protocolVersion); - } - }); - - it('should throw an NetworkProtocolVersionIsNotSetError if network protocol version is not set', async () => { - request.version.app = Long.fromInt(0); - - try { - await beginBlock(request, loggerMock); - - expect.fail('should throw NetworkProtocolVersionIsNotSetError'); - } catch (err) { - expect(err).to.be.an.instanceOf(NetworkProtocolVersionIsNotSetError); - } - }); - - it('should set withdrawal transactions map if present', async () => { - const [txOneBytes, txTwoBytes] = [ - Buffer.alloc(32, 0), - Buffer.alloc(32, 1), - ]; - - rsAbciMock.blockBegin.resolves({ - unsignedWithdrawalTransactions: [txOneBytes, txTwoBytes], - }); - - await beginBlock(request, loggerMock); - - expect( - proposalBlockExecutionContextMock.setWithdrawalTransactionsMap, - ).to.have.been.calledOnceWithExactly({ - [hash(txOneBytes).toString('hex')]: txOneBytes, - [hash(txTwoBytes).toString('hex')]: txTwoBytes, - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.spec.js deleted file mode 100644 index 11e775a082c..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory.spec.js +++ /dev/null @@ -1,69 +0,0 @@ -const Long = require('long'); - -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); - -const broadcastWithdrawalTransactionsFactory = require('../../../../../lib/abci/handlers/proposal/broadcastWithdrawalTransactionsFactory'); -const BlockInfo = require('../../../../../lib/blockExecution/BlockInfo'); - -describe('broadcastWithdrawalTransactionsFactory', () => { - let broadcastWithdrawalTransactions; - let proposalBlockExecutionContextMock; - let coreRpcMock; - let updateWithdrawalTransactionIdAndStatusMock; - - beforeEach(function beforeEach() { - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - proposalBlockExecutionContextMock.getEpochInfo.returns({ - currentEpochIndex: 1, - }); - proposalBlockExecutionContextMock.getHeight.returns(new Long(1)); - proposalBlockExecutionContextMock.getTimeMs.returns(1); - proposalBlockExecutionContextMock.getCoreChainLockedHeight.returns(42); - - coreRpcMock = { - sendRawTransaction: this.sinon.stub(), - }; - - updateWithdrawalTransactionIdAndStatusMock = this.sinon.stub(); - - broadcastWithdrawalTransactions = broadcastWithdrawalTransactionsFactory( - coreRpcMock, - updateWithdrawalTransactionIdAndStatusMock, - ); - }); - - it('should call Core RPC and call document update function', async () => { - const extension = Buffer.alloc(32, 2); - const signature = Buffer.alloc(32, 3); - - const txBytes = Buffer.alloc(32, 1); - - const thresholdVoteExtensions = [ - { extension, signature }, - ]; - const unsignedWithdrawalTransactionsMap = { - [extension.toString('hex')]: txBytes, - }; - - await broadcastWithdrawalTransactions( - proposalBlockExecutionContextMock, - thresholdVoteExtensions, - unsignedWithdrawalTransactionsMap, - ); - - const expectedMap = { [txBytes.toString('hex')]: Buffer.concat([txBytes, signature]) }; - - expect(coreRpcMock.sendRawTransaction).to.have.been.calledOnceWithExactly( - Buffer.concat([txBytes, signature]).toString('hex'), - ); - expect(updateWithdrawalTransactionIdAndStatusMock).to.have.been.calledOnceWithExactly( - BlockInfo.createFromBlockExecutionContext(proposalBlockExecutionContextMock), - 42, - expectedMap, - { - useTransaction: true, - }, - ); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/createConsensusParamUpdateFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/createConsensusParamUpdateFactory.spec.js deleted file mode 100644 index 0e9482be77f..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/createConsensusParamUpdateFactory.spec.js +++ /dev/null @@ -1,90 +0,0 @@ -const { - tendermint: { - types: { - ConsensusParams, - }, - }, -} = require('@dashevo/abci/types'); -const Long = require('long'); -const createConsensusParamUpdateFactory = require('../../../../../lib/abci/handlers/proposal/createConsensusParamUpdateFactory'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); - -describe('createConsensusParamUpdateFactory', () => { - let createConsensusParamUpdate; - let getFeatureFlagForHeightMock; - let loggerMock; - let height; - let version; - let getLatestFeatureFlagGetMock; - let proposalBlockExecutionContextMock; - let round; - - beforeEach(function beforeEach() { - round = 42; - loggerMock = new LoggerMock(this.sinon); - height = Long.fromInt(15); - version = { - app: Long.fromInt(1), - }; - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - proposalBlockExecutionContextMock.getVersion.returns(version); - - getFeatureFlagForHeightMock = this.sinon.stub().resolves(null); - getLatestFeatureFlagGetMock = this.sinon.stub(); - - createConsensusParamUpdate = createConsensusParamUpdateFactory( - proposalBlockExecutionContextMock, - getFeatureFlagForHeightMock, - ); - }); - - it('should return consensusParamUpdates if request contains update consensus features flag', async () => { - getLatestFeatureFlagGetMock.withArgs('block').returns({ - maxBytes: 1, - maxGas: 2, - }); - getLatestFeatureFlagGetMock.withArgs('evidence').returns({ - maxAgeNumBlocks: 1, - maxAgeDuration: null, - maxBytes: 2, - }); - getLatestFeatureFlagGetMock.withArgs('version').returns({ - appVersion: 1, - }); - - getFeatureFlagForHeightMock.resolves({ - get: getLatestFeatureFlagGetMock, - }); - - const response = await createConsensusParamUpdate(height, round, loggerMock); - - expect(response).to.deep.equal(new ConsensusParams({ - block: { - maxBytes: 1, - maxGas: 2, - }, - evidence: { - maxAgeDuration: null, - maxAgeNumBlocks: 1, - maxBytes: 2, - }, - version: { - appVersion: 1, - }, - })); - - expect(getFeatureFlagForHeightMock).to.be.calledOnce(); - }); - - it('should return undefined', async () => { - getFeatureFlagForHeightMock.resolves(null); - - const response = await createConsensusParamUpdate(height, round, loggerMock); - - expect(response).to.be.undefined(); - - expect(getFeatureFlagForHeightMock).to.be.calledOnce(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/createCoreChainLockUpdateFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/createCoreChainLockUpdateFactory.spec.js deleted file mode 100644 index 7e52c580dfc..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/createCoreChainLockUpdateFactory.spec.js +++ /dev/null @@ -1,65 +0,0 @@ -const { - tendermint: { - types: { - CoreChainLock, - }, - }, -} = require('@dashevo/abci/types'); -const createCoreChainLockUpdateFactory = require('../../../../../lib/abci/handlers/proposal/createCoreChainLockUpdateFactory'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); - -describe('createCoreChainLockUpdateFactory', () => { - let createCoreChainLockUpdate; - let latestCoreChainLockMock; - let chainLockMock; - let coreChainLockedHeight; - let loggerMock; - let round; - - beforeEach(function beforeEach() { - round = 0; - loggerMock = new LoggerMock(this.sinon); - - chainLockMock = { - height: 1, - blockHash: Buffer.alloc(0), - signature: Buffer.alloc(0), - }; - - coreChainLockedHeight = 2; - - latestCoreChainLockMock = { - getChainLock: this.sinon.stub().returns(chainLockMock), - }; - - createCoreChainLockUpdate = createCoreChainLockUpdateFactory( - latestCoreChainLockMock, - ); - }); - - it('should return nextCoreChainLockUpdate if latestCoreChainLock above header height', async () => { - chainLockMock.height = 3; - - const response = await createCoreChainLockUpdate(coreChainLockedHeight, round, loggerMock); - - expect(latestCoreChainLockMock.getChainLock).to.have.been.calledOnceWithExactly(); - - const expectedCoreChainLock = new CoreChainLock({ - coreBlockHeight: chainLockMock.height, - coreBlockHash: chainLockMock.blockHash, - signature: chainLockMock.signature, - }); - - expect(response).to.deep.equal(expectedCoreChainLock); - }); - - it('should return undefined', async () => { - chainLockMock.height = 1; - - const response = await createCoreChainLockUpdate(coreChainLockedHeight, round, loggerMock); - - expect(latestCoreChainLockMock.getChainLock).to.have.been.calledOnceWithExactly(); - - expect(response).to.be.undefined(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/deliverTxFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/deliverTxFactory.spec.js deleted file mode 100644 index 2f882d057fc..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/deliverTxFactory.spec.js +++ /dev/null @@ -1,319 +0,0 @@ -const Long = require('long'); - -const crypto = require('crypto'); - -const DashPlatformProtocol = require('@dashevo/dpp'); - -const { FeeResult } = require('@dashevo/rs-drive'); - -const ValidationResult = require('@dashevo/dpp/lib/validation/ValidationResult'); - -const createDPPMock = require('@dashevo/dpp/lib/test/mocks/createDPPMock'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); - -const StateTransitionExecutionContext = require('@dashevo/dpp/lib/stateTransition/StateTransitionExecutionContext'); - -const SomeConsensusError = require('@dashevo/dpp/lib/test/mocks/SomeConsensusError'); - -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); - -const deliverTxFactory = require('../../../../../lib/abci/handlers/proposal/deliverTxFactory'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const DPPValidationAbciError = require('../../../../../lib/abci/errors/DPPValidationAbciError'); -const InvalidArgumentAbciError = require('../../../../../lib/abci/errors/InvalidArgumentAbciError'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('deliverTxFactory', () => { - let deliverTx; - let documentTx; - let dataContractTx; - let dppMock; - let documentsBatchTransitionFixture; - let dataContractCreateTransitionFixture; - let dpp; - let unserializeStateTransitionMock; - let validationResult; - let executionTimerMock; - let loggerMock; - let round; - let proposalBlockExecutionContextMock; - let stateTransitionExecutionContextMock; - let identityBalanceRepositoryMock; - let processingFee; - let storageFee; - let refundsPerEpoch; - let feeRefunds; - let createContextLoggerMock; - let calculateStateTransitionFeeMock; - let calculateStateTransitionFeeFromOperationsMock; - - beforeEach(async function beforeEach() { - round = 42; - const dataContractFixture = getDataContractFixture(); - const documentFixture = getDocumentsFixture(); - - dpp = new DashPlatformProtocol(); - await dpp.initialize(); - - documentsBatchTransitionFixture = dpp.document.createStateTransition({ - create: documentFixture, - }); - - dataContractCreateTransitionFixture = dpp - .dataContract.createDataContractCreateTransition(dataContractFixture); - - loggerMock = new LoggerMock(this.sinon); - - stateTransitionExecutionContextMock = new StateTransitionExecutionContext(); - - processingFee = 10; - storageFee = 100; - const totalRefunds = 15; - refundsPerEpoch = { - 1: totalRefunds, - }; - feeRefunds = [ - { - identifier: Buffer.alloc(32), - creditsPerEpoch: { 1: totalRefunds }, - }, - ]; - - const actualSTFees = FeeResult.create(storageFee, processingFee, feeRefunds); - - identityBalanceRepositoryMock = { - applyFees: this.sinon.stub().resolves( - new StorageResult(actualSTFees), - ), - }; - - documentsBatchTransitionFixture.setExecutionContext(stateTransitionExecutionContextMock); - dataContractCreateTransitionFixture.setExecutionContext(stateTransitionExecutionContextMock); - - documentTx = documentsBatchTransitionFixture.toBuffer(); - - dataContractTx = dataContractCreateTransitionFixture.toBuffer(); - - dppMock = createDPPMock(this.sinon); - - validationResult = new ValidationResult(); - - dppMock - .stateTransition - .validateState - .resolves(validationResult); - - unserializeStateTransitionMock = this.sinon.stub(); - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - proposalBlockExecutionContextMock.getHeight.returns(Long.fromNumber(42)); - proposalBlockExecutionContextMock.getEpochInfo.returns({ - currentEpochIndex: 0, - }); - - executionTimerMock = { - clearTimer: this.sinon.stub(), - getTimer: this.sinon.stub(), - startTimer: this.sinon.stub(), - stopTimer: this.sinon.stub(), - isStarted: this.sinon.stub(), - }; - - createContextLoggerMock = this.sinon.stub().returns(loggerMock); - - calculateStateTransitionFeeMock = this.sinon.stub().returns({ - storageFee, - processingFee, - feeRefunds, - totalRefunds, - requiredAmount: processingFee - totalRefunds, - desiredAmount: storageFee + processingFee - totalRefunds, - }); - - calculateStateTransitionFeeFromOperationsMock = this.sinon.stub().returns({ - storageFee, - processingFee, - feeRefunds, - totalRefunds, - requiredAmount: processingFee - totalRefunds, - desiredAmount: storageFee + processingFee - totalRefunds, - }); - - deliverTx = deliverTxFactory( - unserializeStateTransitionMock, - dppMock, - proposalBlockExecutionContextMock, - executionTimerMock, - identityBalanceRepositoryMock, - calculateStateTransitionFeeMock, - calculateStateTransitionFeeFromOperationsMock, - createContextLoggerMock, - ); - }); - - it('should execute a state transition and return result', async () => { - unserializeStateTransitionMock.resolves(documentsBatchTransitionFixture); - - const response = await deliverTx(documentTx, round, loggerMock); - - expect(response).to.deep.equal({ - code: 0, - fees: { - processingFee, - storageFee, - refundsPerEpoch, - }, - }); - - expect(unserializeStateTransitionMock).to.be.calledOnceWithExactly( - documentsBatchTransitionFixture.toBuffer(), - { - logger: loggerMock, - executionTimer: executionTimerMock, - }, - ); - - expect(dppMock.stateTransition.validateState).to.be.calledOnceWithExactly( - documentsBatchTransitionFixture, - ); - - expect(dppMock.stateTransition.apply).to.be.calledOnceWithExactly( - documentsBatchTransitionFixture, - ); - - expect(identityBalanceRepositoryMock.applyFees).to.be.calledOnce(); - - const applyFeesToBalanceArgs = identityBalanceRepositoryMock.applyFees.getCall(0).args; - - expect(applyFeesToBalanceArgs).to.have.lengthOf(3); - - const identifier = applyFeesToBalanceArgs[0]; - - expect(identifier).to.equals(documentsBatchTransitionFixture.getOwnerId()); - - const feeResult = applyFeesToBalanceArgs[1]; - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.storageFee).to.equals(storageFee); - expect(feeResult.processingFee).to.equals(processingFee); - expect(feeResult.feeRefunds).to.deep.equals(feeRefunds); - - expect(applyFeesToBalanceArgs[2]).to.deep.equals({ useTransaction: true }); - - expect(proposalBlockExecutionContextMock.addDataContract).to.not.be.called(); - - expect( - dataContractCreateTransitionFixture.getExecutionContext().dryOperations, - ).to.have.length(0); - - const stHash = crypto - .createHash('sha256') - .update(documentTx) - .digest() - .toString('hex') - .toUpperCase(); - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - txId: stHash, - }); - }); - - it('should execute a DataContractCreateTransition', async () => { - unserializeStateTransitionMock.resolves(dataContractCreateTransitionFixture); - - const response = await deliverTx(dataContractTx, round, loggerMock); - - expect(response).to.deep.equal({ - code: 0, - fees: { - processingFee, - storageFee, - refundsPerEpoch, - }, - }); - - expect(unserializeStateTransitionMock).to.be.calledOnceWithExactly( - dataContractCreateTransitionFixture.toBuffer(), - { - logger: loggerMock, - executionTimer: executionTimerMock, - }, - ); - - expect(dppMock.stateTransition.validateState).to.be.calledOnceWithExactly( - dataContractCreateTransitionFixture, - ); - - expect(dppMock.stateTransition.apply).to.be.calledOnceWithExactly( - dataContractCreateTransitionFixture, - ); - - expect(identityBalanceRepositoryMock.applyFees).to.be.calledOnce(); - - const applyFeesToBalanceArgs = identityBalanceRepositoryMock.applyFees.getCall(0).args; - - expect(applyFeesToBalanceArgs).to.have.lengthOf(3); - - const identifier = applyFeesToBalanceArgs[0]; - - expect(identifier).to.equals(dataContractCreateTransitionFixture.getOwnerId()); - - const feeResult = applyFeesToBalanceArgs[1]; - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.storageFee).to.equals(storageFee); - expect(feeResult.processingFee).to.equals(processingFee); - expect(feeResult.feeRefunds).to.deep.equals(feeRefunds); - - expect(applyFeesToBalanceArgs[2]).to.deep.equals({ useTransaction: true }); - - expect( - dataContractCreateTransitionFixture.getExecutionContext().dryOperations, - ).to.have.length(0); - - expect(proposalBlockExecutionContextMock.addDataContract).to.be.calledOnceWith( - dataContractCreateTransitionFixture.getDataContract(), - ); - }); - - it('should throw DPPValidationAbciError if a state transition is invalid against state', async () => { - unserializeStateTransitionMock.resolves(dataContractCreateTransitionFixture); - - const error = new SomeConsensusError('Consensus error'); - - validationResult.addError(error); - - try { - await deliverTx(documentTx, round, loggerMock); - - expect.fail('should throw InvalidArgumentAbciError error'); - } catch (e) { - expect(e).to.be.instanceOf(DPPValidationAbciError); - expect(e.getCode()).to.equal(error.getCode()); - expect(e.getData()).to.deep.equal({ - arguments: ['Consensus error'], - }); - } - }); - - it('should throw DPPValidationAbciError if a state transition is not valid', async () => { - const errorMessage = 'Invalid structure'; - const error = new InvalidArgumentAbciError(errorMessage); - - unserializeStateTransitionMock.throws(error); - - try { - await deliverTx(documentTx, round, loggerMock); - - expect.fail('should throw InvalidArgumentAbciError error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidArgumentAbciError); - expect(e.getMessage()).to.equal(errorMessage); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - expect(dppMock.stateTransition.validate).to.not.be.called(); - } - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/endBlockFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/endBlockFactory.spec.js deleted file mode 100644 index cbb0ca7a2cc..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/endBlockFactory.spec.js +++ /dev/null @@ -1,134 +0,0 @@ -const Long = require('long'); - -const endBlockFactory = require('../../../../../lib/abci/handlers/proposal/endBlockFactory'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const GroveDBStoreMock = require('../../../../../lib/test/mock/GroveDBStoreMock'); - -describe('endBlockFactory', () => { - let endBlock; - let height; - let dpnsContractBlockHeight; - let loggerMock; - let createValidatorSetUpdateMock; - let validatorSetMock; - let getFeatureFlagForHeightMock; - let rsAbciMock; - let blockEndMock; - let time; - let createConsensusParamUpdateMock; - let rotateAndCreateValidatorSetUpdateMock; - let groveDBStoreMock; - let appHashFixture; - let validatorSetUpdateFixture; - let consensusParamUpdatesFixture; - let executionTimerMock; - let proposalBlockExecutionContextMock; - let round; - let coreChainLockedHeight; - let fees; - - beforeEach(function beforeEach() { - round = 42; - coreChainLockedHeight = 41; - time = Date.now(); - fees = { - processingFee: 10, - storageFee: 100, - feeRefunds: { - 1: 15, - }, - feeRefundsSum: 15, - }; - - executionTimerMock = { - clearTimer: this.sinon.stub(), - startTimer: this.sinon.stub(), - stopTimer: this.sinon.stub(), - }; - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - proposalBlockExecutionContextMock.hasDataContract.returns(true); - proposalBlockExecutionContextMock.getTimeMs.returns(time); - - proposalBlockExecutionContextMock.getEpochInfo.returns({ - currentEpochIndex: 42, - isEpochChange: true, - }); - - loggerMock = new LoggerMock(this.sinon); - - dpnsContractBlockHeight = 2; - - validatorSetMock = { - rotate: this.sinon.stub(), - getQuorum: this.sinon.stub(), - }; - - createValidatorSetUpdateMock = this.sinon.stub(); - - getFeatureFlagForHeightMock = this.sinon.stub().resolves(null); - - blockEndMock = this.sinon.stub(); - - rsAbciMock = { - blockEnd: blockEndMock, - }; - - blockEndMock.resolves({ - currentEpochIndex: 42, - isEpochChange: true, - }); - - consensusParamUpdatesFixture = Buffer.alloc(1); - validatorSetUpdateFixture = Buffer.alloc(2); - appHashFixture = Buffer.alloc(0); - - createConsensusParamUpdateMock = this.sinon.stub().resolves(consensusParamUpdatesFixture); - rotateAndCreateValidatorSetUpdateMock = this.sinon.stub().resolves(validatorSetUpdateFixture); - - groveDBStoreMock = new GroveDBStoreMock(this.sinon); - groveDBStoreMock.getRootHash.resolves(appHashFixture); - - endBlock = endBlockFactory( - proposalBlockExecutionContextMock, - validatorSetMock, - createValidatorSetUpdateMock, - getFeatureFlagForHeightMock, - createConsensusParamUpdateMock, - rotateAndCreateValidatorSetUpdateMock, - rsAbciMock, - groveDBStoreMock, - executionTimerMock, - ); - - height = Long.fromInt(dpnsContractBlockHeight); - }); - - it('should end block', async () => { - const response = await endBlock({ - height, round, fees, coreChainLockedHeight, - }, loggerMock); - - expect(response).to.deep.equal({ - consensusParamUpdates: consensusParamUpdatesFixture, - validatorSetUpdate: validatorSetUpdateFixture, - appHash: appHashFixture, - }); - - expect(proposalBlockExecutionContextMock.hasDataContract).to.not.have.been.called(); - expect(createConsensusParamUpdateMock).to.be.calledOnceWithExactly(height, round, loggerMock); - expect(rotateAndCreateValidatorSetUpdateMock).to.be.calledOnceWithExactly( - height, - coreChainLockedHeight, - round, - loggerMock, - ); - expect(groveDBStoreMock.getRootHash).to.be.calledOnceWithExactly({ useTransaction: true }); - - expect(rsAbciMock.blockEnd).to.be.calledOnceWithExactly({ fees }, true); - - expect(executionTimerMock.stopTimer).to.be.calledOnceWithExactly('roundExecution', true); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/processProposalFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/processProposalFactory.spec.js deleted file mode 100644 index c114a5e676a..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/processProposalFactory.spec.js +++ /dev/null @@ -1,170 +0,0 @@ -const { - tendermint: { - abci: { - ResponseProcessProposal, - ValidatorSetUpdate, - }, - types: { - ConsensusParams, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const processProposalHandlerFactory = require('../../../../../lib/abci/handlers/proposal/processProposalFactory'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); - -describe('processProposalFactory', () => { - let processProposalHandler; - let request; - let loggerMock; - let beginBlockMock; - let endBlockMock; - let deliverTxMock; - let appHash; - let validatorSetUpdate; - let consensusParamUpdates; - let coreChainLockUpdate; - let proposalBlockExecutionContextMock; - let round; - let executionTimerMock; - let quorumHash; - - beforeEach(function beforeEach() { - round = 0; - appHash = Buffer.alloc(1, 1); - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - loggerMock = new LoggerMock(this.sinon); - - consensusParamUpdates = new ConsensusParams({ - block: { - maxBytes: 1, - maxGas: 2, - }, - evidence: { - maxAgeDuration: null, - maxAgeNumBlocks: 1, - maxBytes: 2, - }, - version: { - appVersion: 1, - }, - }); - - validatorSetUpdate = new ValidatorSetUpdate(); - - beginBlockMock = this.sinon.stub(); - - endBlockMock = this.sinon.stub().resolves({ - consensusParamUpdates, - appHash, - validatorSetUpdate, - }); - - deliverTxMock = this.sinon.stub().resolves({ - code: 0, - fees: { - processingFee: 10, - storageFee: 100, - refundsPerEpoch: { - 1: 15, - }, - }, - }); - - beginBlockMock = this.sinon.stub(); - - executionTimerMock = { - getTimer: this.sinon.stub().returns(0.1), - }; - - processProposalHandler = processProposalHandlerFactory( - deliverTxMock, - proposalBlockExecutionContextMock, - beginBlockMock, - endBlockMock, - executionTimerMock, - ); - - const txs = new Array(3).fill(Buffer.alloc(5, 0)); - - const height = new Long(42); - - const time = { - seconds: Math.ceil(new Date().getTime() / 1000), - }; - const version = { - app: Long.fromInt(1), - }; - const proposerProTxHash = Uint8Array.from([1, 2, 3, 4]); - const coreChainLockedHeight = 10; - const proposedLastCommit = {}; - - coreChainLockUpdate = { - coreBlockHeight: 42, - coreBlockHash: '1528e523f4c20fa84ba70dd96372d34e00ce260f357d53ad1a8bc892ebf20e2d', - signature: '1897ce8f54d2070f44ca5c29983b68b391e8137c25e44f67416e579f3e3bdfef7b4fd22db7818399147e52907998857b0fbc8edfdc40a64f2c7df0e88544d31d12ca8c15e73d50dda25ca23f754ed3f789ed4bcb392161995f464017c10df404', - }; - - quorumHash = Buffer.alloc(32, 0); - - request = { - round, - height, - txs, - coreChainLockedHeight, - version, - proposedLastCommit, - time, - proposerProTxHash, - coreChainLockUpdate, - quorumHash, - }; - }); - - it('should return ResponseProcessProposal', async () => { - const result = await processProposalHandler(request, loggerMock); - - expect(result).to.be.an.instanceOf(ResponseProcessProposal); - expect(result.status).to.equal(1); - expect(result.appHash).to.equal(appHash); - expect(result.txResults).to.be.deep.equal(new Array(3).fill({ code: 0 })); - expect(result.consensusParamUpdates).to.be.equal(consensusParamUpdates); - expect(result.validatorSetUpdate).to.be.equal(validatorSetUpdate); - - expect(beginBlockMock).to.be.calledOnceWithExactly( - { - lastCommitInfo: request.proposedLastCommit, - height: request.height, - coreChainLockedHeight: request.coreChainLockedHeight, - version: request.version, - time: request.time, - proposerProTxHash: Buffer.from(request.proposerProTxHash), - proposedAppVersion: request.proposedAppVersion, - round, - quorumHash, - }, - loggerMock, - ); - - expect(deliverTxMock).to.be.calledThrice(); - - expect(endBlockMock).to.be.calledOnceWithExactly({ - height: request.height, - round, - fees: { - processingFee: 10 * 3, - storageFee: 100 * 3, - refundsPerEpoch: { - 1: 15 * 3, - }, - }, - coreChainLockedHeight: request.coreChainLockedHeight, - }, - loggerMock); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.spec.js deleted file mode 100644 index e404f70cdec..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory.spec.js +++ /dev/null @@ -1,103 +0,0 @@ -const { - tendermint: { - abci: { - ValidatorSetUpdate, - }, - }, -} = require('@dashevo/abci/types'); -const Long = require('long'); -const rotateAndCreateValidatorSetUpdateFactory = require('../../../../../lib/abci/handlers/proposal/rotateAndCreateValidatorSetUpdateFactory'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); - -describe('rotateAndCreateValidatorSetUpdateFactory', () => { - let rotateAndCreateValidatorSetUpdate; - let validatorSetMock; - let createValidatorSetUpdateMock; - let height; - let loggerMock; - let lastCommitInfoMock; - let round; - let proposalBlockExecutionContextMock; - let coreChainLockedHeight; - - beforeEach(function beforeEach() { - round = 0; - coreChainLockedHeight = 1; - - lastCommitInfoMock = { - blockSignature: Uint8Array.from('003657bb44d74c371d14485117de43313ca5c2848f3622d691c2b1bf3576a64bdc2538efab24854eb82ae7db38482dbd15a1cb3bc98e55173817c9d05c86e47a5d67614a501414aae6dd1565e59422d1d77c41ae9b38de34ecf1e9f778b2a97b'), - }; - - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - proposalBlockExecutionContextMock.getLastCommitInfo.returns(lastCommitInfoMock); - - validatorSetMock = { - rotate: this.sinon.stub(), - getQuorum: this.sinon.stub(), - }; - - createValidatorSetUpdateMock = this.sinon.stub(); - - loggerMock = new LoggerMock(this.sinon); - - rotateAndCreateValidatorSetUpdate = rotateAndCreateValidatorSetUpdateFactory( - proposalBlockExecutionContextMock, - validatorSetMock, - createValidatorSetUpdateMock, - ); - }); - - it('should rotate validator set and return ValidatorSetUpdate if height is divisible by ROTATION_BLOCK_INTERVAL', async () => { - height = Long.fromInt(15); - - const quorumHash = Buffer.alloc(64).fill(1).toString('hex'); - - validatorSetMock.rotate.resolves(true); - validatorSetMock.getQuorum.resolves({ quorumHash }); - - const validatorSetUpdate = new ValidatorSetUpdate(); - - createValidatorSetUpdateMock.returns(validatorSetUpdate); - - const response = await rotateAndCreateValidatorSetUpdate( - height, - coreChainLockedHeight, - round, - loggerMock, - ); - - expect(validatorSetMock.rotate).to.be.calledOnceWithExactly( - height, - coreChainLockedHeight, - Buffer.from(lastCommitInfoMock.blockSignature), - ); - - expect(createValidatorSetUpdateMock).to.be.calledOnceWithExactly(validatorSetMock); - - expect(response).to.be.equal(validatorSetUpdate); - }); - - it('should return undefined', async () => { - height = Long.fromInt(15); - - validatorSetMock.rotate.resolves(false); - - const response = await rotateAndCreateValidatorSetUpdate( - height, - coreChainLockedHeight, - round, - loggerMock, - ); - - expect(validatorSetMock.rotate).to.be.calledOnceWithExactly( - height, - coreChainLockedHeight, - Buffer.from(lastCommitInfoMock.blockSignature), - ); - - expect(createValidatorSetUpdateMock).to.not.be.called(); - - expect(response).to.be.undefined(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/proposal/verifyChainLockFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/proposal/verifyChainLockFactory.spec.js deleted file mode 100644 index d8debd3330b..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/proposal/verifyChainLockFactory.spec.js +++ /dev/null @@ -1,117 +0,0 @@ -const verifyChainLockFactory = require('../../../../../lib/abci/handlers/proposal/verifyChainLockFactory'); - -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); - -describe('verifyChainLockFactory', () => { - let verifyChainLock; - let chainLockMock; - let loggerMock; - let coreRpcClientMock; - let latestBlockExecutionContextMock; - - beforeEach(function beforeEach() { - latestBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - latestBlockExecutionContextMock.getCoreChainLockedHeight.returns(41); - - chainLockMock = { - coreBlockHash: Buffer.alloc(1, 1).toString(), - signature: Buffer.alloc(1, 2).toString(), - coreBlockHeight: 42, - }; - - loggerMock = new LoggerMock(this.sinon); - - coreRpcClientMock = { - verifyChainLock: this.sinon.stub(), - }; - coreRpcClientMock.verifyChainLock.resolves({ result: true }); - - verifyChainLock = verifyChainLockFactory( - coreRpcClientMock, - latestBlockExecutionContextMock, - loggerMock, - ); - }); - - it('should verify chain lock though Core', async () => { - const result = await verifyChainLock(chainLockMock); - - expect(result).to.be.true(); - expect(coreRpcClientMock.verifyChainLock).to.be.calledOnceWithExactly( - Buffer.from(chainLockMock.coreBlockHash).toString('hex'), - Buffer.from(chainLockMock.signature).toString('hex'), - chainLockMock.coreBlockHeight, - ); - - expect(latestBlockExecutionContextMock.getCoreChainLockedHeight).to.be.calledOnce(); - }); - - it('should return false if chainLock is not valid', async () => { - coreRpcClientMock.verifyChainLock.resolves({ result: false }); - - const result = await verifyChainLock(chainLockMock); - - expect(result).to.be.false(); - }); - - it('should return false if Core returns parse error', async () => { - const error = new Error('parse error'); - error.code = -32700; - - coreRpcClientMock.verifyChainLock.throws(error); - - const result = await verifyChainLock(chainLockMock); - - expect(result).to.be.false(); - expect(coreRpcClientMock.verifyChainLock).to.be.calledOnceWithExactly( - Buffer.from(chainLockMock.coreBlockHash).toString('hex'), - Buffer.from(chainLockMock.signature).toString('hex'), - chainLockMock.coreBlockHeight, - ); - }); - - it('should return false if Core returns invalid signature format error', async () => { - const error = new Error('invalid signature format'); - error.code = -8; - - coreRpcClientMock.verifyChainLock.throws(error); - - const result = await verifyChainLock(chainLockMock); - - expect(result).to.be.false(); - expect(coreRpcClientMock.verifyChainLock).to.be.calledOnceWithExactly( - Buffer.from(chainLockMock.coreBlockHash).toString('hex'), - Buffer.from(chainLockMock.signature).toString('hex'), - chainLockMock.coreBlockHeight, - ); - }); - - it('should throw an error if Core throws error', async () => { - const error = new Error(); - - coreRpcClientMock.verifyChainLock.throws(error); - - try { - await verifyChainLock(chainLockMock); - - expect.fail('error was not thrown'); - } catch (e) { - expect(e).to.deep.equal(error); - } - - expect(coreRpcClientMock.verifyChainLock).to.be.calledOnceWithExactly( - Buffer.from(chainLockMock.coreBlockHash).toString('hex'), - Buffer.from(chainLockMock.signature).toString('hex'), - chainLockMock.coreBlockHeight, - ); - }); - - it('should return false if coreBlockHeight >= lastCoreChainLockedHeight', async () => { - latestBlockExecutionContextMock.getCoreChainLockedHeight.returns(42); - const result = await verifyChainLock(chainLockMock); - - expect(result).to.be.false(); - expect(coreRpcClientMock.verifyChainLock).to.not.be.called(); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/dataContractQueryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/dataContractQueryHandlerFactory.spec.js deleted file mode 100644 index bafac7aa54f..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/dataContractQueryHandlerFactory.spec.js +++ /dev/null @@ -1,124 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetDataContractResponse, - Proof, - }, -} = require('@dashevo/dapi-grpc'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); - -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const dataContractQueryHandlerFactory = require('../../../../../lib/abci/handlers/query/dataContractQueryHandlerFactory'); - -const NotFoundAbciError = require('../../../../../lib/abci/errors/NotFoundAbciError'); -const StoreRepositoryMock = require('../../../../../lib/test/mock/StoreRepositoryMock'); -const InvalidArgumentAbciError = require('../../../../../lib/abci/errors/InvalidArgumentAbciError'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('dataContractQueryHandlerFactory', () => { - let dataContractQueryHandler; - let dataContract; - let params; - let data; - let createQueryResponseMock; - let responseMock; - let dataContractRepositoryMock; - - beforeEach(function beforeEach() { - dataContract = getDataContractFixture(); - - createQueryResponseMock = this.sinon.stub(); - - responseMock = new GetDataContractResponse(); - responseMock.setProof(new Proof()); - - createQueryResponseMock.returns(responseMock); - - dataContractRepositoryMock = new StoreRepositoryMock(this.sinon); - - dataContractQueryHandler = dataContractQueryHandlerFactory( - dataContractRepositoryMock, - createQueryResponseMock, - ); - - params = { }; - data = { - id: dataContract.getId(), - }; - }); - - it('should throw NotFoundAbciError if Data Contract not found', async () => { - dataContractRepositoryMock.fetch.resolves( - new StorageResult(null), - ); - - try { - await dataContractQueryHandler(params, data, {}); - - expect.fail('should throw NotFoundAbciError'); - } catch (e) { - expect(e).to.be.an.instanceOf(NotFoundAbciError); - expect(dataContractRepositoryMock.fetch).to.be.calledOnce(); - } - }); - - it('should return data contract', async () => { - dataContractRepositoryMock.fetch.resolves( - new StorageResult(dataContract), - ); - - const result = await dataContractQueryHandler(params, data, {}); - - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); - - it('should InvalidArgumentAbciError on wrong Id', async () => { - data.id = Buffer.alloc(0); - - try { - await dataContractQueryHandler(params, data, {}); - - expect.fail('should throw InvalidArgumentAbciError'); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidArgumentAbciError); - } - }); - - it('should return proof if it was requested', async () => { - // const proof = { - // rootTreeProof: Buffer.from('0100000001f0faf5f55674905a68eba1be2f946e667c1cb5010101', 'hex'), - // storeTreeProof: Buffer.from('03046b657931060076616c75653103046b657932060076616c75653210', - // 'hex'), - // }; - - const proof = Buffer.alloc(20, 255); - - dataContractRepositoryMock.fetch.resolves( - new StorageResult(dataContract), - ); - - dataContractRepositoryMock.prove.resolves( - new StorageResult(proof), - ); - - const result = await dataContractQueryHandler(params, data, { prove: true }); - - expect(dataContractRepositoryMock.prove).to.be.calledOnceWithExactly( - new Identifier(data.id), - ); - - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/documentQueryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/documentQueryHandlerFactory.spec.js deleted file mode 100644 index cb56c5aefbe..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/documentQueryHandlerFactory.spec.js +++ /dev/null @@ -1,167 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetDocumentsResponse, - Proof, - }, -} = require('@dashevo/dapi-grpc'); - -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); - -const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); -const documentQueryHandlerFactory = require('../../../../../lib/abci/handlers/query/documentQueryHandlerFactory'); -const InvalidQueryError = require('../../../../../lib/document/errors/InvalidQueryError'); - -const UnavailableAbciError = require('../../../../../lib/abci/errors/UnavailableAbciError'); -const InvalidArgumentAbciError = require('../../../../../lib/abci/errors/InvalidArgumentAbciError'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('documentQueryHandlerFactory', () => { - let documentQueryHandler; - let fetchSignedDocumentsMock; - let proveSignedDocumentsMock; - let documents; - let params; - let data; - let options; - let createQueryResponseMock; - let responseMock; - - beforeEach(function beforeEach() { - documents = getDocumentsFixture(); - - fetchSignedDocumentsMock = this.sinon.stub(); - proveSignedDocumentsMock = this.sinon.stub(); - createQueryResponseMock = this.sinon.stub(); - - responseMock = new GetDocumentsResponse(); - responseMock.setProof(new Proof()); - - createQueryResponseMock.returns(responseMock); - - documentQueryHandler = documentQueryHandlerFactory( - fetchSignedDocumentsMock, - proveSignedDocumentsMock, - createQueryResponseMock, - ); - - params = {}; - data = { - contractId: generateRandomIdentifier(), - type: 'documentType', - orderBy: [{ sort: 'asc' }], - limit: 2, - startAt: undefined, - startAfter: undefined, - where: [['field', '==', 'value']], - }; - options = { - orderBy: data.orderBy, - limit: data.limit, - startAt: data.startAt, - startAfter: data.startAfter, - where: data.where, - }; - }); - - it('should return serialized documents', async () => { - fetchSignedDocumentsMock.resolves( - new StorageResult(documents), - ); - - const result = await documentQueryHandler(params, data, {}); - - expect(createQueryResponseMock).to.be.calledOnceWith(GetDocumentsResponse, undefined); - expect(fetchSignedDocumentsMock).to.be.calledOnceWith( - data.contractId, - data.type, - options, - ); - expect(proveSignedDocumentsMock).to.not.be.called(); - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); - - it('should return proof if it was requested', async () => { - // const proof = { - // rootTreeProof: Buffer.from('0100000001f0faf5f55674905a68eba1be2f946e667c1cb5010101', - // 'hex'), - // storeTreeProof: Buffer.from('03046b657931060076616c75653103046b657932060076616c75653210', - // 'hex'), - // }; - - const proof = Buffer.alloc(20, 255); - - fetchSignedDocumentsMock.resolves(new StorageResult(documents)); - proveSignedDocumentsMock.resolves( - new StorageResult(proof), - ); - - const result = await documentQueryHandler(params, data, { prove: true }); - - expect(createQueryResponseMock).to.be.calledOnceWith(GetDocumentsResponse, true); - expect(fetchSignedDocumentsMock).to.not.be.called(); - expect(proveSignedDocumentsMock).to.be.calledOnceWith(data.contractId, data.type, options); - - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); - - it('should throw InvalidArgumentAbciError on invalid query', async () => { - fetchSignedDocumentsMock.throws(new InvalidQueryError('invalid')); - - try { - await documentQueryHandler(params, data, {}); - - expect.fail('should throw UnavailableAbciError'); - } catch (e) { - expect(e).to.be.an.instanceof(InvalidArgumentAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - expect(e.getMessage()).to.equal('Invalid query: invalid'); - expect(fetchSignedDocumentsMock).to.be.calledOnceWith(data.contractId, data.type); - } - }); - - it('should not proceed forward if createQueryResponse throws UnavailableAbciError', async () => { - createQueryResponseMock.throws(new UnavailableAbciError('message')); - - try { - await documentQueryHandler(params, data, {}); - - expect.fail('should throw UnavailableAbciError'); - } catch (e) { - expect(e).to.be.an.instanceof(UnavailableAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.UNAVAILABLE); - expect(e.getMessage()).to.equal('message'); - expect(fetchSignedDocumentsMock).to.not.be.called(); - } - }); - - it('should throw error if fetchSignedDocuments throws unknown error', async () => { - const error = new Error('Some error'); - - fetchSignedDocumentsMock.throws(error); - - try { - await documentQueryHandler(params, data, {}); - - expect.fail('should throw any error'); - } catch (e) { - expect(e).to.deep.equal(error); - expect(fetchSignedDocumentsMock).to.be.calledOnceWith(data.contractId, data.type); - } - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/getProofsQueryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/getProofsQueryHandlerFactory.spec.js deleted file mode 100644 index ca2970a27b5..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/getProofsQueryHandlerFactory.spec.js +++ /dev/null @@ -1,122 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); -const cbor = require('cbor'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); - -const getProofsQueryHandlerFactory = require('../../../../../lib/abci/handlers/query/getProofsQueryHandlerFactory'); -const BlockExecutionContextMock = require('../../../../../lib/test/mock/BlockExecutionContextMock'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('getProofsQueryHandlerFactory', () => { - let getProofsQueryHandler; - let dataContract; - let identity; - let documents; - let dataContractData; - let documentsData; - let identityData; - let blockExecutionContextMock; - let identityRepositoryMock; - let dataContractRepositoryMock; - let documentRepository; - let timeMs; - - beforeEach(function beforeEach() { - dataContract = getDataContractFixture(); - identity = getIdentityFixture(); - documents = getDocumentsFixture(); - - const version = { - app: Long.fromInt(1), - }; - - timeMs = Date.now(); - - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - blockExecutionContextMock.getHeight.returns(new Long(42)); - blockExecutionContextMock.getCoreChainLockedHeight.returns(41); - blockExecutionContextMock.getTimeMs.returns(timeMs); - blockExecutionContextMock.getVersion.returns(version); - blockExecutionContextMock.getRound.returns(42); - blockExecutionContextMock.getLastCommitInfo.returns({ - quorumHash: Buffer.alloc(32, 1), - blockSignature: Buffer.alloc(32, 1), - }); - - identityRepositoryMock = { - proveMany: this.sinon.stub().resolves(new StorageResult(Buffer.from([1]))), - }; - dataContractRepositoryMock = { - proveMany: this.sinon.stub().resolves(new StorageResult(Buffer.from([1]))), - }; - - documentRepository = { - proveManyDocumentsFromDifferentContracts: this.sinon.stub().resolves( - new StorageResult(Buffer.from([1])), - ), - }; - - getProofsQueryHandler = getProofsQueryHandlerFactory( - blockExecutionContextMock, - identityRepositoryMock, - dataContractRepositoryMock, - documentRepository, - ); - - dataContractData = { - id: dataContract.getId(), - }; - identityData = { - id: identity.getId(), - }; - documentsData = documents.map((doc) => ({ - documentId: doc.getId(), - dataContractId: doc.getDataContractId(), - type: doc.getType(), - })); - }); - - it('should return proof for passed data contract ids', async () => { - const expectedProof = { - quorumHash: Buffer.alloc(32, 1), - signature: Buffer.alloc(32, 1), - merkleProof: Buffer.from([1]), - round: 42, - }; - - const result = await getProofsQueryHandler({}, { - dataContractIds: [dataContractData.id], - identityIds: [identityData.id], - documents: documentsData, - }); - - const expectedResult = new ResponseQuery({ - value: cbor.encode( - { - documentsProof: expectedProof, - identitiesProof: expectedProof, - dataContractsProof: expectedProof, - metadata: { - height: 42, - coreChainLockedHeight: 41, - timeMs, - protocolVersion: 1, - }, - }, - ), - }); - - expect(result).to.be.deep.equal(expectedResult); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.spec.js deleted file mode 100644 index 9d4571ea4a4..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory.spec.js +++ /dev/null @@ -1,135 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetIdentitiesByPublicKeyHashesResponse, - Proof, - }, -} = require('@dashevo/dapi-grpc'); - -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); - -const identitiesByPublicKeyHashesQueryHandlerFactory = require( - '../../../../../lib/abci/handlers/query/identitiesByPublicKeyHashesQueryHandlerFactory', -); -const InvalidArgumentAbciError = require('../../../../../lib/abci/errors/InvalidArgumentAbciError'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('identitiesByPublicKeyHashesQueryHandlerFactory', () => { - let identitiesByPublicKeyHashesQueryHandler; - let identityRepositoryMock; - let publicKeyHashes; - let identities; - let maxIdentitiesPerRequest; - let createQueryResponseMock; - let responseMock; - let params; - let data; - - beforeEach(function beforeEach() { - identityRepositoryMock = { - proveManyByPublicKeyHashes: this.sinon.stub(), - fetchManyByPublicKeyHashes: this.sinon.stub(), - }; - - maxIdentitiesPerRequest = 5; - - createQueryResponseMock = this.sinon.stub(); - - responseMock = new GetIdentitiesByPublicKeyHashesResponse(); - responseMock.setProof(new Proof()); - - createQueryResponseMock.returns(responseMock); - - identitiesByPublicKeyHashesQueryHandler = identitiesByPublicKeyHashesQueryHandlerFactory( - identityRepositoryMock, - maxIdentitiesPerRequest, - createQueryResponseMock, - ); - - publicKeyHashes = [ - Buffer.from('784ca12495d2e61f992db9e55d1f9599b0cf1328', 'hex'), - Buffer.from('784ca12495d2e61f992db9e55d1f9599b0cf1329', 'hex'), - Buffer.from('784ca12495d2e61f992db9e55d1f9599b0cf1330', 'hex'), - ]; - - identities = [ - getIdentityFixture(), - getIdentityFixture(), - ]; - - identityRepositoryMock - .fetchManyByPublicKeyHashes.resolves( - new StorageResult([identities[0], identities[1]]), - ); - - params = {}; - data = { publicKeyHashes }; - }); - - it('should throw an error if maximum requested items exceeded', async () => { - maxIdentitiesPerRequest = 1; - - identitiesByPublicKeyHashesQueryHandler = identitiesByPublicKeyHashesQueryHandlerFactory( - identityRepositoryMock, - maxIdentitiesPerRequest, - createQueryResponseMock, - ); - - try { - await identitiesByPublicKeyHashesQueryHandler(params, data, {}); - - expect.fail('Error was not thrown'); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidArgumentAbciError); - expect(e.getData()).to.deep.equal({ - maxIdentitiesPerRequest, - }); - } - }); - - it('should return identities', async () => { - params = publicKeyHashes; - - const result = await identitiesByPublicKeyHashesQueryHandler(params, data, {}); - - expect(identityRepositoryMock.fetchManyByPublicKeyHashes).to.be.calledOnceWithExactly( - publicKeyHashes, - ); - - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); - - it('should return proof if it was requested', async () => { - // const proof = { - // rootTreeProof: Buffer.from('0100000001f0faf5f55674905a68eba1be2f946e667c1cb5010101', - // 'hex'), - // storeTreeProof: Buffer.from('03046b657931060076616c75653103046b657932060076616c75653210', - // 'hex'), - // }; - - const proof = Buffer.alloc(20, 1); - - identityRepositoryMock.proveManyByPublicKeyHashes.resolves( - new StorageResult(proof), - ); - - const result = await identitiesByPublicKeyHashesQueryHandler(params, data, { prove: true }); - - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - - expect(identityRepositoryMock.proveManyByPublicKeyHashes).to.be.calledOnceWithExactly( - data.publicKeyHashes, - ); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/identityQueryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/identityQueryHandlerFactory.spec.js deleted file mode 100644 index d0e9167fee5..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/identityQueryHandlerFactory.spec.js +++ /dev/null @@ -1,112 +0,0 @@ -const { - tendermint: { - abci: { - ResponseQuery, - }, - }, -} = require('@dashevo/abci/types'); - -const { - v0: { - GetIdentityResponse, - Proof, - }, -} = require('@dashevo/dapi-grpc'); - -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); - -const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); -const identityQueryHandlerFactory = require('../../../../../lib/abci/handlers/query/identityQueryHandlerFactory'); -const NotFoundAbciError = require('../../../../../lib/abci/errors/NotFoundAbciError'); -const StorageResult = require('../../../../../lib/storage/StorageResult'); - -describe('identityQueryHandlerFactory', () => { - let identityQueryHandler; - let identityRepositoryMock; - let identity; - let params; - let data; - let createQueryResponseMock; - let responseMock; - - beforeEach(function beforeEach() { - identityRepositoryMock = { - fetch: this.sinon.stub(), - prove: this.sinon.stub(), - }; - - createQueryResponseMock = this.sinon.stub(); - - responseMock = new GetIdentityResponse(); - responseMock.setProof(new Proof()); - - createQueryResponseMock.returns(responseMock); - - identityQueryHandler = identityQueryHandlerFactory( - identityRepositoryMock, - createQueryResponseMock, - ); - - identity = getIdentityFixture(); - - params = {}; - data = { - id: identity.getId(), - }; - }); - - it('should return serialized identity', async () => { - identityRepositoryMock.fetch.resolves( - new StorageResult(identity), - ); - - const result = await identityQueryHandler(params, data, {}); - - expect(identityRepositoryMock.fetch).to.be.calledOnceWith(data.id); - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); - - it('should throw NotFoundAbciError if identity not found', async () => { - identityRepositoryMock.fetch.resolves( - new StorageResult(null), - ); - - try { - await identityQueryHandler(params, data, {}); - - expect.fail('should throw NotFoundAbciError'); - } catch (e) { - expect(e).to.be.an.instanceof(NotFoundAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.NOT_FOUND); - expect(e.message).to.equal('Identity not found'); - expect(identityRepositoryMock.fetch).to.be.calledOnceWith(data.id); - } - }); - - it('should return proof if it was requested', async () => { - // const proof = { - // rootTreeProof: Buffer.from('0100000001f0faf5f55674905a68eba1be2f946e667c1cb5010101', - // 'hex'), - // storeTreeProof: Buffer.from('03046b657931060076616c75653103046b657932060076616c75653210', - // 'hex'), - // }; - const proof = Buffer.alloc(20, 1); - - identityRepositoryMock.fetch.resolves( - new StorageResult(null), - ); - identityRepositoryMock.prove.resolves( - new StorageResult(proof), - ); - - const result = await identityQueryHandler(params, data, { prove: true }); - - expect(identityRepositoryMock.fetch).to.not.be.called(); - expect(identityRepositoryMock.prove).to.be.calledOnceWith(data.id); - expect(result).to.be.an.instanceof(ResponseQuery); - expect(result.code).to.equal(0); - expect(result.value).to.deep.equal(responseMock.serializeBinary()); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/query/response/createQueryResponseFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/query/response/createQueryResponseFactory.spec.js deleted file mode 100644 index e87bfa35555..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/query/response/createQueryResponseFactory.spec.js +++ /dev/null @@ -1,77 +0,0 @@ -const { - v0: { - GetDataContractResponse, - }, -} = require('@dashevo/dapi-grpc'); - -const BlockExecutionContextMock = require('../../../../../../lib/test/mock/BlockExecutionContextMock'); -const createQueryResponseFactory = require('../../../../../../lib/abci/handlers/query/response/createQueryResponseFactory'); - -describe('createQueryResponseFactory', () => { - let createQueryResponse; - let metadata; - let lastCommitInfo; - let blockExecutionContextMock; - let timeMs; - - beforeEach(function beforeEach() { - const version = { - app: 1, - }; - - timeMs = Date.now(); - - lastCommitInfo = { - quorumHash: Buffer.alloc(12).fill(1), - blockSignature: Buffer.alloc(12).fill(2), - }; - - metadata = { - height: 1, - coreChainLockedHeight: 1, - timeMs, - protocolVersion: version.app, - }; - - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - blockExecutionContextMock.getHeight.returns(metadata.height); - blockExecutionContextMock.getCoreChainLockedHeight.returns(metadata.coreChainLockedHeight); - blockExecutionContextMock.getTimeMs.returns(timeMs); - blockExecutionContextMock.getVersion.returns(version); - blockExecutionContextMock.getLastCommitInfo.returns(lastCommitInfo); - blockExecutionContextMock.isEmpty.returns(false); - blockExecutionContextMock.getRound.returns(42); - - createQueryResponse = createQueryResponseFactory( - blockExecutionContextMock, - ); - }); - - it('should create a response', () => { - const response = createQueryResponse(GetDataContractResponse); - - response.serializeBinary(); - - expect(response).to.be.instanceOf(GetDataContractResponse); - expect(response.getMetadata().toObject()).to.deep.equal(metadata); - expect(response.getProof()).to.undefined(); - }); - - it('should create a response with proof if requested', () => { - const response = createQueryResponse(GetDataContractResponse, true); - - response.serializeBinary(); - - expect(response).to.be.instanceOf(GetDataContractResponse); - - expect(response.getMetadata().toObject()).to.deep.equal(metadata); - - expect(response.getProof().toObject()).to.deep.equal({ - quorumHash: lastCommitInfo.quorumHash.toString('base64'), - signature: lastCommitInfo.blockSignature.toString('base64'), - merkleProof: '', - round: 42, - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/queryHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/queryHandlerFactory.spec.js deleted file mode 100644 index bac844658ee..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/queryHandlerFactory.spec.js +++ /dev/null @@ -1,129 +0,0 @@ -const cbor = require('cbor'); - -const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); -const queryHandlerFactory = require('../../../../lib/abci/handlers/queryHandlerFactory'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); -const InvalidArgumentAbciError = require('../../../../lib/abci/errors/InvalidArgumentAbciError'); - -describe('queryHandlerFactory', () => { - let queryHandler; - let queryHandlerRouterMock; - let sanitizeUrlMock; - let request; - let routeMock; - let loggerMock; - let createContextLoggerMock; - - beforeEach(function beforeEach() { - request = { - path: '/identity', - data: cbor.encode(Buffer.from('data')), - }; - - loggerMock = new LoggerMock(this.sinon); - - sanitizeUrlMock = this.sinon.stub(); - - routeMock = { - handler: this.sinon.stub(), - params: 'params', - }; - - queryHandlerRouterMock = { - find: this.sinon.stub().returns(routeMock), - }; - - createContextLoggerMock = this.sinon.stub(); - - queryHandler = queryHandlerFactory( - queryHandlerRouterMock, - sanitizeUrlMock, - loggerMock, - createContextLoggerMock, - ); - }); - - it('should throw InvalidArgumentAbciError if route was not found', async () => { - const sanitizedUrl = 'sanitizedUrl'; - - sanitizeUrlMock.returns(sanitizedUrl); - queryHandlerRouterMock.find.returns(false); - - try { - await queryHandler(request); - - expect.fail('should throw InvalidArgumentAbciError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidArgumentAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - - expect(sanitizeUrlMock).to.be.calledOnceWith(request.path); - expect(queryHandlerRouterMock.find).to.be.calledOnceWith('GET', sanitizedUrl); - expect(routeMock.handler).to.be.not.called(); - } - }); - - it('should throw InvalidArgumentAbciError if fail to decode request data', async () => { - const sanitizedUrl = 'sanitizedUrl'; - - sanitizeUrlMock.returns(sanitizedUrl); - - request.data = Buffer.from('bb'); - - try { - await queryHandler(request); - - expect.fail('should throw InvalidArgumentAbciError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidArgumentAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - - expect(sanitizeUrlMock).to.be.calledOnceWith(request.path); - expect(queryHandlerRouterMock.find).to.be.calledOnceWith('GET', sanitizedUrl); - expect(routeMock.handler).to.be.not.called(); - } - }); - - it('should throw InvalidArgumentAbciError on invalid request data', async () => { - const sanitizedUrl = 'sanitizedUrl'; - - sanitizeUrlMock.returns(sanitizedUrl); - - request.data = cbor.encode(null); - - try { - await queryHandler(request); - - expect.fail('should throw InvalidArgumentAbciError'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidArgumentAbciError); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - - expect(sanitizeUrlMock).to.be.calledOnceWith(request.path); - expect(queryHandlerRouterMock.find).to.be.calledOnceWith('GET', sanitizedUrl); - expect(routeMock.handler).to.be.not.called(); - } - }); - - it('should call route handler without data'); - - it('should call route handler and return response', async () => { - const data = 'some data'; - const encodedData = cbor.decode(Buffer.from(request.data)); - const sanitizedUrl = 'sanitizedUrl'; - - sanitizeUrlMock.returns(sanitizedUrl); - routeMock.handler.resolves(data); - queryHandlerRouterMock.find.returns(routeMock); - - const result = await queryHandler(request); - - expect(sanitizeUrlMock).to.be.calledOnceWith(request.path); - expect(queryHandlerRouterMock.find).to.be.calledOnceWith('GET', sanitizedUrl); - expect(routeMock.handler).to.be.calledOnceWith(routeMock.params, encodedData, request); - expect(result).to.equal(data); - expect(createContextLoggerMock).to.be.calledOnceWithExactly(loggerMock, { - abciMethod: 'query', - }); - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/stateTransition/unserializeStateTransitionFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/stateTransition/unserializeStateTransitionFactory.spec.js deleted file mode 100644 index d582ded796f..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/stateTransition/unserializeStateTransitionFactory.spec.js +++ /dev/null @@ -1,204 +0,0 @@ -const getIdentityCreateTransitionFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityCreateTransitionFixture'); - -const InvalidStateTransitionTypeError = require('@dashevo/dpp/lib/errors/consensus/basic/stateTransition/InvalidStateTransitionTypeError'); -const InvalidStateTransitionError = require('@dashevo/dpp/lib/stateTransition/errors/InvalidStateTransitionError'); -const BalanceNotEnoughError = require('@dashevo/dpp/lib/errors/consensus/fee/BalanceIsNotEnoughError'); -const ValidatorResult = require('@dashevo/dpp/lib/validation/ValidationResult'); - -const GrpcErrorCodes = require('@dashevo/grpc-common/lib/server/error/GrpcErrorCodes'); -const IdentityNotFoundError = require('@dashevo/dpp/lib/errors/consensus/signature/IdentityNotFoundError'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const unserializeStateTransitionFactory = require('../../../../../lib/abci/handlers/stateTransition/unserializeStateTransitionFactory'); -const LoggerMock = require('../../../../../lib/test/mock/LoggerMock'); -const DPPValidationAbciError = require('../../../../../lib/abci/errors/DPPValidationAbciError'); -const InvalidArgumentAbciError = require('../../../../../lib/abci/errors/InvalidArgumentAbciError'); - -describe('unserializeStateTransitionFactory', () => { - let unserializeStateTransition; - let stateTransitionFixture; - let dppMock; - let noopLoggerMock; - let stateTransition; - - beforeEach(function beforeEach() { - stateTransition = getIdentityCreateTransitionFixture(); - stateTransitionFixture = stateTransition.toBuffer(); - - dppMock = { - dispose: this.sinon.stub(), - stateTransition: { - createFromBuffer: this.sinon.stub(), - validateFee: this.sinon.stub(), - validateSignature: this.sinon.stub(), - validateState: this.sinon.stub(), - apply: this.sinon.stub(), - }, - }; - - dppMock.stateTransition.validateSignature.resolves(new ValidatorResult()); - - noopLoggerMock = new LoggerMock(this.sinon); - - unserializeStateTransition = unserializeStateTransitionFactory(dppMock, noopLoggerMock); - }); - - it('should throw InvalidArgumentAbciError if State Transition is not specified', async () => { - try { - await unserializeStateTransition(); - - expect.fail('should throw InvalidArgumentAbciError error'); - } catch (e) { - expect(e).to.be.instanceOf(InvalidArgumentAbciError); - expect(e.getMessage()).to.equal('State Transition is not specified'); - expect(e.getCode()).to.equal(GrpcErrorCodes.INVALID_ARGUMENT); - - expect(dppMock.stateTransition.validateFee).to.not.be.called(); - } - }); - - it('should throw InvalidArgumentAbciError if State Transition is invalid', async () => { - const dppError = new InvalidStateTransitionTypeError(-1); - const error = new InvalidStateTransitionError( - [dppError], - stateTransitionFixture, - ); - - dppMock.stateTransition.createFromBuffer.throws(error); - - try { - await unserializeStateTransition(stateTransitionFixture); - - expect.fail('should throw InvalidArgumentAbciError error'); - } catch (e) { - expect(e).to.be.instanceOf(DPPValidationAbciError); - expect(e.getCode()).to.equal(dppError.getCode()); - expect(e.getData()).to.deep.equal({ - arguments: [-1], - }); - - expect(dppMock.stateTransition.createFromBuffer).to.be.calledOnce(); - expect(dppMock.stateTransition.validateFee).to.not.be.called(); - } - }); - - it('should throw the error from createFromBuffer if throws not InvalidStateTransitionError', async () => { - const error = new Error('Custom error'); - dppMock.stateTransition.createFromBuffer.throws(error); - - try { - await unserializeStateTransition(stateTransitionFixture); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.equal(error); - - expect(dppMock.stateTransition.createFromBuffer).to.be.calledOnce(); - expect(dppMock.stateTransition.validateFee).to.not.be.called(); - } - }); - - it('should throw InsufficientFundsError in case if identity has not enough credits', async () => { - const balance = 1000; - const fee = 1; - const error = new BalanceNotEnoughError(balance, fee); - - dppMock.stateTransition.validateFee.resolves( - new ValidatorResult([error]), - ); - - dppMock.stateTransition.createFromBuffer.resolves(stateTransition); - - try { - await unserializeStateTransition(stateTransitionFixture); - - expect.fail('should throw an InsufficientFundsError'); - } catch (e) { - expect(e).to.be.instanceOf(DPPValidationAbciError); - expect(e.getCode()).to.equal(error.getCode()); - expect(e.getData()).to.deep.equal({ - arguments: [balance, fee], - }); - - expect(dppMock.stateTransition.createFromBuffer).to.be.calledOnce(); - expect(dppMock.stateTransition.validateFee).to.be.calledOnce(); - } - }); - - it('should return invalid result if validateSignature failed', async () => { - const identity = getIdentityFixture(); - const error = new IdentityNotFoundError(identity.getId()); - - dppMock.stateTransition.validateSignature.resolves( - new ValidatorResult([error]), - ); - - try { - await unserializeStateTransition(stateTransitionFixture); - - expect.fail('should throw an InsufficientFundsError'); - } catch (e) { - expect(e).to.be.instanceOf(DPPValidationAbciError); - expect(e.getCode()).to.equal(error.getCode()); - expect(e.getData()).to.deep.equal({ - arguments: [identity.getId()], - }); - - expect(dppMock.stateTransition.createFromBuffer).to.be.calledOnce(); - expect(dppMock.stateTransition.validateFee).to.have.not.been.called(); - } - }); - - it('should return stateTransition', async () => { - dppMock.stateTransition.createFromBuffer.resolves(stateTransition); - - dppMock.stateTransition.validateFee.resolves(new ValidatorResult()); - - const result = await unserializeStateTransition(stateTransitionFixture); - - expect(result).to.deep.equal(stateTransition); - - // TODO: Enable fee validation when RS Drive is ready - // expect(dppMock.stateTransition.validateFee).to.be.calledOnceWith(stateTransition); - // expect(dppMock.stateTransition.validateState).to.be.calledOnceWithExactly(stateTransition); - // expect(dppMock.stateTransition.apply).to.be.calledOnceWithExactly(stateTransition); - }); - - it('should use provided logger', async function it() { - const loggerMock = new LoggerMock(this.sinon); - - const balance = 1000; - const fee = 1000; - const error = new BalanceNotEnoughError(balance, fee); - - dppMock.stateTransition.createFromBuffer.resolves(stateTransition); - - dppMock.stateTransition.validateFee.resolves( - new ValidatorResult([error]), - ); - - try { - await unserializeStateTransition(stateTransitionFixture, { logger: loggerMock }); - - expect.fail('should throw an InsufficientFundsError'); - } catch (e) { - expect(e).to.be.instanceOf(DPPValidationAbciError); - expect(e.getCode()).to.equal(error.getCode()); - expect(e.getData()).to.deep.equal({ - arguments: [balance, fee], - }); - - expect(dppMock.stateTransition.createFromBuffer).to.be.calledOnce(); - expect(dppMock.stateTransition.validateFee).to.be.calledOnce(); - - expect(noopLoggerMock.info).to.not.have.been.called(); - expect(noopLoggerMock.debug).to.not.have.been.called(); - - expect(loggerMock.info).to.have.been.calledOnceWithExactly( - 'Insufficient funds to process state transition', - ); - expect(loggerMock.debug).to.have.been.calledOnceWithExactly({ - consensusError: error, - }); - } - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/validator/createValidatorSetUpdate.spec.js b/packages/js-drive/test/unit/abci/handlers/validator/createValidatorSetUpdate.spec.js deleted file mode 100644 index 30c170d277f..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/validator/createValidatorSetUpdate.spec.js +++ /dev/null @@ -1,57 +0,0 @@ -const { - tendermint: { - abci: { - ValidatorSetUpdate, - }, - }, -} = require('@dashevo/abci/types'); -const { expect } = require('chai'); - -const createValidatorSetUpdate = require('../../../../../lib/abci/handlers/validator/createValidatorSetUpdate'); -const ValidatorNetworkInfo = require('../../../../../lib/validator/ValidatorNetworkInfo'); - -describe('createValidatorSetUpdate', () => { - let validatorSetMock; - let validatorMock; - let quorumHash; - let quorumPublicKey; - - beforeEach(function beforeEach() { - validatorMock = { - getPublicKeyShare: this.sinon.stub(), - getVotingPower: this.sinon.stub(), - getProTxHash: this.sinon.stub(), - getNetworkInfo: this.sinon.stub(), - }; - - validatorMock.getVotingPower.returns(Buffer.alloc(2, 32)); - validatorMock.getProTxHash.returns(Buffer.alloc(3, 32)); - validatorMock.getNetworkInfo.returns(new ValidatorNetworkInfo('192.168.65.2', 26656)); - - validatorSetMock = { - getValidators: this.sinon.stub(), - getQuorum: this.sinon.stub(), - }; - - quorumHash = Buffer.alloc(1, 32).toString('hex'); - quorumPublicKey = 'a7e75af9dd4d868a41ad2f5a5b021d653e31084261724fb40ae2f1b1c31c778d3b9464502d599cf6720723ec5c68b59d'; - - validatorMock.getPublicKeyShare.returns( - Buffer.from(quorumPublicKey, 'hex'), - ); - - validatorSetMock.getValidators.returns([validatorMock]); - validatorSetMock.getQuorum.returns({ - quorumHash, - quorumPublicKey, - }); - }); - - it('should create ValidatorSetUpdate object from specified ValidatorSet instance', () => { - const result = createValidatorSetUpdate(validatorSetMock); - - expect(result).to.be.an.instanceOf(ValidatorSetUpdate); - - // TODO: check something else? - }); -}); diff --git a/packages/js-drive/test/unit/abci/handlers/verifyVoteExtensionHandlerFactory.spec.js b/packages/js-drive/test/unit/abci/handlers/verifyVoteExtensionHandlerFactory.spec.js deleted file mode 100644 index ab558ad9639..00000000000 --- a/packages/js-drive/test/unit/abci/handlers/verifyVoteExtensionHandlerFactory.spec.js +++ /dev/null @@ -1,98 +0,0 @@ -const { - tendermint: { - abci: { - ResponseVerifyVoteExtension, - }, - types: { - VoteExtensionType, - }, - }, -} = require('@dashevo/abci/types'); -const verifyVoteExtensionHandlerFactory = require('../../../../lib/abci/handlers/verifyVoteExtensionHandlerFactory'); -const BlockExecutionContextMock = require('../../../../lib/test/mock/BlockExecutionContextMock'); -const LoggerMock = require('../../../../lib/test/mock/LoggerMock'); - -describe('verifyVoteExtensionHandlerFactory', () => { - let verifyVoteExtensionHandler; - let proposalBlockExecutionContextMock; - let unsignedWithdrawalTransactionsMapMock; - - beforeEach(function beforeEach() { - proposalBlockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - const loggerMock = new LoggerMock(this.sinon); - proposalBlockExecutionContextMock.getContextLogger.returns(loggerMock); - - unsignedWithdrawalTransactionsMapMock = {}; - proposalBlockExecutionContextMock.getWithdrawalTransactionsMap.returns( - unsignedWithdrawalTransactionsMapMock, - ); - - verifyVoteExtensionHandler = verifyVoteExtensionHandlerFactory( - proposalBlockExecutionContextMock, - ); - }); - - it('should return ResponseVerifyVoteExtension with REJECT status if vote extensions length not match', async () => { - const voteExtensions = [ - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 1) }, - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 2) }, - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 3) }, - ]; - - const unsignedWithdrawalTransactionsMap = { - [Buffer.alloc(32, 1).toString('hex')]: undefined, - [Buffer.alloc(32, 2).toString('hex')]: undefined, - }; - - proposalBlockExecutionContextMock.getWithdrawalTransactionsMap.returns( - unsignedWithdrawalTransactionsMap, - ); - - const result = await verifyVoteExtensionHandler({ voteExtensions }); - - expect(result).to.be.an.instanceOf(ResponseVerifyVoteExtension); - expect(result.status).to.equal(2); - }); - - it('should return ResponseVerifyVoteExtension with REJECT status if vote extension is missing', async () => { - const voteExtensions = [ - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 1) }, - ]; - - const unsignedWithdrawalTransactionsMap = { - [Buffer.alloc(32, 1).toString('hex')]: undefined, - [Buffer.alloc(32, 2).toString('hex')]: undefined, - }; - - proposalBlockExecutionContextMock.getWithdrawalTransactionsMap.returns( - unsignedWithdrawalTransactionsMap, - ); - - const result = await verifyVoteExtensionHandler({ voteExtensions }); - - expect(result).to.be.an.instanceOf(ResponseVerifyVoteExtension); - expect(result.status).to.equal(2); - }); - - it('should return ACCEPT if everything is fine', async () => { - const voteExtensions = [ - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 1) }, - { type: VoteExtensionType.THRESHOLD_RECOVER, extension: Buffer.alloc(32, 2) }, - ]; - - const unsignedWithdrawalTransactionsMap = { - [Buffer.alloc(32, 1).toString('hex')]: undefined, - [Buffer.alloc(32, 2).toString('hex')]: undefined, - }; - - proposalBlockExecutionContextMock.getWithdrawalTransactionsMap.returns( - unsignedWithdrawalTransactionsMap, - ); - - const result = await verifyVoteExtensionHandler({ voteExtensions }); - - expect(result).to.be.an.instanceOf(ResponseVerifyVoteExtension); - expect(result.status).to.equal(1); - }); -}); diff --git a/packages/js-drive/test/unit/blockExecution/BlockExecutionContext.spec.js b/packages/js-drive/test/unit/blockExecution/BlockExecutionContext.spec.js deleted file mode 100644 index 96bb1b8fd34..00000000000 --- a/packages/js-drive/test/unit/blockExecution/BlockExecutionContext.spec.js +++ /dev/null @@ -1,427 +0,0 @@ -const { - tendermint: { - abci: { - CommitInfo, - }, - version: { - Consensus, - }, - }, -} = require('@dashevo/abci/types'); - -const Long = require('long'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const BlockExecutionContext = require('../../../lib/blockExecution/BlockExecutionContext'); -const getBlockExecutionContextObjectFixture = require('../../../lib/test/fixtures/getBlockExecutionContextObjectFixture'); - -describe('BlockExecutionContext', () => { - let blockExecutionContext; - let dataContract; - let lastCommitInfo; - let logger; - let plainObject; - let height; - let coreChainLockedHeight; - let version; - let epochInfo; - let timeMs; - let prepareProposalResult; - let proposedAppVersion; - - beforeEach(() => { - blockExecutionContext = new BlockExecutionContext(); - dataContract = getDataContractFixture(); - delete dataContract.entropy; - - plainObject = getBlockExecutionContextObjectFixture(dataContract); - - lastCommitInfo = CommitInfo.fromObject(plainObject.lastCommitInfo); - - logger = plainObject.contextLogger; - height = Long.fromNumber(plainObject.height); - proposedAppVersion = Long.fromNumber(plainObject.proposedAppVersion); - coreChainLockedHeight = plainObject.coreChainLockedHeight; - version = Consensus.fromObject(plainObject.version); - epochInfo = plainObject.epochInfo; - timeMs = plainObject.timeMs; - prepareProposalResult = plainObject.prepareProposalResult; - }); - - describe('#addDataContract', () => { - it('should add a Data Contract', async () => { - expect(blockExecutionContext.getDataContracts()).to.have.lengthOf(0); - - blockExecutionContext.addDataContract(dataContract); - const contracts = blockExecutionContext.getDataContracts(); - - expect(contracts).to.have.lengthOf(1); - expect(contracts[0]).to.deep.equal(dataContract); - }); - }); - - describe('#hasDataContract', () => { - it('should respond with false if data contract with specified ID is not present', async () => { - const result = blockExecutionContext.hasDataContract(dataContract.getId()); - - expect(result).to.be.false(); - }); - - it('should respond with true if data contract with specified ID is present', async () => { - blockExecutionContext.addDataContract(dataContract); - - const result = blockExecutionContext.hasDataContract(dataContract.getId()); - - expect(result).to.be.true(); - }); - }); - - describe('#getDataContracts', () => { - it('should get data contracts', async () => { - blockExecutionContext.addDataContract(dataContract); - blockExecutionContext.addDataContract(dataContract); - - const contracts = blockExecutionContext.getDataContracts(); - - expect(contracts).to.have.lengthOf(2); - expect(contracts[0]).to.deep.equal(dataContract); - expect(contracts[1]).to.deep.equal(dataContract); - }); - }); - - describe('#reset', () => { - it('should reset state', () => { - blockExecutionContext.addDataContract(dataContract); - - expect(blockExecutionContext.getDataContracts()).to.have.lengthOf(1); - - blockExecutionContext.reset(); - - expect(blockExecutionContext.getDataContracts()).to.have.lengthOf(0); - - expect(blockExecutionContext.getHeight()).to.be.null(); - expect(blockExecutionContext.getCoreChainLockedHeight()).to.be.null(); - expect(blockExecutionContext.getVersion()).to.be.null(); - expect(blockExecutionContext.getTimeMs()).to.be.null(); - expect(blockExecutionContext.getLastCommitInfo()).to.be.null(); - expect(blockExecutionContext.getProposedAppVersion()).to.be.null(); - expect(blockExecutionContext.getWithdrawalTransactionsMap()).to.deep.equal({}); - }); - }); - - describe('#setCoreChainLockedHeight', () => { - it('should set coreChainLockedHeight', async () => { - const result = blockExecutionContext.setCoreChainLockedHeight(coreChainLockedHeight); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.coreChainLockedHeight).to.deep.equal(coreChainLockedHeight); - }); - }); - - describe('#getCoreChainLockedHeight', () => { - it('should get coreChainLockedHeight', async () => { - blockExecutionContext.coreChainLockedHeight = coreChainLockedHeight; - - expect(blockExecutionContext.getCoreChainLockedHeight()).to.deep.equal(coreChainLockedHeight); - }); - }); - - describe('#setHeight', () => { - it('should set height', async () => { - const result = blockExecutionContext.setHeight(height); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.height).to.deep.equal(height); - }); - }); - - describe('#getHeight', () => { - it('should get height', async () => { - blockExecutionContext.height = height; - - expect(blockExecutionContext.getHeight()).to.deep.equal(height); - }); - }); - - describe('#setProposedAppVersion', () => { - it('should set proposed app version', async () => { - const result = blockExecutionContext.setProposedAppVersion(proposedAppVersion); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.proposedAppVersion).to.deep.equal(proposedAppVersion); - }); - }); - - describe('#getProposedAppVersion', () => { - it('should get proposed app version', async () => { - blockExecutionContext.proposedAppVersion = proposedAppVersion; - - expect(blockExecutionContext.getProposedAppVersion()).to.deep.equal(proposedAppVersion); - }); - }); - - describe('#setVersion', () => { - it('should set version', async () => { - const result = blockExecutionContext.setVersion(version); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.version).to.deep.equal(version); - }); - }); - - describe('#getVersion', () => { - it('should get version', async () => { - blockExecutionContext.version = version; - - expect(blockExecutionContext.getVersion()).to.deep.equal(version); - }); - }); - - describe('#setLastCommitInfo', () => { - it('should set lastCommitInfo', async () => { - const result = blockExecutionContext.setLastCommitInfo(lastCommitInfo); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.lastCommitInfo).to.deep.equal(lastCommitInfo); - }); - }); - - describe('#getLastCommitInfo', () => { - it('should get lastCommitInfo', async () => { - blockExecutionContext.lastCommitInfo = lastCommitInfo; - - expect(blockExecutionContext.getLastCommitInfo()).to.deep.equal(lastCommitInfo); - }); - }); - - describe('#setWithdrawalTransactionsMap', () => { - it('should set withdrawalTransactionsMap', async () => { - const result = blockExecutionContext.setWithdrawalTransactionsMap( - plainObject.withdrawalTransactionsMap, - ); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.withdrawalTransactionsMap).to.deep.equal( - plainObject.withdrawalTransactionsMap, - ); - }); - }); - - describe('#getWithdrawalTransactionsMap', () => { - it('should get withdrawalTransactionsMap', async () => { - blockExecutionContext.withdrawalTransactionsMap = plainObject.withdrawalTransactionsMap; - - expect(blockExecutionContext.getWithdrawalTransactionsMap()).to.deep.equal( - plainObject.withdrawalTransactionsMap, - ); - }); - }); - - describe('#setRound', () => { - it('should set round', async () => { - const result = blockExecutionContext.setRound( - plainObject.round, - ); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.round).to.deep.equal( - plainObject.round, - ); - }); - }); - - describe('#getRound', () => { - it('should get round', async () => { - blockExecutionContext.round = plainObject.round; - - expect(blockExecutionContext.getRound()).to.deep.equal( - plainObject.round, - ); - }); - }); - - describe('#setPrepareProposalResult', () => { - it('should set PrepareProposal result', async () => { - const result = blockExecutionContext.setPrepareProposalResult( - plainObject.prepareProposalResult, - ); - - expect(result).to.equal(blockExecutionContext); - - expect(blockExecutionContext.prepareProposalResult).to.deep.equal( - plainObject.prepareProposalResult, - ); - }); - }); - - describe('#getPrepareProposalResult', () => { - it('should get PrepareProposal result', async () => { - blockExecutionContext.prepareProposalResult = plainObject.prepareProposalResult; - - expect(blockExecutionContext.getPrepareProposalResult()).to.deep.equal( - plainObject.prepareProposalResult, - ); - }); - }); - - describe('#setTimeMs', () => { - it('should set time', async () => { - blockExecutionContext.setTimeMs(timeMs); - - expect(blockExecutionContext.timeMs).to.deep.equal(timeMs); - }); - }); - - describe('#getTimeMs', () => { - it('should get time', async () => { - blockExecutionContext.timeMs = timeMs; - - expect(blockExecutionContext.getTimeMs()).to.deep.equal(timeMs); - }); - }); - - describe('#setEpochInfo', () => { - it('should set epoch info'); - }); - - describe('#getEpochInfo', () => { - it('should return epoch info'); - }); - - describe('#populate', () => { - it('should populate instance from another instance', () => { - const anotherBlockExecutionContext = new BlockExecutionContext(); - - anotherBlockExecutionContext.dataContracts = [dataContract]; - anotherBlockExecutionContext.lastCommitInfo = lastCommitInfo; - anotherBlockExecutionContext.height = height; - anotherBlockExecutionContext.version = version; - anotherBlockExecutionContext.coreChainLockedHeight = coreChainLockedHeight; - anotherBlockExecutionContext.contextLogger = logger; - anotherBlockExecutionContext.withdrawalTransactionsMap = plainObject - .withdrawalTransactionsMap; - anotherBlockExecutionContext.epochInfo = epochInfo; - anotherBlockExecutionContext.timeMs = timeMs; - - blockExecutionContext.populate(anotherBlockExecutionContext); - - expect(blockExecutionContext.dataContracts).to.equal( - anotherBlockExecutionContext.dataContracts, - ); - expect(blockExecutionContext.lastCommitInfo).to.equal( - anotherBlockExecutionContext.lastCommitInfo, - ); - expect(blockExecutionContext.height).to.equal( - anotherBlockExecutionContext.height, - ); - expect(blockExecutionContext.version).to.equal( - anotherBlockExecutionContext.version, - ); - expect(blockExecutionContext.coreChainLockedHeight).to.equal( - anotherBlockExecutionContext.coreChainLockedHeight, - ); - expect(blockExecutionContext.contextLogger).to.equal( - anotherBlockExecutionContext.contextLogger, - ); - expect(blockExecutionContext.withdrawalTransactionsMap).to.equal( - anotherBlockExecutionContext.withdrawalTransactionsMap, - ); - expect(blockExecutionContext.epochInfo).to.equal( - anotherBlockExecutionContext.epochInfo, - ); - expect(blockExecutionContext.timeMs).to.equal( - anotherBlockExecutionContext.timeMs, - ); - }); - }); - - describe('#toObject', () => { - it('should return a plain object', () => { - blockExecutionContext.dataContracts = [dataContract]; - blockExecutionContext.lastCommitInfo = lastCommitInfo; - blockExecutionContext.height = height; - blockExecutionContext.coreChainLockedHeight = coreChainLockedHeight; - blockExecutionContext.version = version; - blockExecutionContext.contextLogger = logger; - blockExecutionContext.epochInfo = epochInfo; - blockExecutionContext.timeMs = timeMs; - blockExecutionContext.withdrawalTransactionsMap = plainObject.withdrawalTransactionsMap; - blockExecutionContext.round = plainObject.round; - blockExecutionContext.prepareProposalResult = plainObject.prepareProposalResult; - blockExecutionContext.proposedAppVersion = proposedAppVersion; - - expect(blockExecutionContext.toObject()).to.deep.equal(plainObject); - }); - - it('should skipContextLogger if the option passed', () => { - blockExecutionContext.dataContracts = [dataContract]; - blockExecutionContext.lastCommitInfo = lastCommitInfo; - blockExecutionContext.height = height; - blockExecutionContext.coreChainLockedHeight = coreChainLockedHeight; - blockExecutionContext.version = version; - blockExecutionContext.contextLogger = logger; - blockExecutionContext.withdrawalTransactionsMap = plainObject.withdrawalTransactionsMap; - blockExecutionContext.round = plainObject.round; - blockExecutionContext.epochInfo = epochInfo; - blockExecutionContext.timeMs = timeMs; - blockExecutionContext.prepareProposalResult = prepareProposalResult; - blockExecutionContext.proposedAppVersion = proposedAppVersion; - - const result = blockExecutionContext.toObject({ skipContextLogger: true }); - - delete plainObject.contextLogger; - - expect(result).to.deep.equal(plainObject); - }); - - it('should skipPrepareProposalResult if the option passed', () => { - blockExecutionContext.dataContracts = [dataContract]; - blockExecutionContext.lastCommitInfo = lastCommitInfo; - blockExecutionContext.height = height; - blockExecutionContext.coreChainLockedHeight = coreChainLockedHeight; - blockExecutionContext.version = version; - blockExecutionContext.contextLogger = logger; - blockExecutionContext.withdrawalTransactionsMap = plainObject.withdrawalTransactionsMap; - blockExecutionContext.round = plainObject.round; - blockExecutionContext.epochInfo = epochInfo; - blockExecutionContext.timeMs = timeMs; - blockExecutionContext.proposedAppVersion = proposedAppVersion; - - const result = blockExecutionContext.toObject({ skipPrepareProposalResult: true }); - - delete plainObject.prepareProposalResult; - - expect(result).to.deep.equal(plainObject); - }); - }); - - describe('#fromObject', () => { - it('should populate instance from a plain object', () => { - blockExecutionContext.fromObject(plainObject); - - if (blockExecutionContext.dataContracts[0].$defs === undefined) { - blockExecutionContext.dataContracts[0].$defs = {}; - } - - expect(blockExecutionContext.dataContracts).to.have.deep.members( - [dataContract], - ); - expect(blockExecutionContext.lastCommitInfo).to.deep.equal(lastCommitInfo); - expect(blockExecutionContext.height).to.deep.equal(height); - expect(blockExecutionContext.version).to.deep.equal(version); - expect(blockExecutionContext.coreChainLockedHeight).to.deep.equal(coreChainLockedHeight); - expect(blockExecutionContext.contextLogger).to.equal(logger); - expect(blockExecutionContext.withdrawalTransactionsMap).to.deep.equal( - plainObject.withdrawalTransactionsMap, - ); - expect(blockExecutionContext.timeMs).to.equal(timeMs); - }); - }); -}); diff --git a/packages/js-drive/test/unit/core/LatestCoreChainLock.spec.js b/packages/js-drive/test/unit/core/LatestCoreChainLock.spec.js deleted file mode 100644 index 2ab24a6db1e..00000000000 --- a/packages/js-drive/test/unit/core/LatestCoreChainLock.spec.js +++ /dev/null @@ -1,44 +0,0 @@ -const LatestCoreChainLock = require('../../../lib/core/LatestCoreChainLock'); - -describe('LatestCoreChainLock', () => { - describe('#constructor', () => { - it('should instantiate', () => { - const latestCoreChainLock = new LatestCoreChainLock(); - expect(latestCoreChainLock.chainLock).to.equal(undefined); - const latestCoreChainLockWithValue = new LatestCoreChainLock('someValue'); - expect(latestCoreChainLockWithValue.chainLock).to.equal('someValue'); - }); - }); - - describe('#update', () => { - it('should update', () => { - const latestCoreChainLock = new LatestCoreChainLock(); - latestCoreChainLock.update('someValue'); - expect(latestCoreChainLock.chainLock).to.equal('someValue'); - }); - - it('should emit updated chainLock', (done) => { - const chainLock = 'someValue'; - const latestCoreChainLock = new LatestCoreChainLock(); - - latestCoreChainLock.on(LatestCoreChainLock.EVENTS.update, (data) => { - expect(data).to.equal(chainLock); - - done(); - }); - - latestCoreChainLock.update(chainLock); - }); - }); - - describe('#getChainLock', () => { - it('should return chainLock', async () => { - const chainLock = 'someValue'; - - const latestCoreChainLock = new LatestCoreChainLock(); - latestCoreChainLock.update(chainLock); - - expect(latestCoreChainLock.getChainLock()).to.equal(chainLock); - }); - }); -}); diff --git a/packages/js-drive/test/unit/core/ensureBlock.spec.js b/packages/js-drive/test/unit/core/ensureBlock.spec.js deleted file mode 100644 index a9b86156f94..00000000000 --- a/packages/js-drive/test/unit/core/ensureBlock.spec.js +++ /dev/null @@ -1,66 +0,0 @@ -const chai = require('chai'); -const chaiAsPromised = require('chai-as-promised'); - -chai.use(chaiAsPromised); -chai.should(); - -const EventEmitter = require('events'); -const ZMQClient = require('../../../lib/core/ZmqClient'); -const ensureBlock = require('../../../lib/core/ensureBlock'); - -describe('ensureBlock', () => { - const hash = '00000'; - const otherHash = '00001'; - const socketClient = new EventEmitter(); - let rpcClient; - - beforeEach(function beforeEach() { - socketClient.subscribe = this.sinon.stub(); - - rpcClient = { - getBlock: this.sinon.stub().resolves(true), - }; - }); - - it('should ensure a block exist before returning promise', async () => { - await ensureBlock(socketClient, rpcClient, hash); - - expect(rpcClient.getBlock).to.be.calledOnceWithExactly(hash); - }); - - it('should wait for block if not found before returning promise', (done) => { - const err = new Error(); - err.code = -5; - err.message = 'Block not found'; - - rpcClient.getBlock.throws(err); - - ensureBlock(socketClient, rpcClient, hash).then(done); - - setImmediate(() => { - socketClient.emit(ZMQClient.TOPICS.hashblock, otherHash); - }); - - setImmediate(() => { - socketClient.emit(ZMQClient.TOPICS.hashblock, hash); - }); - - expect(rpcClient.getBlock).to.be.calledOnceWithExactly(hash); - }); - - it('should throw on unexpected error', async () => { - const err = new Error(); - err.code = -6; - err.message = 'Another error'; - - rpcClient.getBlock.throws(err); - - try { - await ensureBlock(socketClient, rpcClient, hash); - expect.fail('Internal error must be thrown'); - } catch (e) { - expect(e).to.equal(err); - expect(rpcClient.getBlock).to.be.calledOnceWithExactly(hash); - } - }); -}); diff --git a/packages/js-drive/test/unit/core/getRandomQuorumFactory.spec.js b/packages/js-drive/test/unit/core/getRandomQuorumFactory.spec.js deleted file mode 100644 index d75a5c2aea4..00000000000 --- a/packages/js-drive/test/unit/core/getRandomQuorumFactory.spec.js +++ /dev/null @@ -1,196 +0,0 @@ -const { expect } = require('chai'); -const getRandomQuorumFactory = require('../../../lib/core/getRandomQuorumFactory'); - -describe('getRandomQuorumFactory', () => { - let smlMock; - let quorumType; - let getRandomQuorum; - let coreRpcClientMock; - let randomQuorum; - let coreHeight; - - beforeEach(function beforeEach() { - smlMock = { - getQuorumsOfType: this.sinon.stub(), - getQuorum: this.sinon.stub(), - quorumList: [], - blockHash: '0'.repeat(32), - }; - - coreHeight = 690; - - quorumType = 102; - - smlMock.getQuorum.resolves(randomQuorum); - - smlMock.getQuorumsOfType.returns([ - { - quorumHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - validMembersCount: 90, - }, - { - quorumHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - getAllQuorumMembers: 90, - }, - ]); - - const quorumListExtended = { - llmq_test: [ - { - '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c': { - creationHeight: 672, - minedBlockHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - }, - }, - { - '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce': { - creationHeight: 672, - minedBlockHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - }, - }, - ], - llmq_test_instantsend: [ - { - '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c': { - creationHeight: 672, - minedBlockHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - }, - }, - { - '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce': { - creationHeight: 672, - minedBlockHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - }, - }, - ], - llmq_test_v17: [ - { - '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c': { - creationHeight: 672, - minedBlockHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - }, - }, - { - '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce': { - creationHeight: 672, - minedBlockHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - }, - }, - ], - }; - - coreRpcClientMock = { - quorum: this.sinon.stub().resolves({ result: quorumListExtended }), - }; - - getRandomQuorum = getRandomQuorumFactory(coreRpcClientMock); - }); - - it('should return random quorum based on entropy', async () => { - const result = await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect(smlMock.getQuorumsOfType).to.have.been.calledOnceWithExactly(quorumType); - expect(smlMock.getQuorum).to.have.been.calledOnceWithExactly( - quorumType, '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - ); - expect(result).to.equals(randomQuorum); - }); - - it('should throw an error if SML does not contain any quorums', async () => { - smlMock.getQuorumsOfType.returns([]); - - try { - await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect.fail('should throw an error'); - } catch (e) { - expect(e.message).to.be.equal(`SML at block ${'0'.repeat(32)} contains no quorums of any type`); - } - }); - - it('should throw an error if SML contains quorums that differ from the specified quorum type', async () => { - smlMock.getQuorumsOfType.returns([]); - smlMock.quorumList = [{ llmqType: 999 }]; - - try { - await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect.fail('should throw an error'); - } catch (e) { - expect(e.message).to.be.equal(`SML at block ${'0'.repeat(32)} contains no quorums of type ${quorumType}, but contains entries for types 999. Please check the Drive configuration`); - } - }); - - it('should filter quorums by minQuorumMembers', async () => { - smlMock.getQuorumsOfType.returns([ - { - quorumHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - validMembersCount: 90, - }, - { - quorumHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - validMembersCount: 89, - }, - ]); - - const result = await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect(smlMock.getQuorumsOfType).to.have.been.calledOnceWithExactly(quorumType); - expect(smlMock.getQuorum).to.have.been.calledOnceWithExactly( - quorumType, '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - ); - expect(result).to.equals(randomQuorum); - }); - - it('should filter quorums by ttl', async () => { - coreRpcClientMock.quorum.resolves({ - result: { - llmq_test_v17: [ - { - '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c': { - creationHeight: 100, - minedBlockHash: '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - }, - }, - { - '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce': { - creationHeight: 672, - minedBlockHash: '251fae1f7fe89d38c4ce71781685c96291cc3852e9586c8eb6d5a71b73d6285c', - }, - }, - ], - }, - }); - - const result = await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect(smlMock.getQuorumsOfType).to.have.been.calledOnceWithExactly(quorumType); - expect(smlMock.getQuorum).to.have.been.calledOnceWithExactly( - quorumType, '1af5ffbdb862a18b454106b6b99e30bb683fa5bab8278b19a6e91bf742405cce', - ); - - expect(coreRpcClientMock.quorum).to.be.calledOnceWithExactly('listextended', coreHeight); - expect(result).to.equals(randomQuorum); - }); - - it('should choose from all quorums if filtered list is empty', async () => { - smlMock.getQuorumsOfType.returns([ - { - quorumHash: Buffer.alloc(1, 64).toString('hex'), - validMembersCount: 10, - }, - { - quorumHash: Buffer.alloc(1, 32).toString('hex'), - validMembersCount: 10, - }, - ]); - - const result = await getRandomQuorum(smlMock, quorumType, Buffer.alloc(1), coreHeight); - - expect(smlMock.getQuorumsOfType).to.have.been.calledOnceWithExactly(quorumType); - expect(smlMock.getQuorum).to.have.been.calledOnceWithExactly( - quorumType, '20', - ); - expect(result).to.equals(randomQuorum); - }); -}); diff --git a/packages/js-drive/test/unit/core/updateSimplifiedMasternodeListFactory.spec.js b/packages/js-drive/test/unit/core/updateSimplifiedMasternodeListFactory.spec.js deleted file mode 100644 index b058e0743c2..00000000000 --- a/packages/js-drive/test/unit/core/updateSimplifiedMasternodeListFactory.spec.js +++ /dev/null @@ -1,195 +0,0 @@ -const SimplifiedMNListDiff = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListDiff'); -const { expect } = require('chai'); -const updateSimplifiedMasternodeListFactory = require('../../../lib/core/updateSimplifiedMasternodeListFactory'); -const NotEnoughBlocksForValidSMLError = require('../../../lib/core/errors/NotEnoughBlocksForValidSMLError'); -const LoggerMock = require('../../../lib/test/mock/LoggerMock'); - -describe('updateSimplifiedMasternodeListFactory', () => { - let updateSimplifiedMasternodeList; - let coreRpcClientMock; - let network; - let smlMaxListsLimit; - let simplifiedMasternodeListMock; - let rawDiff; - let coreHeight; - - beforeEach(function beforeEach() { - network = 'regtest'; - - rawDiff = { - baseBlockHash: '644bd9dcbc0537026af6d31181570f934d868f121c55513009bb36f509ec816e', - blockHash: '23beac1b700c4a49855a9653e036219384ac2fab7eeba2ec45b3e2d0063d1285', - cbTxMerkleTree: '03000000032f7f142e19bee0c595dac9f900695d1e428a4db70a805fda6c834cfec0de506a0d39baea39dbbaf9827a1f3b8f381a65ebcf4c2ef415025bc4d20afd372e680d12c226f084a6e28e421fbedff22b13aa1191d6a80744d104fa75ede12332467d0107', - cbTx: '03000500010000000000000000000000000000000000000000000000000000000000000000ffffffff0502e9030101ffffffff01a2567a76070000001976a914f713c2fa5ef0e7c48f0d1b3ad2a79150037c72d788ac00000000460200e90300003fdbe53b9a4cd0b62284195cbd4f4c1655ebdd70e9117ed3c0e49c37bfce46060000000000000000000000000000000000000000000000000000000000000000', - deletedMNs: [], - mnList: [ - { - proRegTxHash: 'e57402007ca10454d77437d9c1156b1c4ff8af86d699c08e9a31dbd1dfe3c991', - confirmedHash: '0000000000000000000000000000000000000000000000000000000000000000', - service: '127.0.0.1:20001', - pubKeyOperator: '906d84cb88f532145d8838414f777b971c976ffcf8ccfc57413a13cf2f8a7750a92f9b997a5a741f1afa34d989f4312b', - votingAddress: 'ydC3Qkhq6qc1qgHD8PVSHyAB6t3NYa7aw4', - nType: 0, - isValid: true, - }, - ], - deletedQuorums: [], - newQuorums: [], - merkleRootMNList: '0646cebf379ce4c0d37e11e970ddeb55164c4fbd5c198422b6d04c9a3be5db3f', - merkleRootQuorums: '0000000000000000000000000000000000000000000000000000000000000000', - }; - - coreHeight = 84202; - - coreRpcClientMock = { - protx: this.sinon.stub(), - }; - - coreRpcClientMock.protx.resolves({ - result: rawDiff, - }); - - simplifiedMasternodeListMock = { - applyDiffs: this.sinon.stub(), - reset: this.sinon.stub(), - }; - - smlMaxListsLimit = 2; - - const loggerMock = new LoggerMock(this.sinon); - - updateSimplifiedMasternodeList = updateSimplifiedMasternodeListFactory( - coreRpcClientMock, - simplifiedMasternodeListMock, - smlMaxListsLimit, - network, - loggerMock, - ); - }); - - it('should throw error if not enough blocks for valid SML', async () => { - try { - await updateSimplifiedMasternodeList(smlMaxListsLimit); - - expect.fail('should throw NotEnoughBlocksForValidSMLError'); - } catch (e) { - expect(e).to.be.instanceOf(NotEnoughBlocksForValidSMLError); - expect(e.getBlockHeight()).to.be.equal(smlMaxListsLimit); - } - }); - - it('should obtain 16 latest diffs according to core height on first call', async () => { - const isUpdated = await updateSimplifiedMasternodeList(coreHeight); - - expect(isUpdated).to.be.true(); - - const proTxCallCount = coreHeight - (coreHeight - smlMaxListsLimit) + 1; - - expect(coreRpcClientMock.protx.callCount).to.equal(proTxCallCount); - - expect(coreRpcClientMock.protx.getCall(0).args).to.have.deep.members( - [ - 'diff', - 1, - (coreHeight - smlMaxListsLimit), - true, - ], - ); - - for (let i = 1; i < proTxCallCount; i++) { - expect(coreRpcClientMock.protx.getCall(i).args).to.have.deep.members( - [ - 'diff', - (coreHeight - smlMaxListsLimit) + (i - 1), - (coreHeight - smlMaxListsLimit) + (i - 1) + 1, - true, - ], - ); - } - - const smlDiffs = []; - for (let i = 0; i < proTxCallCount; i++) { - smlDiffs.push(new SimplifiedMNListDiff(rawDiff, network)); - } - - const argsDiffBuffers = simplifiedMasternodeListMock.applyDiffs.getCall(0).args[0].map( - (item) => item.toBuffer(), - ); - - const smlDiffBuffers = smlDiffs.map((item) => item.toBuffer()); - - expect(argsDiffBuffers).to.deep.equal(smlDiffBuffers); - }); - - it('should update diffs since last call and up to passed core height', async () => { - let isUpdated = await updateSimplifiedMasternodeList(coreHeight); - - expect(isUpdated).to.be.true(); - - isUpdated = await updateSimplifiedMasternodeList(coreHeight + 1); - - expect(isUpdated).to.be.true(); - - const proTxCallCount = smlMaxListsLimit + 2; - - expect(coreRpcClientMock.protx.callCount).to.equal(proTxCallCount); - - expect(coreRpcClientMock.protx.getCall(0).args).to.have.deep.members( - [ - 'diff', - 1, - (coreHeight - smlMaxListsLimit), - true, - ], - ); - - for (let i = 1; i < proTxCallCount; i++) { - expect(coreRpcClientMock.protx.getCall(i).args).to.have.deep.members( - [ - 'diff', - (coreHeight - smlMaxListsLimit) + (i - 1), - (coreHeight - smlMaxListsLimit) + (i - 1) + 1, - true, - ], - ); - } - - const simplifiedMNListDiffArray = []; - - for (let i = 0; i < proTxCallCount - 1; i++) { - simplifiedMNListDiffArray.push(new SimplifiedMNListDiff(rawDiff, network)); - } - - const argsDiffsBuffers = simplifiedMasternodeListMock.applyDiffs.getCall(0).args[0].map( - (item) => item.toBuffer(), - ); - - const smlDiffBuffers = simplifiedMNListDiffArray.map((item) => item.toBuffer()); - - expect(argsDiffsBuffers).to.deep.equal(smlDiffBuffers); - }); - - it('should not update more than 16 diffs', async () => { - let isUpdated = await updateSimplifiedMasternodeList(coreHeight); // 3 - - expect(isUpdated).to.be.true(); - - isUpdated = await updateSimplifiedMasternodeList(coreHeight + 10); // 3 - - expect(isUpdated).to.be.true(); - - const proTxCallCount = 3 + 3; - - expect(coreRpcClientMock.protx.callCount).to.equal(proTxCallCount); - }); - - it('should return false if SML was not updated', async () => { - let isUpdated = await updateSimplifiedMasternodeList(coreHeight); - - expect(isUpdated).to.be.true(); - - isUpdated = await updateSimplifiedMasternodeList(coreHeight); - - expect(isUpdated).to.be.false(); - }); -}); diff --git a/packages/js-drive/test/unit/core/waitForChainLockedHeightFactory.spec.js b/packages/js-drive/test/unit/core/waitForChainLockedHeightFactory.spec.js deleted file mode 100644 index 6226680bf53..00000000000 --- a/packages/js-drive/test/unit/core/waitForChainLockedHeightFactory.spec.js +++ /dev/null @@ -1,63 +0,0 @@ -const EventEmitter = require('events'); -const waitForChainLockedHeightFactory = require('../../../lib/core/waitForChainLockedHeightFactory'); -const MissingChainlockError = require('../../../lib/core/errors/MissingChainLockError'); -const LatestCoreChainLock = require('../../../lib/core/LatestCoreChainLock'); - -describe('waitForChainLockedHeightFactory', () => { - let waitForChainLockedHeight; - let latestCoreChainLockMock; - let chainLock; - let coreHeight; - - beforeEach(function beforeEach() { - coreHeight = 84202; - - chainLock = { - height: coreHeight, - signature: '0a43f1c3e5b3e8dbd670bca8d437dc25572f72d8e1e9be673e9ebbb606570307c3e5f5d073f7beb209dd7e0b8f96c751060ab3a7fb69a71d5ccab697b8cfa5a91038a6fecf76b7a827d75d17f01496302942aa5e2c7f4a48246efc8d3941bf6c', - }; - - latestCoreChainLockMock = new EventEmitter(); - latestCoreChainLockMock.getChainLock = this.sinon.stub().returns(chainLock); - - waitForChainLockedHeight = waitForChainLockedHeightFactory( - latestCoreChainLockMock, - ); - }); - - it('should throw MissingChainlockError if chainlock is empty', async () => { - latestCoreChainLockMock.getChainLock.returns(null); - - try { - await waitForChainLockedHeight(coreHeight); - - expect.fail(); - } catch (e) { - expect(e).to.be.an.instanceOf(MissingChainlockError); - } - }); - - it('should resolve promise if existing chainlock on the same height or higher', async () => { - latestCoreChainLockMock.getChainLock.returns(chainLock); - - await waitForChainLockedHeight(coreHeight); - }); - - it('should resolve when chainLock height to be equal or higher', (done) => { - coreHeight = chainLock.height + 1; - - waitForChainLockedHeight(coreHeight) - .then(() => { - expect(latestCoreChainLockMock.getChainLock).to.have.been.calledOnce(); - - done(); - }); - - setImmediate(() => { - latestCoreChainLockMock.emit(LatestCoreChainLock.EVENTS.update, { - ...chainLock, - height: chainLock.height + 1, - }); - }); - }); -}); diff --git a/packages/js-drive/test/unit/core/waitForCoreChainLockSyncFactory.spec.js b/packages/js-drive/test/unit/core/waitForCoreChainLockSyncFactory.spec.js deleted file mode 100644 index d88d7801873..00000000000 --- a/packages/js-drive/test/unit/core/waitForCoreChainLockSyncFactory.spec.js +++ /dev/null @@ -1,86 +0,0 @@ -const EventEmitter = require('events'); -const LatestCoreChainLock = require('../../../lib/core/LatestCoreChainLock'); -const ZMQClient = require('../../../lib/core/ZmqClient'); -const waitForCoreChainLockSyncFactory = require('../../../lib/core/waitForCoreChainLockSyncFactory'); -const LoggerMock = require('../../../lib/test/mock/LoggerMock'); - -describe('waitForCoreChainLockSyncFactory', () => { - let waitForCoreChainLockHandler; - let coreRpcClientMock; - let coreZMQClientMock; - let latestCoreChainLock; - let chainLock; - let rawChainLockSigMessage; - - beforeEach(function beforeEach() { - chainLock = { - blockHash: '0000003df90e1cec3fea6bd17508f653cea093c536199e9d50a05bd69ee23b5d', - height: 3887, - signature: '1770e35c281ebfcf14b8a62071f76146eb0a5ede6fb43543a9c0ccddf3cf87fcdd0a96eea867595bb980dcea13e6283f16744631df895404434c7840f9b3d9c1069790a0459a0d35b7ae353519f5d437ded547f8d65f6c4916e988c842488e7a', - }; - - rawChainLockSigMessage = Buffer.from('00000020fd0ab0fc0fb0cbecb62cf7555aee6a8ce18564a9bbed8b22585d9f8563000000ee131c25019aaee0f1bdde2a5d6eb99ec0b4497e68776f18916951e8ddb6b922dd3be45f62f6011ed18800000103000500010000000000000000000000000000000000000000000000000000000000000000ffffffff05024c0f010bffffffff0200c817a8040000001976a91416b93a3b9168a20605cc3cda62f6135a3baa531a88ac00ac23fc060000001976a91416b93a3b9168a20605cc3cda62f6135a3baa531a88ac000000004602004c0f00003d8e273bf286d48ccba5a87b5adf332ed070a15e4e2d81eeb9ff685373be5656961e0b73ea855fdac9cc530782a7f0a22d25d1eaab4b2068efa647e9da0915d02f0f00005d3be29ed65ba0509d9e1936c593a0ce53f60875d16bea3fec1c0ef93d0000001770e35c281ebfcf14b8a62071f76146eb0a5ede6fb43543a9c0ccddf3cf87fcdd0a96eea867595bb980dcea13e6283f16744631df895404434c7840f9b3d9c1069790a0459a0d35b7ae353519f5d437ded547f8d65f6c4916e988c842488e7a', 'hex'); - - latestCoreChainLock = new LatestCoreChainLock(); - coreRpcClientMock = { - getBestChainLock: this.sinon.stub().resolves({ - result: chainLock, - error: null, - id: 5, - }), - getBlock: this.sinon.stub(), - }; - coreZMQClientMock = new EventEmitter(); - coreZMQClientMock.subscribe = this.sinon.stub(); - - const loggerMock = new LoggerMock(this.sinon); - - waitForCoreChainLockHandler = waitForCoreChainLockSyncFactory( - coreZMQClientMock, - coreRpcClientMock, - latestCoreChainLock, - loggerMock, - ); - }); - - it('should wait for chainlock to be synced', async () => { - expect(latestCoreChainLock.chainLock).to.equal(undefined); - - await waitForCoreChainLockHandler(); - - expect(latestCoreChainLock.chainLock.toJSON()).to.deep.equal(chainLock); - - expect(coreZMQClientMock.subscribe).to.be.calledTwice(); - expect(coreZMQClientMock.subscribe).to.be.calledWith(ZMQClient.TOPICS.rawchainlocksig); - expect(coreZMQClientMock.subscribe).to.be.calledWith(ZMQClient.TOPICS.hashblock); - expect(coreRpcClientMock.getBestChainLock).to.be.calledOnce(); - }); - - it('should handle when no chainlock is found via RPC', (done) => { - expect(latestCoreChainLock.chainLock).to.equal(undefined); - - const err = new Error(); - err.code = -32603; - err.message = 'Chainlock not found'; - - coreRpcClientMock.getBestChainLock.throws(err); - - waitForCoreChainLockHandler() - .then(() => { - expect(latestCoreChainLock.chainLock.toJSON()).to.deep.equal(chainLock); - - expect(coreZMQClientMock.subscribe).to.be.calledTwice(); - expect(coreZMQClientMock.subscribe).to.be.calledWith(ZMQClient.TOPICS.rawchainlocksig); - expect(coreZMQClientMock.subscribe).to.be.calledWith(ZMQClient.TOPICS.hashblock); - expect(coreRpcClientMock.getBestChainLock).to.be.calledOnce(); - done(); - }); - - setImmediate(() => { - coreZMQClientMock.emit( - ZMQClient.TOPICS.rawchainlocksig, - rawChainLockSigMessage, - ); - }); - }); -}); diff --git a/packages/js-drive/test/unit/dpp/CachedStateRepositoryDecorator.spec.js b/packages/js-drive/test/unit/dpp/CachedStateRepositoryDecorator.spec.js deleted file mode 100644 index 00f40a8ba79..00000000000 --- a/packages/js-drive/test/unit/dpp/CachedStateRepositoryDecorator.spec.js +++ /dev/null @@ -1,247 +0,0 @@ -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const createStateRepositoryMock = require('@dashevo/dpp/lib/test/mocks/createStateRepositoryMock'); - -const CachedStateRepositoryDecorator = require('../../../lib/dpp/CachedStateRepositoryDecorator'); - -describe('CachedStateRepositoryDecorator', () => { - let stateRepositoryMock; - let cachedStateRepository; - let id; - let identity; - let documents; - let dataContract; - - beforeEach(function beforeEach() { - id = 'id'; - identity = getIdentityFixture(); - documents = getDocumentsFixture(); - dataContract = getDataContractFixture(); - - stateRepositoryMock = createStateRepositoryMock(this.sinon); - - cachedStateRepository = new CachedStateRepositoryDecorator( - stateRepositoryMock, - ); - }); - - describe('#fetchIdentity', () => { - it('should fetch identity from state repository', async () => { - stateRepositoryMock.fetchIdentity.resolves(identity); - - const result = await cachedStateRepository.fetchIdentity(id); - - expect(result).to.deep.equal(identity); - expect(stateRepositoryMock.fetchIdentity).to.be.calledOnceWith(id); - }); - }); - - describe('#createIdentity', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.createIdentity(identity); - - expect(stateRepositoryMock.createIdentity).to.be.calledOnceWith(identity); - }); - }); - - describe('#addKeysToIdentity', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.addKeysToIdentity(identity.getId(), identity.getPublicKeys()); - - expect(stateRepositoryMock.addKeysToIdentity).to.be.calledOnceWith( - identity.getId(), - identity.getPublicKeys(), - ); - }); - }); - - describe('#fetchIdentityBalance', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.fetchIdentityBalance(identity.getId()); - - expect(stateRepositoryMock.fetchIdentityBalance).to.be.calledOnceWith( - identity.getId(), - ); - }); - }); - - describe('#fetchIdentityBalanceWithDebt', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.fetchIdentityBalanceWithDebt(identity.getId()); - - expect(stateRepositoryMock.fetchIdentityBalanceWithDebt).to.be.calledOnceWith( - identity.getId(), - ); - }); - }); - - describe('#addToIdentityBalance', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.addToIdentityBalance(identity.getId(), 100); - - expect(stateRepositoryMock.addToIdentityBalance).to.be.calledOnceWith( - identity.getId(), - 100, - ); - }); - }); - - describe('#disableIdentityKeys', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.disableIdentityKeys(identity.getId(), [100], 100); - - expect(stateRepositoryMock.disableIdentityKeys).to.be.calledOnceWith( - identity.getId(), - [100], - 100, - ); - }); - }); - - describe('#updateIdentityRevision', () => { - it('should store identity to repository', async () => { - await cachedStateRepository.updateIdentityRevision(identity.getId(), 1); - - expect(stateRepositoryMock.updateIdentityRevision).to.be.calledOnceWith( - identity.getId(), - 1, - ); - }); - }); - - describe('#fetchDocuments', () => { - it('should fetch documents from state repository', async () => { - const contractId = 'contractId'; - const type = 'documentType'; - const options = {}; - - stateRepositoryMock.fetchDocuments.resolves(documents); - - const result = await cachedStateRepository.fetchDocuments(contractId, type, options); - - expect(result).to.equal(documents); - expect(stateRepositoryMock.fetchDocuments).to.be.calledOnceWith(contractId, type, options); - }); - }); - - describe('#createDocument', () => { - it('should create document in repository', async () => { - const [document] = documents; - - await cachedStateRepository.createDocument(document); - - expect(stateRepositoryMock.createDocument).to.be.calledOnceWith(document); - }); - }); - - describe('#updateDocument', () => { - it('should update document in repository', async () => { - const [document] = documents; - - await cachedStateRepository.updateDocument(document); - - expect(stateRepositoryMock.updateDocument).to.be.calledOnceWith(document); - }); - }); - - describe('#removeDocument', () => { - it('should delete document from repository', async () => { - const type = 'documentType'; - - await cachedStateRepository.removeDocument(dataContract, type, id); - - expect(stateRepositoryMock.removeDocument).to.be.calledOnceWith(dataContract, type, id); - }); - }); - - describe('fetchTransaction', () => { - it('should fetch transaction from state repository', async () => { - stateRepositoryMock.fetchTransaction.resolves(dataContract); - - const result = await cachedStateRepository.fetchTransaction(id); - - expect(result).to.equal(dataContract); - expect(stateRepositoryMock.fetchTransaction).to.be.calledOnceWith(id); - }); - }); - - describe('#fetchDataContract', () => { - it('should fetch data contract from state repository if it is not present in cache', async () => { - stateRepositoryMock.fetchDataContract.resolves(dataContract); - - const result = await cachedStateRepository.fetchDataContract(id); - - expect(result).to.equal(dataContract); - expect(stateRepositoryMock.fetchDataContract).to.be.calledOnceWith(id); - }); - }); - - describe('#fetchLatestPlatformBlockHeight', () => { - it('should fetch latest platform height from state repository', async () => { - stateRepositoryMock.fetchLatestPlatformBlockHeight.resolves(10); - - const result = await cachedStateRepository.fetchLatestPlatformBlockHeight(id); - - expect(result).to.equal(10); - expect(stateRepositoryMock.fetchLatestPlatformBlockHeight).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestPlatformBlockTime', () => { - it('should fetch latest platform block time from state repository', async () => { - const timeMs = Date.now(); - - stateRepositoryMock.fetchLatestPlatformBlockTime.returns(timeMs); - - const result = await cachedStateRepository.fetchLatestPlatformBlockTime(); - - expect(result).to.deep.equal(timeMs); - expect(stateRepositoryMock.fetchLatestPlatformBlockTime).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestPlatformCoreChainLockedHeight', () => { - it('should fetch latest platform core chain locked height from state repository', async () => { - const height = 42; - - stateRepositoryMock.fetchLatestPlatformCoreChainLockedHeight.resolves(height); - - const result = await cachedStateRepository.fetchLatestPlatformCoreChainLockedHeight(id); - - expect(result).to.deep.equal(height); - expect(stateRepositoryMock.fetchLatestPlatformCoreChainLockedHeight).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestWithdrawalTransactionIndex', () => { - it('should call fetchLatestWithdrawalTransactionIndex', async () => { - stateRepositoryMock.fetchLatestWithdrawalTransactionIndex.resolves(42); - - const result = await cachedStateRepository.fetchLatestWithdrawalTransactionIndex(); - - expect(result).to.equal(42); - expect( - stateRepositoryMock.fetchLatestWithdrawalTransactionIndex, - ).to.have.been.calledOnce(); - }); - }); - - describe('#enqueueWithdrawalTransaction', () => { - it('should call enqueueWithdrawalTransaction', async () => { - const index = 42; - const transactionBytes = Buffer.alloc(32, 1); - - await cachedStateRepository.enqueueWithdrawalTransaction( - index, transactionBytes, - ); - - expect( - stateRepositoryMock.enqueueWithdrawalTransaction, - ).to.have.been.calledOnceWithExactly( - index, - transactionBytes, - ); - }); - }); -}); diff --git a/packages/js-drive/test/unit/dpp/DriveStateRepository.spec.js b/packages/js-drive/test/unit/dpp/DriveStateRepository.spec.js deleted file mode 100644 index a974f8522a7..00000000000 --- a/packages/js-drive/test/unit/dpp/DriveStateRepository.spec.js +++ /dev/null @@ -1,732 +0,0 @@ -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const ReadOperation = require('@dashevo/dpp/lib/stateTransition/fee/operations/ReadOperation'); -const StateTransitionExecutionContext = require('@dashevo/dpp/lib/stateTransition/StateTransitionExecutionContext'); - -const Long = require('long'); - -const DriveStateRepository = require('../../../lib/dpp/DriveStateRepository'); -const StorageResult = require('../../../lib/storage/StorageResult'); -const BlockExecutionContextMock = require('../../../lib/test/mock/BlockExecutionContextMock'); -const BlockInfo = require('../../../lib/blockExecution/BlockInfo'); - -describe('DriveStateRepository', () => { - let stateRepository; - let identityRepositoryMock; - let identityBalanceRepositoryMock; - let identityPublicKeyRepositoryMock; - let dataContractRepositoryMock; - let fetchDocumentsMock; - let documentsRepositoryMock; - let spentAssetLockTransactionsRepositoryMock; - let coreRpcClientMock; - let id; - let identity; - let documents; - let dataContract; - let blockExecutionContextMock; - let simplifiedMasternodeListMock; - let instantLockMock; - let repositoryOptions; - let executionContext; - let operations; - let blockInfo; - let rsDriveMock; - let blockHeight; - let timeMs; - - beforeEach(function beforeEach() { - identity = getIdentityFixture(); - documents = getDocumentsFixture(); - dataContract = getDataContractFixture(); - id = generateRandomIdentifier(); - - coreRpcClientMock = { - getRawTransaction: this.sinon.stub(), - verifyIsLock: this.sinon.stub(), - }; - - dataContractRepositoryMock = { - fetch: this.sinon.stub(), - create: this.sinon.stub(), - update: this.sinon.stub(), - }; - - identityRepositoryMock = { - fetch: this.sinon.stub(), - create: this.sinon.stub(), - updateRevision: this.sinon.stub(), - }; - - identityBalanceRepositoryMock = { - add: this.sinon.stub(), - fetch: this.sinon.stub(), - fetchWithDebt: this.sinon.stub(), - }; - - identityPublicKeyRepositoryMock = { - fetch: this.sinon.stub(), - add: this.sinon.stub(), - disable: this.sinon.stub(), - }; - - fetchDocumentsMock = this.sinon.stub(); - - documentsRepositoryMock = { - create: this.sinon.stub(), - update: this.sinon.stub(), - find: this.sinon.stub(), - delete: this.sinon.stub(), - }; - - spentAssetLockTransactionsRepositoryMock = { - store: this.sinon.stub(), - find: this.sinon.stub(), - delete: this.sinon.stub(), - }; - - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - - timeMs = Date.now(); - - blockHeight = Long.fromNumber(1); - - blockInfo = new BlockInfo(blockHeight.toNumber(), 0, timeMs); - - blockExecutionContextMock.getEpochInfo.returns({ - currentEpochIndex: blockInfo.epoch, - }); - blockExecutionContextMock.getHeight.returns(blockHeight); - blockExecutionContextMock.getTimeMs.returns(timeMs); - - simplifiedMasternodeListMock = { - getStore: this.sinon.stub(), - }; - - repositoryOptions = { useTransaction: true }; - - rsDriveMock = { - fetchLatestWithdrawalTransactionIndex: this.sinon.stub(), - enqueueWithdrawalTransaction: this.sinon.stub(), - }; - - rsDriveMock.fetchLatestWithdrawalTransactionIndex.resolves(42); - - stateRepository = new DriveStateRepository( - identityRepositoryMock, - identityBalanceRepositoryMock, - identityPublicKeyRepositoryMock, - dataContractRepositoryMock, - fetchDocumentsMock, - documentsRepositoryMock, - spentAssetLockTransactionsRepositoryMock, - coreRpcClientMock, - blockExecutionContextMock, - simplifiedMasternodeListMock, - rsDriveMock, - repositoryOptions, - ); - - instantLockMock = { - getRequestId: () => 'someRequestId', - txid: 'someTxId', - signature: 'signature', - verify: this.sinon.stub(), - }; - - executionContext = new StateTransitionExecutionContext(); - operations = [new ReadOperation(1)]; - }); - - describe('#fetchIdentity', () => { - it('should fetch identity from repository', async () => { - identityRepositoryMock.fetch.resolves( - new StorageResult(identity, operations), - ); - - const result = await stateRepository.fetchIdentity(id, executionContext); - - expect(result).to.equal(identity); - expect(identityRepositoryMock.fetch).to.be.calledOnceWith( - id, - { - blockInfo, - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#createIdentity', () => { - it('should create identity', async () => { - identityRepositoryMock.create.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.createIdentity(identity, executionContext); - - expect(identityRepositoryMock.create).to.be.calledOnceWith( - identity, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#fetchIdentityBalance', () => { - it('should fetch identity balance', async () => { - identityBalanceRepositoryMock.fetch.resolves( - new StorageResult(1, operations), - ); - - const result = await stateRepository.fetchIdentityBalance(identity.getId(), executionContext); - - expect(result).to.equals(1); - - expect(identityBalanceRepositoryMock.fetch).to.be.calledOnceWith( - identity.getId(), - { - blockInfo, - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#fetchIdentityBalanceWithDebt', () => { - it('should fetch identity balance', async () => { - identityBalanceRepositoryMock.fetchWithDebt.resolves( - new StorageResult(1, operations), - ); - - const result = await stateRepository.fetchIdentityBalanceWithDebt( - identity.getId(), - executionContext, - ); - - expect(result).to.equals(1); - - expect(identityBalanceRepositoryMock.fetchWithDebt).to.be.calledOnceWith( - identity.getId(), - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#addToIdentityBalance', () => { - it('should update identity balance', async () => { - identityBalanceRepositoryMock.add.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.addToIdentityBalance(identity.getId(), 1, executionContext); - - expect(identityBalanceRepositoryMock.add).to.be.calledOnceWith( - identity.getId(), - 1, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#updateIdentityRevision', () => { - it('should update identity revision', async () => { - identityRepositoryMock.updateRevision.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.updateIdentityRevision(identity.getId(), 1, executionContext); - - expect(identityRepositoryMock.updateRevision).to.be.calledOnceWith( - identity.getId(), - 1, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#addKeysToIdentity', () => { - it('should add keys to identity', async () => { - identityPublicKeyRepositoryMock.add.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.addKeysToIdentity( - identity.getId(), - identity.getPublicKeys(), - executionContext, - ); - - expect(identityPublicKeyRepositoryMock.add).to.be.calledOnceWith( - identity.getId(), - identity.getPublicKeys(), - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#disableIdentityKeys', () => { - it('should disable identity keys', async () => { - identityPublicKeyRepositoryMock.disable.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.disableIdentityKeys( - identity.getId(), - [1, 2], - 123, - executionContext, - ); - - expect(identityPublicKeyRepositoryMock.disable).to.be.calledOnceWith( - identity.getId(), - [1, 2], - 123, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#fetchDataContract', () => { - it('should fetch data contract from repository', async () => { - dataContractRepositoryMock.fetch.resolves( - new StorageResult(dataContract, operations), - ); - - const result = await stateRepository.fetchDataContract(id, executionContext); - - expect(result).to.equal(dataContract); - expect(dataContractRepositoryMock.fetch).to.be.calledOnceWithExactly( - id, - { - blockInfo, - dryRun: false, - useTransaction: repositoryOptions.useTransaction, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#createDataContract', () => { - it('should create data contract to repository', async () => { - dataContractRepositoryMock.create.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.createDataContract(dataContract, executionContext); - - expect(dataContractRepositoryMock.create).to.be.calledOnceWith( - dataContract, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#updateDataContract', () => { - it('should store data contract to repository', async () => { - dataContractRepositoryMock.update.resolves( - new StorageResult(undefined, operations), - ); - - await stateRepository.updateDataContract(dataContract, executionContext); - - expect(dataContractRepositoryMock.update).to.be.calledOnceWith( - dataContract, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#fetchDocuments', () => { - it('should fetch documents from repository', async () => { - const type = 'documentType'; - const options = {}; - - fetchDocumentsMock.resolves( - new StorageResult(documents, operations), - ); - - const result = await stateRepository.fetchDocuments( - id, - type, - options, - executionContext, - ); - - expect(result).to.equal(documents); - expect(fetchDocumentsMock).to.be.calledOnceWith( - id, - type, - { - blockInfo, - ...options, - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#createDocument', () => { - it('should create document in repository', async () => { - documentsRepositoryMock.create.resolves( - new StorageResult(undefined, operations), - ); - - const [document] = documents; - - await stateRepository.createDocument(document, executionContext); - - expect(documentsRepositoryMock.create).to.be.calledOnceWith( - document, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#updateDocument', () => { - it('should store document in repository', async () => { - documentsRepositoryMock.update.resolves( - new StorageResult(undefined, operations), - ); - - const [document] = documents; - - await stateRepository.updateDocument(document, executionContext); - - expect(documentsRepositoryMock.update).to.be.calledOnceWith( - document, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#removeDocument', () => { - it('should delete document from repository', async () => { - documentsRepositoryMock.delete.resolves( - new StorageResult(undefined, operations), - ); - - const type = 'documentType'; - - await stateRepository.removeDocument(dataContract, type, id, executionContext); - - expect(documentsRepositoryMock.delete).to.be.calledOnceWith( - dataContract, - type, - id, - blockInfo, - { - useTransaction: repositoryOptions.useTransaction, - dryRun: false, - }, - ); - - expect(executionContext.getOperations()).to.deep.equals(operations); - }); - }); - - describe('#fetchTransaction', () => { - it('should fetch transaction from core', async () => { - const rawTransaction = { - hex: 'some result', - height: 1, - }; - - coreRpcClientMock.getRawTransaction.resolves({ result: rawTransaction }); - - const result = await stateRepository.fetchTransaction(id, executionContext); - - expect(result).to.deep.equal({ - data: Buffer.from(rawTransaction.hex, 'hex'), - height: rawTransaction.height, - }); - - expect(coreRpcClientMock.getRawTransaction).to.be.calledOnceWithExactly(id, 1); - - const operation = new ReadOperation(Buffer.from(rawTransaction.hex, 'hex').length); - - expect(executionContext.getOperations()).to.deep.equals([operation]); - }); - - it('should return null if core throws Invalid address or key error', async () => { - const error = new Error('Some error'); - error.code = -5; - - coreRpcClientMock.getRawTransaction.throws(error); - - const result = await stateRepository.fetchTransaction(id); - - expect(result).to.equal(null); - expect(coreRpcClientMock.getRawTransaction).to.be.calledOnceWith(id); - }); - - it('should throw an error if core throws an unknown error', async () => { - const error = new Error('Some error'); - - coreRpcClientMock.getRawTransaction.throws(error); - - try { - await stateRepository.fetchTransaction(id); - - expect.fail('should throw error'); - } catch (e) { - expect(e).to.equal(error); - expect(coreRpcClientMock.getRawTransaction).to.be.calledOnceWith(id); - } - }); - - it('should return mocked transaction on dry run', async () => { - executionContext.enableDryRun(); - - const result = await stateRepository.fetchTransaction(id, executionContext); - - executionContext.disableDryRun(); - - expect(result).to.deep.equal({ - data: Buffer.alloc(0), - height: 1, - }); - - expect(coreRpcClientMock.getRawTransaction).to.not.be.called(id); - }); - }); - - describe('#fetchLatestPlatformBlockHeight', () => { - it('should fetch latest platform block height', async () => { - blockExecutionContextMock.getHeight.resolves(10); - - const result = await stateRepository.fetchLatestPlatformBlockHeight(); - - expect(result).to.equal(10); - expect(blockExecutionContextMock.getHeight).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestPlatformBlockTime', () => { - it('should fetch latest platform block time', async () => { - const result = await stateRepository.fetchLatestPlatformBlockTime(); - - expect(result).to.deep.equal(timeMs); - expect(blockExecutionContextMock.getTimeMs).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestPlatformCoreChainLockedHeight', () => { - it('should fetch latest platform core chainlocked height', async () => { - blockExecutionContextMock.getCoreChainLockedHeight.returns(10); - - const result = await stateRepository.fetchLatestPlatformCoreChainLockedHeight(); - - expect(result).to.equal(10); - expect(blockExecutionContextMock.getCoreChainLockedHeight).to.be.calledOnce(); - }); - }); - - describe('#verifyInstantLock', () => { - let smlStore; - - beforeEach(() => { - blockExecutionContextMock.getHeight.returns(41); - blockExecutionContextMock.getCoreChainLockedHeight.returns(42); - - smlStore = {}; - - simplifiedMasternodeListMock.getStore.returns(smlStore); - }); - - it('it should verify instant lock using Core', async () => { - coreRpcClientMock.verifyIsLock.resolves({ result: true }); - - const result = await stateRepository.verifyInstantLock(instantLockMock); - - expect(result).to.equal(true); - expect(coreRpcClientMock.verifyIsLock).to.have.been.calledOnceWithExactly( - 'someRequestId', - 'someTxId', - 'signature', - 42, - ); - expect(instantLockMock.verify).to.have.not.been.called(); - }); - - it('should return false if core throws Invalid address or key error', async () => { - const error = new Error('Some error'); - error.code = -5; - - coreRpcClientMock.verifyIsLock.throws(error); - - const result = await stateRepository.verifyInstantLock(instantLockMock); - - expect(result).to.equal(false); - expect(coreRpcClientMock.verifyIsLock).to.have.been.calledOnceWithExactly( - 'someRequestId', - 'someTxId', - 'signature', - 42, - ); - expect(instantLockMock.verify).to.have.not.been.called(); - }); - - it('should return false if core throws Invalid parameter', async () => { - const error = new Error('Some error'); - error.code = -8; - - coreRpcClientMock.verifyIsLock.throws(error); - - const result = await stateRepository.verifyInstantLock(instantLockMock); - - expect(result).to.equal(false); - expect(coreRpcClientMock.verifyIsLock).to.have.been.calledOnceWithExactly( - 'someRequestId', - 'someTxId', - 'signature', - 42, - ); - expect(instantLockMock.verify).to.have.not.been.called(); - }); - - it('should return false if coreChainLockedHeight is null', async () => { - blockExecutionContextMock.getCoreChainLockedHeight.returns(null); - - const result = await stateRepository.verifyInstantLock(instantLockMock); - - expect(result).to.be.false(); - }); - - it('should return true on dry run', async () => { - const error = new Error('Some error'); - error.code = -5; - - coreRpcClientMock.verifyIsLock.throws(error); - - executionContext.enableDryRun(); - - const result = await stateRepository.verifyInstantLock(instantLockMock, executionContext); - - executionContext.disableDryRun(); - - expect(result).to.be.true(); - expect(instantLockMock.verify).to.have.not.been.called(); - expect(coreRpcClientMock.verifyIsLock).to.have.not.been.called(); - }); - }); - - describe('#fetchSMLStore', () => { - it('should fetch SML store', async () => { - simplifiedMasternodeListMock.getStore.resolves('store'); - - const result = await stateRepository.fetchSMLStore(); - - expect(result).to.equal('store'); - expect(simplifiedMasternodeListMock.getStore).to.be.calledOnce(); - }); - }); - - describe('#fetchLatestWithdrawalTransactionIndex', () => { - it('should call fetchLatestWithdrawalTransactionIndex', async () => { - const result = await stateRepository.fetchLatestWithdrawalTransactionIndex(); - - expect(result).to.equal(42); - expect( - rsDriveMock.fetchLatestWithdrawalTransactionIndex, - ).to.have.been.calledOnceWithExactly( - blockInfo, - repositoryOptions.useTransaction, - repositoryOptions.dryRun, - ); - }); - }); - - describe('#enqueueWithdrawalTransaction', () => { - it('should call enqueueWithdrawalTransaction', async () => { - const index = 42; - const transactionBytes = Buffer.alloc(32, 1); - - await stateRepository.enqueueWithdrawalTransaction( - index, transactionBytes, - ); - - expect( - rsDriveMock.enqueueWithdrawalTransaction, - ).to.have.been.calledOnceWithExactly( - index, - transactionBytes, - blockInfo, - repositoryOptions.useTransaction, - ); - }); - }); -}); diff --git a/packages/js-drive/test/unit/dpp/LoggedStateRepositoryDecorator.spec.js b/packages/js-drive/test/unit/dpp/LoggedStateRepositoryDecorator.spec.js deleted file mode 100644 index 0e1344b80e5..00000000000 --- a/packages/js-drive/test/unit/dpp/LoggedStateRepositoryDecorator.spec.js +++ /dev/null @@ -1,983 +0,0 @@ -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const createStateRepositoryMock = require('@dashevo/dpp/lib/test/mocks/createStateRepositoryMock'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const LoggedStateRepositoryDecorator = require('../../../lib/dpp/LoggedStateRepositoryDecorator'); -const LoggerMock = require('../../../lib/test/mock/LoggerMock'); -const BlockExecutionContextMock = require('../../../lib/test/mock/BlockExecutionContextMock'); - -describe('LoggedStateRepositoryDecorator', () => { - let loggedStateRepositoryDecorator; - let stateRepositoryMock; - let loggerMock; - let blockExecutionContextMock; - - beforeEach(function beforeEach() { - stateRepositoryMock = createStateRepositoryMock(this.sinon); - loggerMock = new LoggerMock(this.sinon); - - blockExecutionContextMock = new BlockExecutionContextMock(this.sinon); - blockExecutionContextMock.getContextLogger.returns(loggerMock); - - loggedStateRepositoryDecorator = new LoggedStateRepositoryDecorator( - stateRepositoryMock, - blockExecutionContextMock, - ); - }); - - describe('#fetchIdentity', () => { - let id; - - beforeEach(() => { - id = generateRandomIdentifier(); - }); - - it('should call logger with proper params', async () => { - const response = getIdentityFixture(); - - stateRepositoryMock.fetchIdentity.resolves(response); - - await loggedStateRepositoryDecorator.fetchIdentity(id); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentity', - parameters: { id }, - response, - }, - }, 'StateRepository#fetchIdentity'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchIdentity.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchIdentity(id); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentity', - parameters: { id }, - response: undefined, - }, - }, 'StateRepository#fetchIdentity'); - }); - }); - - describe('#storeIdentity', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.createIdentity.resolves(response); - - await loggedStateRepositoryDecorator.createIdentity(identity); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createIdentity', - parameters: { identity }, - response, - }, - }, 'StateRepository#createIdentity'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.createIdentity.throws(error); - - try { - await loggedStateRepositoryDecorator.createIdentity(identity); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createIdentity', - parameters: { identity }, - response: undefined, - }, - }, 'StateRepository#createIdentity'); - }); - }); - - describe('#addKeysToIdentity', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.addKeysToIdentity.resolves(response); - - await loggedStateRepositoryDecorator.addKeysToIdentity( - identity.getId(), - identity.getPublicKeys(), - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'addKeysToIdentity', - parameters: { identityId: identity.getId(), keys: identity.getPublicKeys() }, - response, - }, - }, 'StateRepository#addKeysToIdentity'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.addKeysToIdentity.throws(error); - - try { - await loggedStateRepositoryDecorator.addKeysToIdentity( - identity.getId(), - identity.getPublicKeys(), - ); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'addKeysToIdentity', - parameters: { identityId: identity.getId(), keys: identity.getPublicKeys() }, - response: undefined, - }, - }, 'StateRepository#addKeysToIdentity'); - }); - }); - - describe('#fetchIdentityBalance', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.fetchIdentityBalance.resolves(response); - - await loggedStateRepositoryDecorator.fetchIdentityBalance( - identity.getId(), - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentityBalance', - parameters: { identityId: identity.getId() }, - response, - }, - }, 'StateRepository#fetchIdentityBalance'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchIdentityBalance.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchIdentityBalance(identity.getId()); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentityBalance', - parameters: { identityId: identity.getId() }, - response: undefined, - }, - }, 'StateRepository#fetchIdentityBalance'); - }); - }); - - describe('#fetchIdentityBalanceWithDebt', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.fetchIdentityBalanceWithDebt.resolves(response); - - await loggedStateRepositoryDecorator.fetchIdentityBalanceWithDebt( - identity.getId(), - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentityBalanceWithDebt', - parameters: { identityId: identity.getId() }, - response, - }, - }, 'StateRepository#fetchIdentityBalanceWithDebt'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchIdentityBalanceWithDebt.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchIdentityBalanceWithDebt(identity.getId()); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchIdentityBalanceWithDebt', - parameters: { identityId: identity.getId() }, - response: undefined, - }, - }, 'StateRepository#fetchIdentityBalanceWithDebt'); - }); - }); - - describe('#addToIdentityBalance', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.addToIdentityBalance.resolves(response); - - const amount = 200; - - await loggedStateRepositoryDecorator.addToIdentityBalance( - identity.getId(), - amount, - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'addToIdentityBalance', - parameters: { identityId: identity.getId(), amount }, - response, - }, - }, 'StateRepository#addToIdentityBalance'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.addToIdentityBalance.throws(error); - - const amount = 100; - - try { - await loggedStateRepositoryDecorator.addToIdentityBalance(identity.getId(), amount); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'addToIdentityBalance', - parameters: { identityId: identity.getId(), amount }, - response: undefined, - }, - }, 'StateRepository#addToIdentityBalance'); - }); - }); - - describe('#disableIdentityKeys', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.disableIdentityKeys.resolves(response); - - const keyIds = [1, 2]; - const disableAt = 123; - - await loggedStateRepositoryDecorator.disableIdentityKeys( - identity.getId(), - keyIds, - disableAt, - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'disableIdentityKeys', - parameters: { identityId: identity.getId(), keyIds, disableAt }, - response, - }, - }, 'StateRepository#disableIdentityKeys'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.disableIdentityKeys.throws(error); - - const keyIds = [1, 2]; - const disableAt = 123; - - try { - await loggedStateRepositoryDecorator.disableIdentityKeys( - identity.getId(), - keyIds, - disableAt, - ); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'disableIdentityKeys', - parameters: { identityId: identity.getId(), keyIds, disableAt }, - response: undefined, - }, - }, 'StateRepository#disableIdentityKeys'); - }); - }); - - describe('#updateIdentityRevision', () => { - let identity; - - beforeEach(() => { - identity = getIdentityFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.updateIdentityRevision.resolves(response); - - const revision = 1; - - await loggedStateRepositoryDecorator.updateIdentityRevision( - identity.getId(), - revision, - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateIdentityRevision', - parameters: { identityId: identity.getId(), revision }, - response, - }, - }, 'StateRepository#updateIdentityRevision'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.updateIdentityRevision.throws(error); - - const revision = 1; - - try { - await loggedStateRepositoryDecorator.updateIdentityRevision( - identity.getId(), - revision, - ); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateIdentityRevision', - parameters: { identityId: identity.getId(), revision }, - response: undefined, - }, - }, 'StateRepository#updateIdentityRevision'); - }); - }); - - describe('#fetchDataContract', () => { - let id; - - beforeEach(() => { - id = generateRandomIdentifier(); - }); - - it('should call logger with proper params', async () => { - const response = getDataContractFixture(); - - stateRepositoryMock.fetchDataContract.resolves(response); - - await loggedStateRepositoryDecorator.fetchDataContract(id); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchDataContract', - parameters: { id }, - response, - }, - }, 'StateRepository#fetchDataContract'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchDataContract.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchDataContract(id); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchDataContract', - parameters: { id }, - response: undefined, - }, - }, 'StateRepository#fetchDataContract'); - }); - }); - - describe('#createDataContract', () => { - let dataContract; - - beforeEach(() => { - dataContract = getDataContractFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.createDataContract.resolves(response); - - await loggedStateRepositoryDecorator.createDataContract(dataContract); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createDataContract', - parameters: { dataContract }, - response, - }, - }, 'StateRepository#createDataContract'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.createDataContract.throws(error); - - try { - await loggedStateRepositoryDecorator.createDataContract(dataContract); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createDataContract', - parameters: { dataContract }, - response: undefined, - }, - }, 'StateRepository#createDataContract'); - }); - }); - - describe('#updateDataContract', () => { - let dataContract; - - beforeEach(() => { - dataContract = getDataContractFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.updateDataContract.resolves(response); - - await loggedStateRepositoryDecorator.updateDataContract(dataContract); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateDataContract', - parameters: { dataContract }, - response, - }, - }, 'StateRepository#updateDataContract'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.updateDataContract.throws(error); - - try { - await loggedStateRepositoryDecorator.updateDataContract(dataContract); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateDataContract', - parameters: { dataContract }, - response: undefined, - }, - }, 'StateRepository#updateDataContract'); - }); - }); - - describe('#fetchDocuments', () => { - let contractId; - let type; - let options; - - beforeEach(() => { - contractId = generateRandomIdentifier(); - type = 'type'; - options = { - where: [['field', '==', 'value']], - }; - }); - - it('should call logger with proper params', async () => { - const response = getDocumentsFixture(); - - stateRepositoryMock.fetchDocuments.resolves(response); - - await loggedStateRepositoryDecorator.fetchDocuments(contractId, type, options); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchDocuments', - parameters: { contractId, type, options }, - response, - }, - }, 'StateRepository#fetchDocuments'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchDocuments.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchDocuments(contractId, type, options); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchDocuments', - parameters: { contractId, type, options }, - response: undefined, - }, - }, 'StateRepository#fetchDocuments'); - }); - }); - - describe('#createDocument', () => { - let document; - - beforeEach(() => { - [document] = getDocumentsFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.createDocument.resolves(response); - - await loggedStateRepositoryDecorator.createDocument(document); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createDocument', - parameters: { document }, - response, - }, - }, 'StateRepository#createDocument'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.createDocument.throws(error); - - try { - await loggedStateRepositoryDecorator.createDocument(document); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'createDocument', - parameters: { document }, - response: undefined, - }, - }, 'StateRepository#createDocument'); - }); - }); - - describe('#updateDocument', () => { - let document; - - beforeEach(() => { - [document] = getDocumentsFixture(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.updateDocument.resolves(response); - - await loggedStateRepositoryDecorator.updateDocument(document); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateDocument', - parameters: { document }, - response, - }, - }, 'StateRepository#updateDocument'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.updateDocument.throws(error); - - try { - await loggedStateRepositoryDecorator.updateDocument(document); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'updateDocument', - parameters: { document }, - response: undefined, - }, - }, 'StateRepository#updateDocument'); - }); - }); - - describe('#removeDocument', () => { - let dataContract; - let type; - let id; - - beforeEach(() => { - dataContract = getDataContractFixture(); - type = 'type'; - id = generateRandomIdentifier(); - }); - - it('should call logger with proper params', async () => { - const response = undefined; - - stateRepositoryMock.removeDocument.resolves(response); - - await loggedStateRepositoryDecorator.removeDocument(dataContract, type, id); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'removeDocument', - parameters: { dataContract, type, id }, - response, - }, - }, 'StateRepository#removeDocument'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.removeDocument.throws(error); - - try { - await loggedStateRepositoryDecorator.removeDocument(dataContract, type, id); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'removeDocument', - parameters: { dataContract, type, id }, - response: undefined, - }, - }, 'StateRepository#removeDocument'); - }); - }); - - describe('#fetchTransaction', () => { - let id; - - beforeEach(() => { - id = 'id'; - }); - - it('should call logger with proper params', async () => { - const response = { hex: '123' }; - - stateRepositoryMock.fetchTransaction.resolves(response); - - await loggedStateRepositoryDecorator.fetchTransaction(id); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchTransaction', - parameters: { id }, - response, - }, - }, 'StateRepository#fetchTransaction'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchTransaction.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchTransaction(id); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchTransaction', - parameters: { id }, - response: undefined, - }, - }, 'StateRepository#fetchTransaction'); - }); - }); - - describe('#fetchLatestPlatformBlockHeight', () => { - it('should call logger with proper params', async () => { - const response = {}; - - stateRepositoryMock.fetchLatestPlatformBlockHeight.resolves(response); - - await loggedStateRepositoryDecorator.fetchLatestPlatformBlockHeight(); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformBlockHeight', - parameters: {}, - response, - }, - }, 'StateRepository#fetchLatestPlatformBlockHeight'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchLatestPlatformBlockHeight.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchLatestPlatformBlockHeight(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformBlockHeight', - parameters: {}, - response: undefined, - }, - }, 'StateRepository#fetchLatestPlatformBlockHeight'); - }); - }); - - describe('#fetchLatestPlatformBlockTime', () => { - it('should call logger with proper params', async () => { - const response = {}; - - stateRepositoryMock.fetchLatestPlatformBlockTime.resolves(response); - - await loggedStateRepositoryDecorator.fetchLatestPlatformBlockTime(); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformBlockTime', - parameters: {}, - response, - }, - }, 'StateRepository#fetchLatestPlatformBlockTime'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchLatestPlatformBlockTime.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchLatestPlatformBlockTime(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformBlockTime', - parameters: {}, - response: undefined, - }, - }, 'StateRepository#fetchLatestPlatformBlockTime'); - }); - }); - - describe('#fetchLatestPlatformCoreChainLockedHeight', () => { - it('should call logger with proper params', async () => { - const response = {}; - - stateRepositoryMock.fetchLatestPlatformCoreChainLockedHeight.resolves(response); - - await loggedStateRepositoryDecorator.fetchLatestPlatformCoreChainLockedHeight(); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformCoreChainLockedHeight', - parameters: {}, - response, - }, - }, 'StateRepository#fetchLatestPlatformCoreChainLockedHeight'); - }); - - it('should call logger in case of error', async () => { - const error = new Error('unknown error'); - - stateRepositoryMock.fetchLatestPlatformCoreChainLockedHeight.throws(error); - - try { - await loggedStateRepositoryDecorator.fetchLatestPlatformCoreChainLockedHeight(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).equals(error); - } - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestPlatformCoreChainLockedHeight', - parameters: {}, - response: undefined, - }, - }, 'StateRepository#fetchLatestPlatformCoreChainLockedHeight'); - }); - }); - - describe('#fetchLatestWithdrawalTransactionIndex', () => { - it('should call fetchLatestWithdrawalTransactionIndex', async () => { - stateRepositoryMock.fetchLatestWithdrawalTransactionIndex.resolves(42); - - const result = await loggedStateRepositoryDecorator.fetchLatestWithdrawalTransactionIndex(); - - expect(result).to.equal(42); - expect( - stateRepositoryMock.fetchLatestWithdrawalTransactionIndex, - ).to.have.been.calledOnce(); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'fetchLatestWithdrawalTransactionIndex', - parameters: {}, - response: 42, - }, - }, 'StateRepository#fetchLatestWithdrawalTransactionIndex'); - }); - }); - - describe('#enqueueWithdrawalTransaction', () => { - it('should call enqueueWithdrawalTransaction', async () => { - const index = 42; - const transactionBytes = Buffer.alloc(32, 1); - - await loggedStateRepositoryDecorator.enqueueWithdrawalTransaction( - index, transactionBytes, - ); - - expect( - stateRepositoryMock.enqueueWithdrawalTransaction, - ).to.have.been.calledOnceWithExactly( - index, - transactionBytes, - ); - - expect(loggerMock.trace).to.be.calledOnceWithExactly({ - stateRepository: { - method: 'enqueueWithdrawalTransaction', - parameters: { index, transactionBytes }, - response: undefined, - }, - }, 'StateRepository#enqueueWithdrawalTransaction'); - }); - }); -}); diff --git a/packages/js-drive/test/unit/featureFlag/getFeatureFlagForHeightFactory.spec.js b/packages/js-drive/test/unit/featureFlag/getFeatureFlagForHeightFactory.spec.js deleted file mode 100644 index 508fa99878d..00000000000 --- a/packages/js-drive/test/unit/featureFlag/getFeatureFlagForHeightFactory.spec.js +++ /dev/null @@ -1,65 +0,0 @@ -const Long = require('long'); - -const Identifier = require('@dashevo/dpp/lib/Identifier'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); - -const getFeatureFlagForHeightFactory = require('../../../lib/featureFlag/getFeatureFlagForHeightFactory'); -const StorageResult = require('../../../lib/storage/StorageResult'); - -describe('getFeatureFlagForHeightFactory', () => { - let featureFlagDataContractId; - let fetchDocumentsMock; - let getFeatureFlagForHeight; - let document; - let featureFlagDataContractBlockHeight; - - beforeEach(function beforeEach() { - featureFlagDataContractId = Identifier.from(Buffer.alloc(32, 1)); - - ([document] = getDocumentsFixture()); - - fetchDocumentsMock = this.sinon.stub().resolves( - new StorageResult([document]), - ); - - featureFlagDataContractBlockHeight = 42; - - getFeatureFlagForHeight = getFeatureFlagForHeightFactory( - featureFlagDataContractId, - fetchDocumentsMock, - ); - }); - - it('should call `fetchDocuments` and return first item from the result', async () => { - const result = await getFeatureFlagForHeight('someType', new Long(43)); - - const query = { - where: [ - ['enableAtHeight', '==', 43], - ], - }; - - expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly( - featureFlagDataContractId, - 'someType', - { - ...query, - useTransaction: false, - }, - ); - expect(result).to.deep.equal(document); - }); - - it('should return null if featureFlagDataContractId is undefined', async () => { - getFeatureFlagForHeight = getFeatureFlagForHeightFactory( - undefined, - featureFlagDataContractBlockHeight, - fetchDocumentsMock, - ); - - const result = await getFeatureFlagForHeight('someType', new Long(42)); - - expect(result).to.equal(null); - expect(fetchDocumentsMock).to.not.be.called(); - }); -}); diff --git a/packages/js-drive/test/unit/featureFlag/getLatestFeatureFlagFactory.spec.js b/packages/js-drive/test/unit/featureFlag/getLatestFeatureFlagFactory.spec.js deleted file mode 100644 index d0db783d48f..00000000000 --- a/packages/js-drive/test/unit/featureFlag/getLatestFeatureFlagFactory.spec.js +++ /dev/null @@ -1,53 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/Identifier'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const { expect } = require('chai'); - -const Long = require('long'); - -const getLatestFeatureFlagFactory = require('../../../lib/featureFlag/getLatestFeatureFlagFactory'); -const StorageResult = require('../../../lib/storage/StorageResult'); - -describe('getLatestFeatureFlagFactory', () => { - let featureFlagDataContractId; - let fetchDocumentsMock; - let getLatestFeatureFlag; - let document; - - beforeEach(function beforeEach() { - featureFlagDataContractId = Identifier.from(Buffer.alloc(32, 1)); - - ([document] = getDocumentsFixture()); - - fetchDocumentsMock = this.sinon.stub(); - fetchDocumentsMock.resolves( - new StorageResult([document]), - ); - - getLatestFeatureFlag = getLatestFeatureFlagFactory( - featureFlagDataContractId, - fetchDocumentsMock, - ); - }); - - it('should call `fetchDocuments` and return first item from the result', async () => { - const result = await getLatestFeatureFlag('someType', new Long(42)); - - const query = { - where: [ - ['enableAtHeight', '<=', 42], - ], - orderBy: [ - ['enableAtHeight', 'desc'], - ], - limit: 1, - useTransaction: false, - }; - - expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly( - featureFlagDataContractId, - 'someType', - query, - ); - expect(result).to.deep.equal(document); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/createMasternodeIdentityFactory.spec.js b/packages/js-drive/test/unit/identity/masternode/createMasternodeIdentityFactory.spec.js deleted file mode 100644 index 31fed3011d5..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/createMasternodeIdentityFactory.spec.js +++ /dev/null @@ -1,191 +0,0 @@ -const createDPPMock = require('@dashevo/dpp/lib/test/mocks/createDPPMock'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); -const ValidationResult = require('@dashevo/dpp/lib/validation/ValidationResult'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const createMasternodeIdentityFactory = require('../../../../lib/identity/masternode/createMasternodeIdentityFactory'); -const InvalidMasternodeIdentityError = require('../../../../lib/identity/masternode/errors/InvalidMasternodeIdentityError'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); - -describe('createMasternodeIdentityFactory', () => { - let createMasternodeIdentity; - let dppMock; - let validationResult; - let getWithdrawPubKeyTypeFromPayoutScriptMock; - let getPublicKeyFromPayoutScriptMock; - let identityRepositoryMock; - let blockInfo; - - beforeEach(function beforeEach() { - dppMock = createDPPMock(this.sinon); - - getWithdrawPubKeyTypeFromPayoutScriptMock = this.sinon.stub().returns( - IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH, - ); - - getPublicKeyFromPayoutScriptMock = this.sinon.stub().returns( - Buffer.alloc(20, 1), - ); - - validationResult = new ValidationResult(); - - dppMock.identity.validate.resolves(validationResult); - - identityRepositoryMock = { - create: this.sinon.stub(), - }; - - createMasternodeIdentity = createMasternodeIdentityFactory( - dppMock, - identityRepositoryMock, - getWithdrawPubKeyTypeFromPayoutScriptMock, - getPublicKeyFromPayoutScriptMock, - ); - - blockInfo = new BlockInfo(1, 0, Date.now()); - }); - - it('should create masternode identity', async () => { - const identityId = generateRandomIdentifier(); - const pubKeyData = Buffer.from([0]); - const pubKeyType = IdentityPublicKey.TYPES.ECDSA_HASH160; - - const result = await createMasternodeIdentity(blockInfo, identityId, pubKeyData, pubKeyType); - - const identity = new Identity({ - protocolVersion: 1, - id: identityId, - publicKeys: [{ - id: 0, - type: pubKeyType, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: true, - // Copy data buffer - data: Buffer.from([0]), - }], - balance: 0, - revision: 0, - }); - - expect(result).to.deep.equal(identity); - - expect(identityRepositoryMock.create).to.have.been.calledOnceWithExactly( - identity, - blockInfo, - { useTransaction: true }, - ); - - expect(getWithdrawPubKeyTypeFromPayoutScriptMock).to.not.be.called(); - - expect(getPublicKeyFromPayoutScriptMock).to.not.be.called(); - - expect(dppMock.identity.validate).to.be.calledOnceWithExactly(identity); - }); - - it('should store identity and public key hashed to the previous store', async () => { - const identityId = generateRandomIdentifier(); - const pubKeyData = Buffer.from([0]); - const pubKeyType = IdentityPublicKey.TYPES.ECDSA_HASH160; - - const result = await createMasternodeIdentity(blockInfo, identityId, pubKeyData, pubKeyType); - - const identity = new Identity({ - protocolVersion: 1, - id: identityId, - publicKeys: [{ - id: 0, - type: pubKeyType, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: true, - // Copy data buffer - data: Buffer.from([0]), - }], - balance: 0, - revision: 0, - }); - - expect(result).to.deep.equal(identity); - - expect(identityRepositoryMock.create).to.have.been.calledOnceWithExactly( - identity, - blockInfo, - { useTransaction: true }, - ); - }); - - it('should throw DPPValidationAbciError if identity is not valid', async () => { - const validationError = new Error('Validation error'); - - validationResult.addError(validationError); - - const identityId = generateRandomIdentifier(); - const pubKeyData = Buffer.from([0]); - const pubKeyType = IdentityPublicKey.TYPES.ECDSA_HASH160; - - try { - await createMasternodeIdentity(blockInfo, identityId, pubKeyData, pubKeyType); - - expect.fail('should fail with an error'); - } catch (e) { - expect(e).to.be.an.instanceof(InvalidMasternodeIdentityError); - expect(e.message).to.be.equal('Invalid masternode identity'); - expect(e.getValidationError()).to.be.deep.equal(validationError); - } - }); - - // TODO: Enable keys when we have support of non unique keys in DPP - it.skip('should create masternode identity with payoutScript public key', async () => { - const identityId = generateRandomIdentifier(); - const pubKeyData = Buffer.from([0]); - const pubKeyType = IdentityPublicKey.TYPES.ECDSA_HASH160; - const payoutScript = new Script(Address.fromString('7UkJidhNjEPJCQnCTXeaJKbJmL4JuyV66w')); - - const result = await createMasternodeIdentity( - blockInfo, - identityId, - pubKeyData, - pubKeyType, - payoutScript, - ); - - const identity = new Identity({ - protocolVersion: 1, - id: identityId, - publicKeys: [{ - id: 0, - type: pubKeyType, - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: true, - data: Buffer.from([0]), - }, { - id: 1, - type: IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH, - purpose: IdentityPublicKey.PURPOSES.WITHDRAW, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.CRITICAL, - readOnly: false, - data: Buffer.alloc(20, 1), - }], - balance: 0, - revision: 0, - }); - - expect(result).to.deep.equal(identity); - - expect(identityRepositoryMock.create).to.have.been.calledOnceWithExactly( - identity, - blockInfo, - { useTransaction: true }, - ); - - expect(getWithdrawPubKeyTypeFromPayoutScriptMock).to.be.calledOnce(); - - expect(getPublicKeyFromPayoutScriptMock).to.be.calledOnce(); - - expect(dppMock.identity.validate).to.be.calledOnceWithExactly(identity); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/createOperatorIdentifier.spec.js b/packages/js-drive/test/unit/identity/masternode/createOperatorIdentifier.spec.js deleted file mode 100644 index 59815f056d5..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/createOperatorIdentifier.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const createOperatorIdentifier = require('../../../../lib/identity/masternode/createOperatorIdentifier'); - -describe('createOperatorIdentifier', () => { - let smlEntry; - - beforeEach(() => { - smlEntry = { - proRegTxHash: '5557273f5922d9925e2327908ddb128bcf8e055a04d86e23431809bedd077060', - confirmedHash: '0000003da09fd100c60ad5743c44257bb9220ad8162a9b6cae9d005c8e465dba', - service: '95.222.25.60:19997', - pubKeyOperator: '08b66151b81bd6a08bad2e68810ea07014012d6d804859219958a7fbc293689aa902bd0cd6db7a4699c9e88a4ae8c2c0', - votingAddress: 'yZRteAQ51BoeD3sJL1iGdt6HJLgkWGurw5', - isValid: false, - }; - }); - - it('should return operator identifier from smlEntry', () => { - const identifier = createOperatorIdentifier(smlEntry); - - expect(identifier).to.deep.equal(Identifier.from('EwLi1FgGwvmLQ9nkfnttpXzv4SfC7XGBvs61QBCtnHEL')); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/createVotingIdentifier.spec.js b/packages/js-drive/test/unit/identity/masternode/createVotingIdentifier.spec.js deleted file mode 100644 index 7d65de4353d..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/createVotingIdentifier.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const createVotingIdentifier = require('../../../../lib/identity/masternode/createVotingIdentifier'); - -describe('createVotingIdentifier', () => { - let smlEntry; - - beforeEach(() => { - smlEntry = { - proRegTxHash: '5557273f5922d9925e2327908ddb128bcf8e055a04d86e23431809bedd077060', - confirmedHash: '0000003da09fd100c60ad5743c44257bb9220ad8162a9b6cae9d005c8e465dba', - service: '95.222.25.60:19997', - pubKeyOperator: '08b66151b81bd6a08bad2e68810ea07014012d6d804859219958a7fbc293689aa902bd0cd6db7a4699c9e88a4ae8c2c0', - votingAddress: 'yZRteAQ51BoeD3sJL1iGdt6HJLgkWGurw5', - isValid: false, - }; - }); - - it('should return voting identifier from smlEntry', () => { - const identifier = createVotingIdentifier(smlEntry); - - expect(identifier).to.deep.equal(Identifier.from('G1p14MYdpNRLNWuKgQ9SjJUPxfuaJMTwYjdRWu9sLzvL')); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/getPublicKeyFromPayoutScript.spec.js b/packages/js-drive/test/unit/identity/masternode/getPublicKeyFromPayoutScript.spec.js deleted file mode 100644 index 9239624e377..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/getPublicKeyFromPayoutScript.spec.js +++ /dev/null @@ -1,43 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const InvalidIdentityPublicKeyTypeError = require('@dashevo/dpp/lib/stateTransition/errors/InvalidIdentityPublicKeyTypeError'); -const getPublicKeyFromPayoutScript = require('../../../../lib/identity/masternode/getPublicKeyFromPayoutScript'); - -describe('getPublicKeyFromPayoutScript', () => { - it('should return public key for ECDSA_HASH160 script', () => { - const payoutAddress = Address.fromString('yLceJztHVZFbeqE9v86sLD9bDKFBmNqHQD'); - const scriptBuffer = new Script(payoutAddress); - - const type = IdentityPublicKey.TYPES.ECDSA_HASH160; - - const result = getPublicKeyFromPayoutScript(scriptBuffer, type); - - expect(result).to.deep.equal(Buffer.from('0340a3abf7e6eccf42b4dd71ef8c20ed53a78d1f', 'hex')); - }); - - it('should return public key for BIP13_SCRIPT_HASH script', () => { - const payoutAddress = Address.fromString('7UkJidhNjEPJCQnCTXeaJKbJmL4JuyV66w'); - const scriptBuffer = new Script(payoutAddress); - - const type = IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH; - - const result = getPublicKeyFromPayoutScript(scriptBuffer, type); - - expect(result).to.deep.equal(Buffer.from('19a7d869032368fd1f1e26e5e73a4ad0e474960e', 'hex')); - }); - - it('should throw InvalidIdentityPublicKeyTypeError if type is unknown', () => { - const payoutAddress = Address.fromString('7UkJidhNjEPJCQnCTXeaJKbJmL4JuyV66w'); - const scriptBuffer = new Script(payoutAddress); - - try { - getPublicKeyFromPayoutScript(scriptBuffer, -1); - - expect.fail('should throw InvalidIdentityPublicKeyTypeError'); - } catch (e) { - expect(e).to.be.an.instanceof(InvalidIdentityPublicKeyTypeError); - expect(e.getPublicKeyType()).to.equal(-1); - } - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.spec.js b/packages/js-drive/test/unit/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.spec.js deleted file mode 100644 index 5b2950fec34..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory.spec.js +++ /dev/null @@ -1,44 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const getWithdrawPubKeyTypeFromPayoutScriptFactory = require('../../../../lib/identity/masternode/getWithdrawPubKeyTypeFromPayoutScriptFactory'); -const InvalidPayoutScriptError = require('../../../../lib/identity/masternode/errors/InvalidPayoutScriptError'); - -describe('getWithdrawPubKeyTypeFromPayoutScriptFactory', () => { - let getWithdrawPubKeyTypeFromPayoutScript; - let network; - - beforeEach(() => { - network = 'testnet'; - getWithdrawPubKeyTypeFromPayoutScript = getWithdrawPubKeyTypeFromPayoutScriptFactory( - network, - ); - }); - - it('should return ECDSA_HASH160 if address has p2pkh type', () => { - const payoutScript = Script(Address.fromString('yTsGq4wV8WF5GKLaYV2C43zrkr2sfTtysT')); - const type = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - expect(type).to.be.equal(IdentityPublicKey.TYPES.ECDSA_HASH160); - }); - - it('should return BIP13_SCRIPT_HASH if address has p2sh type', () => { - const payoutScript = Script(Address.fromString('7UkJidhNjEPJCQnCTXeaJKbJmL4JuyV66w')); - const type = getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - expect(type).to.be.equal(IdentityPublicKey.TYPES.BIP13_SCRIPT_HASH); - }); - - it('should throw InvalidPayoutScriptError if address is not p2sh or p2pkh', () => { - const payoutScript = new Script(); - - try { - getWithdrawPubKeyTypeFromPayoutScript(payoutScript); - - expect.fail('should throw InvalidPayoutScriptError'); - } catch (e) { - expect(e).to.be.an.instanceOf(InvalidPayoutScriptError); - expect(e.getPayoutScript()).to.deep.equal(payoutScript); - } - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/handleNewMasternodeFactory.spec.js b/packages/js-drive/test/unit/identity/masternode/handleNewMasternodeFactory.spec.js deleted file mode 100644 index 84e5b382fbf..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/handleNewMasternodeFactory.spec.js +++ /dev/null @@ -1,178 +0,0 @@ -const createDPPMock = require('@dashevo/dpp/lib/test/mocks/createDPPMock'); -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Address = require('@dashevo/dashcore-lib/lib/address'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const handleNewMasternodeFactory = require('../../../../lib/identity/masternode/handleNewMasternodeFactory'); -const getSmlFixture = require('../../../../lib/test/fixtures/getSmlFixture'); -const createOperatorIdentifier = require('../../../../lib/identity/masternode/createOperatorIdentifier'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); -const createVotingIdentifier = require('../../../../lib/identity/masternode/createVotingIdentifier'); - -describe('handleNewMasternodeFactory', () => { - let handleNewMasternode; - let dppMock; - let createMasternodeIdentityMock; - let createRewardShareDocumentMock; - let fetchTransactionMock; - let transactionFixture; - let masternodeEntry; - let dataContract; - let blockInfo; - let identityFixture; - - beforeEach(function beforeEach() { - const smlFixture = getSmlFixture(); - [masternodeEntry] = smlFixture[0].mnList; - masternodeEntry.operatorPayoutAddress = 'yTCALGQTFNsA4pMPLTKAWdaLRmxfGpbujY'; - - dataContract = getDataContractFixture(); - - dppMock = createDPPMock(this.sinon); - - identityFixture = getIdentityFixture(); - - createMasternodeIdentityMock = this.sinon.stub().resolves(identityFixture); - createRewardShareDocumentMock = this.sinon.stub(); - - blockInfo = new BlockInfo(1, 0, Date.now()); - - transactionFixture = { - extraPayload: { - operatorReward: 0, - keyIDOwner: Buffer.alloc(20).fill('a').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('b').toString('hex'), - }, - }; - - fetchTransactionMock = this.sinon.stub().resolves(transactionFixture); - - handleNewMasternode = handleNewMasternodeFactory( - dppMock, - createMasternodeIdentityMock, - createRewardShareDocumentMock, - fetchTransactionMock, - ); - }); - - it('should create masternode identity', async () => { - masternodeEntry.payoutAddress = 'yRRwW957BJwL6SVVh3s8ASQYa2qXnduyfx'; - - const payoutAddress = Address.fromString(masternodeEntry.payoutAddress); - const payoutScript = new Script(payoutAddress); - - const result = await handleNewMasternode(masternodeEntry, dataContract, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(2); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.createdEntities[0].toObject()).to.deep.equal(identityFixture.toObject()); - expect(result.createdEntities[1].toObject()).to.deep.equal(identityFixture.toObject()); - - expect(fetchTransactionMock).to.be.calledOnceWithExactly(masternodeEntry.proRegTxHash); - expect(createMasternodeIdentityMock.getCall(0)).to.be.calledWithExactly( - blockInfo, - Identifier.from('HYyu6DdUQyiHZwzeWpmahu7AUrsEF9MKkRcrdQnKeNSj'), - Buffer.from('6161616161616161616161616161616161616161', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - payoutScript, - ); - - expect(createMasternodeIdentityMock.getCall(1)).to.be.calledWithExactly( - blockInfo, - Identifier.from('GVYoKVDd29gbmHzbVGepFjCbdymCS5Jq26CCiLnWNL6C'), - Buffer.from('6262626262626262626262626262626262626262', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - ); - - expect(createRewardShareDocumentMock).to.not.be.called(); - }); - - it('should not create voting identity if keyIDVoting equals keyIDOwner', async () => { - masternodeEntry.payoutAddress = 'yRRwW957BJwL6SVVh3s8ASQYa2qXnduyfx'; - - const payoutAddress = Address.fromString(masternodeEntry.payoutAddress); - const payoutScript = new Script(payoutAddress); - - transactionFixture.extraPayload.keyIDVoting = transactionFixture.extraPayload.keyIDOwner; - - fetchTransactionMock.resolves(transactionFixture); - - const result = await handleNewMasternode(masternodeEntry, dataContract, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(1); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.createdEntities[0].toJSON()).to.deep.equal(identityFixture.toJSON()); - - expect(fetchTransactionMock).to.be.calledOnceWithExactly(masternodeEntry.proRegTxHash); - expect(createMasternodeIdentityMock).to.be.calledOnceWithExactly( - blockInfo, - Identifier.from('HYyu6DdUQyiHZwzeWpmahu7AUrsEF9MKkRcrdQnKeNSj'), - Buffer.from('6161616161616161616161616161616161616161', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - payoutScript, - ); - - expect(createRewardShareDocumentMock).to.not.be.called(); - }); - - it('should create masternode identity and a document in rewards data contract with percentage', async () => { - transactionFixture.extraPayload.operatorReward = 10; - - const result = await handleNewMasternode(masternodeEntry, dataContract, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(3); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.createdEntities[0].toJSON()).to.deep.equal(identityFixture.toJSON()); - expect(result.createdEntities[1].toJSON()).to.deep.equal(identityFixture.toJSON()); - expect(result.createdEntities[2].toJSON()).to.deep.equal(identityFixture.toJSON()); - - const operatorIdentifier = createOperatorIdentifier(masternodeEntry); - const operatorPayoutAddress = Address.fromString(masternodeEntry.operatorPayoutAddress); - const operatorPayoutScript = new Script(operatorPayoutAddress); - - const votingIdentifier = createVotingIdentifier(masternodeEntry); - const payoutAddress = Address.fromString(masternodeEntry.payoutAddress); - const payoutScript = new Script(payoutAddress); - - expect(fetchTransactionMock).to.be.calledOnceWithExactly(masternodeEntry.proRegTxHash); - expect(createMasternodeIdentityMock).to.be.calledThrice(); - expect(createMasternodeIdentityMock.getCall(0)).to.be.calledWithExactly( - blockInfo, - Identifier.from('HYyu6DdUQyiHZwzeWpmahu7AUrsEF9MKkRcrdQnKeNSj'), - Buffer.from('6161616161616161616161616161616161616161', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - payoutScript, - ); - - expect(createMasternodeIdentityMock.getCall(1)).to.be.calledWithExactly( - blockInfo, - operatorIdentifier, - Buffer.from('951a3208ba531ea75aedd2dc0a9efc75f2c4d9492f1ee0a989b593bcd9722b1a101774d80a426552a9f91d24eb55af6e', 'hex'), - IdentityPublicKey.TYPES.BLS12_381, - operatorPayoutScript, - ); - - expect(createMasternodeIdentityMock.getCall(2)).to.be.calledWithExactly( - blockInfo, - votingIdentifier, - Buffer.from('6262626262626262626262626262626262626262', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - ); - - expect(createRewardShareDocumentMock).to.be.calledOnceWithExactly( - dataContract, - Identifier.from('HYyu6DdUQyiHZwzeWpmahu7AUrsEF9MKkRcrdQnKeNSj'), - Identifier.from('4Ftw1Euv5BJrUk73gKeELFsVqrfVXjbUTSt4tNZjBaVq'), - 10, - blockInfo, - ); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/handleUpdatedScriptPayoutFactory.spec.js b/packages/js-drive/test/unit/identity/masternode/handleUpdatedScriptPayoutFactory.spec.js deleted file mode 100644 index dec890be168..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/handleUpdatedScriptPayoutFactory.spec.js +++ /dev/null @@ -1,157 +0,0 @@ -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const Script = require('@dashevo/dashcore-lib/lib/script'); -const identitySchema = require('@dashevo/dpp/schema/identity/identity.json'); -const handleUpdatedScriptPayoutFactory = require('../../../../lib/identity/masternode/handleUpdatedScriptPayoutFactory'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); -const StorageResult = require('../../../../lib/storage/StorageResult'); - -describe('handleUpdatedScriptPayoutFactory', () => { - let handleUpdatedScriptPayout; - let getWithdrawPubKeyTypeFromPayoutScriptMock; - let getPublicKeyFromPayoutScriptMock; - let identity; - let blockInfo; - let identityRepositoryMock; - let identityPublicKeyRepositoryMock; - - beforeEach(function beforeEach() { - identity = getIdentityFixture(); - - blockInfo = new BlockInfo(1, 0, Date.now()); - - getWithdrawPubKeyTypeFromPayoutScriptMock = this.sinon.stub().returns( - IdentityPublicKey.TYPES.ECDSA_HASH160, - ); - - getPublicKeyFromPayoutScriptMock = this.sinon.stub().returns(Buffer.alloc(20, '0')); - - identityRepositoryMock = { - updateRevision: this.sinon.stub(), - fetch: this.sinon.stub().resolves(new StorageResult(identity, [])), - }; - - identityPublicKeyRepositoryMock = { - add: this.sinon.stub(), - disable: this.sinon.stub(), - }; - - handleUpdatedScriptPayout = handleUpdatedScriptPayoutFactory( - identityRepositoryMock, - identityPublicKeyRepositoryMock, - getWithdrawPubKeyTypeFromPayoutScriptMock, - getPublicKeyFromPayoutScriptMock, - ); - }); - - it('should not update identity if identityPublicKeys max length was reached', async () => { - const { maxItems } = identitySchema.properties.publicKeys; - for (let i = identity.getPublicKeys().length; i < maxItems; ++i) { - identity.publicKeys.push({ - data: 'fakePublicKey', - }); - } - - const newPubKeyData = Buffer.alloc(20, '0'); - - const result = await handleUpdatedScriptPayout( - identity.getId(), - newPubKeyData, - identity.publicKeys[0].getData(), - ); - - expect(result.createdEntities).to.have.lengthOf(0); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(identityRepositoryMock.updateRevision).to.not.be.called(); - expect(identityPublicKeyRepositoryMock.add).to.not.be.called(); - expect(identityPublicKeyRepositoryMock.disable).to.not.be.called(); - }); - - it('should add a public key and disable an old one', async () => { - const newPubKeyData = Buffer.alloc(20, '0'); - - const result = await handleUpdatedScriptPayout( - identity.getId(), - newPubKeyData, - blockInfo, - identity.publicKeys[0].getData(), - ); - - const newWithdrawalIdentityPublicKey = new IdentityPublicKey() - .setId(2) - .setType(IdentityPublicKey.TYPES.ECDSA_HASH160) - .setData(Buffer.from(newPubKeyData)) - .setReadOnly(true) - .setPurpose(IdentityPublicKey.PURPOSES.WITHDRAW) - .setSecurityLevel(IdentityPublicKey.SECURITY_LEVELS.MASTER); - - expect(identityRepositoryMock.updateRevision).to.be.calledOnceWithExactly( - identity.getId(), - 1, - blockInfo, - { useTransaction: true }, - ); - - expect(identityPublicKeyRepositoryMock.add).to.be.calledOnceWithExactly( - identity.getId(), - [newWithdrawalIdentityPublicKey], - blockInfo, - { useTransaction: true }, - ); - - expect(result.createdEntities).to.have.lengthOf(1); - expect(result.updatedEntities).to.have.lengthOf(1); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.createdEntities[0]).to.be.instanceOf(IdentityPublicKey); - expect(result.createdEntities[0].toObject()).to.deep.equal( - newWithdrawalIdentityPublicKey.toObject(), - ); - - expect(result.updatedEntities[0]).to.be.instanceOf(Identity); - expect(result.updatedEntities[0].toObject()).to.deep.equal(identity.toObject()); - }); - - it('should add public keys', async () => { - const newPubKeyData = Buffer.alloc(20, '0'); - - const result = await handleUpdatedScriptPayout( - identity.getId(), - newPubKeyData, - blockInfo, - new Script(), - ); - - const newWithdrawalIdentityPublicKey = new IdentityPublicKey() - .setId(2) - .setType(IdentityPublicKey.TYPES.ECDSA_HASH160) - .setData(Buffer.from(newPubKeyData)) - .setReadOnly(true) - .setPurpose(IdentityPublicKey.PURPOSES.WITHDRAW) - .setSecurityLevel(IdentityPublicKey.SECURITY_LEVELS.MASTER); - - expect(identityRepositoryMock.updateRevision).to.be.calledOnceWithExactly( - identity.getId(), - 1, - blockInfo, - { useTransaction: true }, - ); - - expect(identityPublicKeyRepositoryMock.add).to.be.calledOnceWithExactly( - identity.getId(), - [newWithdrawalIdentityPublicKey], - blockInfo, - { useTransaction: true }, - ); - - expect(result.createdEntities).to.have.lengthOf(1); - expect(result.updatedEntities).to.have.lengthOf(1); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.updatedEntities[0]).to.be.instanceOf(Identity); - expect(result.updatedEntities[0].toObject()).to.deep.equal(identity.toObject()); - }); -}); diff --git a/packages/js-drive/test/unit/identity/masternode/handleUpdatedVotingAddressFactory.spec.js b/packages/js-drive/test/unit/identity/masternode/handleUpdatedVotingAddressFactory.spec.js deleted file mode 100644 index d1c3ba3f140..00000000000 --- a/packages/js-drive/test/unit/identity/masternode/handleUpdatedVotingAddressFactory.spec.js +++ /dev/null @@ -1,102 +0,0 @@ -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const IdentityPublicKey = require('@dashevo/dpp/lib/identity/IdentityPublicKey'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); -const handleUpdatedVotingAddressFactory = require('../../../../lib/identity/masternode/handleUpdatedVotingAddressFactory'); -const StorageResult = require('../../../../lib/storage/StorageResult'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); - -describe('handleUpdatedVotingAddressFactory', () => { - let handleUpdatedVotingAddress; - let createMasternodeIdentityMock; - let smlEntry; - let identity; - let fetchTransactionMock; - let transactionFixture; - let identityRepositoryMock; - let blockInfo; - - beforeEach(function beforeEach() { - smlEntry = { - proRegTxHash: '5557273f5922d9925e2327908ddb128bcf8e055a04d86e23431809bedd077060', - confirmedHash: '0000003da09fd100c60ad5743c44257bb9220ad8162a9b6cae9d005c8e465dba', - service: '95.222.25.60:19997', - pubKeyOperator: '08b66151b81bd6a08bad2e68810ea07014012d6d804859219958a7fbc293689aa902bd0cd6db7a4699c9e88a4ae8c2c0', - votingAddress: 'yZRteAQ51BoeD3sJL1iGdt6HJLgkWGurw5', - isValid: false, - }; - - transactionFixture = { - extraPayload: { - operatorReward: 0, - keyIDOwner: Buffer.alloc(20).fill('a').toString('hex'), - keyIDVoting: Buffer.alloc(20).fill('b').toString('hex'), - }, - }; - - fetchTransactionMock = this.sinon.stub().resolves(transactionFixture); - - identity = getIdentityFixture(); - - identityRepositoryMock = { - update: this.sinon.stub(), - fetch: this.sinon.stub().resolves(new StorageResult(null, [])), - }; - - createMasternodeIdentityMock = this.sinon.stub(); - - blockInfo = new BlockInfo(1, 0, Date.now()); - - handleUpdatedVotingAddress = handleUpdatedVotingAddressFactory( - identityRepositoryMock, - createMasternodeIdentityMock, - fetchTransactionMock, - ); - }); - - it('should store updated identity', async () => { - createMasternodeIdentityMock.resolves(identity); - - const result = await handleUpdatedVotingAddress(smlEntry, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(1); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(result.createdEntities[0]).to.deep.equal(identity); - expect(createMasternodeIdentityMock).to.be.calledOnceWithExactly( - blockInfo, - Identifier.from('G1p14MYdpNRLNWuKgQ9SjJUPxfuaJMTwYjdRWu9sLzvL'), - Buffer.from('8fd1a9502c58ab103792693e951bf39f10ee46a9', 'hex'), - IdentityPublicKey.TYPES.ECDSA_HASH160, - ); - expect(fetchTransactionMock).to.be.calledWithExactly(smlEntry.proRegTxHash); - }); - - it('should not update identity if identity already exists', async () => { - identityRepositoryMock.fetch.resolves(new StorageResult(identity, [])); - - const result = await handleUpdatedVotingAddress(smlEntry, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(0); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(createMasternodeIdentityMock).to.not.be.called(); - expect(fetchTransactionMock).to.be.calledWithExactly(smlEntry.proRegTxHash); - }); - - it('should not update identity if owner and voting keys are the same', async () => { - transactionFixture.extraPayload.keyIDVoting = transactionFixture.extraPayload.keyIDOwner; - - fetchTransactionMock.resolves(transactionFixture); - - const result = await handleUpdatedVotingAddress(smlEntry, blockInfo); - - expect(result.createdEntities).to.have.lengthOf(0); - expect(result.updatedEntities).to.have.lengthOf(0); - expect(result.removedEntities).to.have.lengthOf(0); - - expect(createMasternodeIdentityMock).to.not.be.called(); - expect(fetchTransactionMock).to.be.calledWithExactly(smlEntry.proRegTxHash); - }); -}); diff --git a/packages/js-drive/test/unit/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.spec.js b/packages/js-drive/test/unit/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.spec.js deleted file mode 100644 index 1985b1b1623..00000000000 --- a/packages/js-drive/test/unit/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory.spec.js +++ /dev/null @@ -1,89 +0,0 @@ -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const Identifier = require('@dashevo/dpp/lib/identifier/Identifier'); - -const updateWithdrawalTransactionIdAndStatusFactory = require('../../../../lib/identity/withdrawals/updateWithdrawalTransactionIdAndStatusFactory'); -const BlockInfo = require('../../../../lib/blockExecution/BlockInfo'); - -describe('updateWithdrawalTransactionIdAndStatusFactory', () => { - let updateWithdrawalTransactionIdAndStatus; - let withdrawalsContractId; - let documentRepositoryMock; - let fetchDocumentsMock; - let document1Fixture; - let document2Fixture; - - beforeEach(function beforeEach() { - ([document1Fixture, document2Fixture] = getDocumentsFixture()); - - document1Fixture.set('transactionId', Buffer.alloc(32, 1)); - document2Fixture.set('transactionId', Buffer.alloc(32, 3)); - - withdrawalsContractId = Identifier.from(Buffer.alloc(32)); - - documentRepositoryMock = { - update: this.sinon.stub(), - }; - - fetchDocumentsMock = this.sinon.stub(); - fetchDocumentsMock.resolves([document1Fixture, document2Fixture]); - - updateWithdrawalTransactionIdAndStatus = updateWithdrawalTransactionIdAndStatusFactory( - documentRepositoryMock, - fetchDocumentsMock, - withdrawalsContractId, - ); - }); - - it('should update documents transactionId, status and revision', async () => { - const blockInfo = new BlockInfo(1, 1, 1); - - const coreChainLockedHeight = 42; - - const transactionIdMap = { - [Buffer.alloc(32, 1).toString('hex')]: Buffer.alloc(32, 2), - [Buffer.alloc(32, 3).toString('hex')]: Buffer.alloc(32, 4), - }; - - await updateWithdrawalTransactionIdAndStatus( - blockInfo, - coreChainLockedHeight, - transactionIdMap, - { - useTransaction: true, - }, - ); - - expect(fetchDocumentsMock).to.have.been.calledOnceWithExactly( - withdrawalsContractId, - 'withdrawal', - { - where: [ - ['status', '==', 1], - ['transactionId', 'in', [Buffer.alloc(32, 1), Buffer.alloc(32, 3)]], - ], - orderBy: [ - ['transactionId', 'asc'], - ], - useTransaction: true, - }, - ); - - expect(documentRepositoryMock.update).to.have.been.calledTwice(); - expect(documentRepositoryMock.update.getCall(0).args).to.deep.equal( - [document1Fixture, blockInfo, { useTransaction: true }], - ); - expect(documentRepositoryMock.update.getCall(1).args).to.deep.equal( - [document2Fixture, blockInfo, { useTransaction: true }], - ); - - expect(document1Fixture.get('transactionSignHeight')).to.deep.equal(coreChainLockedHeight); - expect(document1Fixture.get('transactionId')).to.deep.equal(Buffer.alloc(32, 2)); - expect(document1Fixture.get('status')).to.deep.equal(2); - expect(document1Fixture.getRevision()).to.deep.equal(2); - - expect(document2Fixture.get('transactionSignHeight')).to.deep.equal(coreChainLockedHeight); - expect(document2Fixture.get('transactionId')).to.deep.equal(Buffer.alloc(32, 4)); - expect(document2Fixture.get('status')).to.deep.equal(2); - expect(document2Fixture.getRevision()).to.deep.equal(2); - }); -}); diff --git a/packages/js-drive/test/unit/util/ExecutionTimer.spec.js b/packages/js-drive/test/unit/util/ExecutionTimer.spec.js deleted file mode 100644 index b1f3aff7a98..00000000000 --- a/packages/js-drive/test/unit/util/ExecutionTimer.spec.js +++ /dev/null @@ -1,43 +0,0 @@ -const ExecutionTimer = require('../../../lib/util/ExecutionTimer'); -const wait = require('../../../lib/util/wait'); - -describe('ExecutionTimer', () => { - let timer; - - beforeEach(() => { - timer = new ExecutionTimer(); - }); - - describe('#startTimer', () => { - it('should throw an error if timer already started', () => { - timer.startTimer('some'); - - try { - timer.startTimer('some'); - expect.fail('An error was not thrown'); - } catch (e) { - expect(e.message).to.equal('some timer is already started'); - } - }); - }); - - describe('#stopTimer', () => { - it('should throw an error if timer has not been started', () => { - try { - timer.stopTimer('some'); - expect.fail('An error was not thrown'); - } catch (e) { - expect(e.message).to.equal('some timer is not started'); - } - }); - }); - - it('should measure function execution time', async () => { - // TODO: maybe there should be a better way to do it - timer.startTimer('some'); - await wait(1500); - const timings = timer.stopTimer('some'); - - expect(parseInt(timings, 10)).to.equal(1); - }); -}); diff --git a/packages/js-drive/test/unit/util/errorHandlerFactory.spec.js b/packages/js-drive/test/unit/util/errorHandlerFactory.spec.js deleted file mode 100644 index 466f87948a4..00000000000 --- a/packages/js-drive/test/unit/util/errorHandlerFactory.spec.js +++ /dev/null @@ -1,142 +0,0 @@ -const errorHandlerFactory = require('../../../lib/errorHandlerFactory'); -const LoggerMock = require('../../../lib/test/mock/LoggerMock'); - -describe('errorHandlerFactory', () => { - let errorHandler; - let containerMock; - let loggerMock; - let closeAbciServerMock; - - beforeEach(function beforeEach() { - this.sinon.stub(console, 'log'); - this.sinon.stub(console, 'error'); - this.sinon.stub(process, 'exit'); - - containerMock = { - dispose: this.sinon.stub(), - }; - - closeAbciServerMock = this.sinon.stub(); - - loggerMock = new LoggerMock(this.sinon); - - errorHandler = errorHandlerFactory( - loggerMock, - containerMock, - closeAbciServerMock, - ); - }); - - it('should close server, log error, dispose container and exit process on first call', async () => { - const error = new Error('message'); - - await errorHandler(error); - - expect(closeAbciServerMock).to.be.calledOnceWithExactly(); - - // Error face is printed - // eslint-disable-next-line no-console - expect(console.log).to.be.calledOnce(); - - expect(loggerMock.fatal).to.be.calledOnceWithExactly({ err: error }, error.message); - - expect(containerMock.dispose).to.be.calledOnceWithExactly(); - - expect(process.exit).to.be.calledOnceWithExactly(1); - }); - - it('should use consensus logger if it\'s present', async function it() { - const error = new Error('message'); - - const contextLogger = new LoggerMock(this.sinon); - - error.contextLogger = contextLogger; - - await errorHandler(error); - - expect(loggerMock.fatal).to.not.be.called(); - expect(contextLogger.fatal).to.be.calledOnceWithExactly({ err: error }, error.message); - - expect(containerMock.dispose).to.be.calledOnceWithExactly(); - - expect(process.exit).to.be.calledOnceWithExactly(1); - - // eslint-disable-next-line no-console - expect(console.log).to.be.calledOnce(); - }); - - it('should collect an error on second call', async () => { - const error1 = new Error('error1'); - const error2 = new Error('error2'); - - await Promise.all([ - errorHandler(error1), - errorHandler(error2), - ]); - - expect(closeAbciServerMock).to.be.calledOnceWithExactly(); - - // Error face is printed - // eslint-disable-next-line no-console - expect(console.log).to.be.calledOnce(); - - expect(loggerMock.fatal).to.be.calledTwice(); - - expect(loggerMock.fatal.getCall(0)).to.be.calledWithExactly({ err: error1 }, error1.message); - expect(loggerMock.fatal.getCall(1)).to.be.calledWithExactly({ err: error2 }, error2.message); - - expect(containerMock.dispose).to.be.calledOnceWithExactly(); - - expect(process.exit).to.be.calledOnceWithExactly(1); - }); - - it('should dispose container and output error in console if it was thrown during error handling', async () => { - const closeError = new Error('close server error'); - - closeAbciServerMock.throws(closeError); - - const error = new Error('message'); - - await errorHandler(error); - - expect(closeAbciServerMock).to.be.calledOnceWithExactly(); - - // Error face is printed - // eslint-disable-next-line no-console - expect(console.log).to.not.be.called(); - - expect(loggerMock.fatal).to.not.be.called(); - - expect(containerMock.dispose).to.be.calledOnceWithExactly(); - - // eslint-disable-next-line no-console - expect(console.error).to.be.calledOnceWithExactly(closeError); - - expect(process.exit).to.be.calledOnceWithExactly(1); - }); - - it('should output error in console if it was thrown during dispose', async () => { - const disposeError = new Error('dispose error'); - - containerMock.dispose.throws(disposeError); - - const error = new Error('message'); - - await errorHandler(error); - - expect(closeAbciServerMock).to.be.calledOnceWithExactly(); - - // Error face is printed - // eslint-disable-next-line no-console - expect(console.log).to.be.calledOnce(); - - expect(loggerMock.fatal).to.be.calledOnceWithExactly({ err: error }, error.message); - - expect(containerMock.dispose).to.be.calledOnceWithExactly(); - - // eslint-disable-next-line no-console - expect(console.error).to.be.calledOnceWithExactly(disposeError); - - expect(process.exit).to.be.calledOnceWithExactly(1); - }); -}); diff --git a/packages/js-drive/test/unit/util/rejectAfter.spec.js b/packages/js-drive/test/unit/util/rejectAfter.spec.js deleted file mode 100644 index 31a281a6fa6..00000000000 --- a/packages/js-drive/test/unit/util/rejectAfter.spec.js +++ /dev/null @@ -1,34 +0,0 @@ -const rejectAfter = require('../../../lib/util/rejectAfter'); - -describe('rejectAfter', () => { - it('should return resolved promise', async () => { - const resolvedValue = 1; - const promise = Promise.resolve(resolvedValue); - - const actualValue = await rejectAfter(promise, new Error(), 1000); - - expect(actualValue).to.equal(resolvedValue); - }); - - it('should return rejected promise', (done) => { - const error = new Error(); - const promise = Promise.reject(error); - - const actualPromise = rejectAfter(promise, new Error(), 1000); - - expect(actualPromise).to.be.rejectedWith(error).and.notify(done); - }); - - it('should reject unresolved promise after specified time', function it(done) { - const promise = new Promise(() => {}); - const error = new Error(); - - const clock = this.sinon.useFakeTimers(); - - const rejectedPromise = rejectAfter(promise, error, 1000); - - clock.next(); - - expect(rejectedPromise).to.be.rejectedWith(error).and.notify(done); - }); -}); diff --git a/packages/js-drive/test/unit/util/sanitizeUrl.spec.js b/packages/js-drive/test/unit/util/sanitizeUrl.spec.js deleted file mode 100644 index 73c40d47682..00000000000 --- a/packages/js-drive/test/unit/util/sanitizeUrl.spec.js +++ /dev/null @@ -1,13 +0,0 @@ -const { expect } = require('chai'); -const sanitizeUrl = require('../../../lib/util/sanitizeUrl'); - -describe('sanitizeUrl', () => { - it('should sanitize an url', () => { - const sanitized = sanitizeUrl('https://www.dash.org?something=true'); - expect(sanitized).to.equal('https://www.dash.org'); - }); - it('should handle non RFC path', () => { - const sanitized = sanitizeUrl('/foo;jsessionid=123456'); - expect(sanitized).to.equal('/foo'); - }); -}); diff --git a/packages/js-drive/test/unit/util/wait.spec.js b/packages/js-drive/test/unit/util/wait.spec.js deleted file mode 100644 index 353cf3606b0..00000000000 --- a/packages/js-drive/test/unit/util/wait.spec.js +++ /dev/null @@ -1,30 +0,0 @@ -const wait = require('../../../lib/util/wait'); - -describe('wait', () => { - let clock; - let executeWithWait; - - beforeEach(function beforeEach() { - clock = this.sinon.useFakeTimers(); - - executeWithWait = async (f) => { - await wait(1200); - f(); - }; - }); - - it('should delay execution of a flow for a specified amount of milliseconds', function it(done) { - const callback = this.sinon.stub(); - - executeWithWait(callback).then(() => { - expect(callback).to.have.been.calledOnce(); - done(); - }).catch(done); - - clock.tick(1199); - - expect(callback).to.have.not.been.called(); - - clock.tick(1); - }); -}); diff --git a/packages/js-drive/test/unit/validator/Validator.spec.js b/packages/js-drive/test/unit/validator/Validator.spec.js deleted file mode 100644 index c3544e8140b..00000000000 --- a/packages/js-drive/test/unit/validator/Validator.spec.js +++ /dev/null @@ -1,37 +0,0 @@ -const { expect } = require('chai'); -const Validator = require('../../../lib/validator/Validator'); -const ValidatorNetworkInfo = require('../../../lib/validator/ValidatorNetworkInfo'); - -describe('Validator', () => { - let networkInfo; - let host; - let port; - - beforeEach(() => { - host = '192.168.65.2'; - port = 26656; - networkInfo = new ValidatorNetworkInfo(host, port); - }); - - describe('#createFromQuorumMember', () => { - it('should create an instance from quorum member info', () => { - const memberInfo = { - proTxHash: Buffer.alloc(0, 32).toString('hex'), - pubKeyShare: Buffer.alloc(1, 32).toString('hex'), - }; - - const instance = Validator.createFromQuorumMember(memberInfo, networkInfo); - - expect(instance).to.be.an.instanceOf(Validator); - expect(instance.getProTxHash()).to.deep.equal( - Buffer.from(memberInfo.proTxHash, 'hex'), - ); - expect(instance.getPublicKeyShare()).to.deep.equal( - Buffer.from(memberInfo.pubKeyShare, 'hex'), - ); - expect(instance.getNetworkInfo()).to.be.an.instanceOf(ValidatorNetworkInfo); - expect(instance.getNetworkInfo().getHost()).to.equal(host); - expect(instance.getNetworkInfo().getPort()).to.equal(port); - }); - }); -}); diff --git a/packages/js-drive/test/unit/validator/ValidatorNetworkInfo.spec.js b/packages/js-drive/test/unit/validator/ValidatorNetworkInfo.spec.js deleted file mode 100644 index 92ba6b25946..00000000000 --- a/packages/js-drive/test/unit/validator/ValidatorNetworkInfo.spec.js +++ /dev/null @@ -1,24 +0,0 @@ -const ValidatorNetworkInfo = require('../../../lib/validator/ValidatorNetworkInfo'); - -describe('ValidatorNetworkInfo', () => { - let validatorNetworkInfo; - let host; - let port; - - beforeEach(() => { - host = '192.168.65.2'; - port = 26656; - }); - - it('should return host', () => { - validatorNetworkInfo = new ValidatorNetworkInfo(host, port); - - expect(validatorNetworkInfo.getHost()).to.equal(host); - }); - - it('should return port', () => { - validatorNetworkInfo = new ValidatorNetworkInfo(host, port); - - expect(validatorNetworkInfo.getPort()).to.equal(port); - }); -}); diff --git a/packages/js-drive/test/unit/validator/ValidatorSet.spec.js b/packages/js-drive/test/unit/validator/ValidatorSet.spec.js deleted file mode 100644 index 7e9e0e3db5f..00000000000 --- a/packages/js-drive/test/unit/validator/ValidatorSet.spec.js +++ /dev/null @@ -1,253 +0,0 @@ -const Long = require('long'); - -const QuorumEntry = require('@dashevo/dashcore-lib/lib/deterministicmnlist/QuorumEntry'); - -const SimplifiedMNListEntry = require('@dashevo/dashcore-lib/lib/deterministicmnlist/SimplifiedMNListEntry'); -const ValidatorSet = require('../../../lib/validator/ValidatorSet'); -const getSmlFixture = require('../../../lib/test/fixtures/getSmlFixture'); -const ValidatorSetIsNotInitializedError = require('../../../lib/validator/errors/ValidatorSetIsNotInitializedError'); -const Validator = require('../../../lib/validator/Validator'); -const PublicKeyShareIsNotPresentError = require('../../../lib/validator/errors/PublicKeyShareIsNotPresentError'); - -describe('ValidatorSet', () => { - let smlStoreMock; - let simplifiedMasternodeListMock; - let smlDiffMock; - let smlMock; - let quorumMembers; - let rotationEntropy; - let quorumEntry; - let coreHeight; - let coreRpcClientMock; - let validatorNetworkPort; - - let validatorSetLLMQType; - - let validatorSet; - let getRandomQuorumMock; - let fetchQuorumMembersMock; - - beforeEach(function beforeEach() { - coreHeight = 42; - - validatorSetLLMQType = 4; - - quorumEntry = new QuorumEntry(getSmlFixture()[0].newQuorums[0]); - - smlDiffMock = { - blockHash: 'some block hash', - }; - - smlMock = { - getQuorum: this.sinon.stub().returns(quorumEntry), - toSimplifiedMNListDiff: this.sinon.stub().returns(smlDiffMock), - getQuorumsOfType: this.sinon.stub().returns( - getSmlFixture()[0].newQuorums.filter((quorum) => quorum.llmqType === 1), - ), - getValidMasternodesList: this.sinon.stub().returns([ - new SimplifiedMNListEntry({ - proRegTxHash: 'c286807d463b06c7aba3b9a60acf64c1fc03da8c1422005cd9b4293f08cf0562', - confirmedHash: '4eb56228c535db3b234907113fd41d57bcc7cdcb8e0e00e57590af27ee88c119', - service: '192.168.65.2:20101', - pubKeyOperator: '809519c5f6f3be1c08782ac42ae9a83b6c7205eba43f9a96a4f032ec7a73f1a7c25fa78cce0d6d9c135f7e2c28527179', - votingAddress: 'yXmprXYP51uzfMyndtWwxz96MnkCKkFc9x', - nType: 0, - isValid: true, - }), - new SimplifiedMNListEntry({ - proRegTxHash: 'a3e1edc6bd352eeaf0ae58e30781ef4b127854241a3fe7fddf36d5b7e1dc2b3f', - confirmedHash: '27a0b637b56af038c45e2fd1f06c2401c8dadfa28ca5e0d19ca836cc984a8378', - service: '192.168.65.2:20201', - pubKeyOperator: '987a4873caba62cd45a2f7d4aa6d94519ee6753e9bef777c927cb94ade768a542b0ff34a93231d3a92b4e75ffdaa366e', - votingAddress: 'ycL7L4mhYoaZdm9TH85svvpfeKtdfo249u', - nType: 0, - isValid: true, - }), - ]), - }; - - smlStoreMock = { - getSMLbyHeight: this.sinon.stub().returns(smlMock), - getCurrentSML: this.sinon.stub().returns(smlMock), - }; - - simplifiedMasternodeListMock = { - getStore: this.sinon.stub().returns(smlStoreMock), - }; - - rotationEntropy = Buffer.from('00000ac05a06682172d8b49be7c9ddc4189126d7200ebf0fc074c433ae74b596', 'hex'); - - quorumMembers = [ - { - proTxHash: 'c286807d463b06c7aba3b9a60acf64c1fc03da8c1422005cd9b4293f08cf0562', - pubKeyOperator: '06abc1c890c9da4e513d52f20da1882228bfa2db4bb29cbd064e1b2a61d9dcdadcf0784fd1371338c8ad1bf323d87ae6', - valid: true, - pubKeyShare: '00d7bb8d6753865c367824691610dcc313b661b7e024e36e82f8af33f5701caddb2668dadd1e647d8d7d5b30e37ebbcf', - }, - { - proTxHash: 'a3e1edc6bd352eeaf0ae58e30781ef4b127854241a3fe7fddf36d5b7e1dc2b3f', - pubKeyOperator: '04d748ba0efeb7a8f8548e0c22b4c188c293a19837a1c5440649279ba73ead0c62ac1e840050a10a35e0ae05659d2a8d', - valid: true, - pubKeyShare: '86d0992f5c73b8f57101c34a0c4ebb17d962bb935a738c1ef1e2bb1c25034d8e4a0a2cc96e0ebc69a7bf3b8b67b2de5f', - }, - { - proTxHash: 'a3e1edc6bd352eeaf0ae58e30781ef4b127854241a3fe7fddf36d5b7e1dc2b3f', - pubKeyOperator: '04d748ba0efeb7a8f8548e0c22b4c188c293a19837a1c5440649279ba73ead0c62ac1e840050a10a35e0ae05659d2a8d', - valid: false, - }, - ]; - - getRandomQuorumMock = this.sinon.stub().resolves(quorumEntry); - - fetchQuorumMembersMock = this.sinon.stub().resolves(quorumMembers); - - const notMasternodeError = new Error(); - notMasternodeError.code = -32603; - - coreRpcClientMock = { - masternode: this.sinon.stub().throws(notMasternodeError), - }; - - validatorNetworkPort = 26656; - - validatorSet = new ValidatorSet( - simplifiedMasternodeListMock, - getRandomQuorumMock, - fetchQuorumMembersMock, - validatorSetLLMQType, - coreRpcClientMock, - validatorNetworkPort, - ); - }); - - describe('initialize', () => { - it('should initialize with specified core height', async () => { - await validatorSet.initialize(coreHeight); - - expect(smlStoreMock.getSMLbyHeight).to.be.calledOnceWithExactly(coreHeight); - - expect(getRandomQuorumMock).to.be.calledOnceWithExactly( - smlMock, - validatorSetLLMQType, - Buffer.from(smlDiffMock.blockHash, 'hex'), - coreHeight, - ); - - expect(fetchQuorumMembersMock).to.be.calledOnceWithExactly( - validatorSetLLMQType, - quorumEntry.quorumHash, - ); - - expect(smlStoreMock.getCurrentSML().getValidMasternodesList).to.be.calledOnce(); - }); - - it('should throw an error if the node is a quorum member and doesn\'t receive public key shares', async () => { - coreRpcClientMock.masternode.resolves({ - result: { - proTxHash: quorumMembers[0].proTxHash, - }, - }); - - quorumMembers[2].valid = true; - - try { - await validatorSet.initialize(coreHeight); - - expect.fail('should throw PublicKeyShareIsNotPresentError'); - } catch (e) { - expect(e).to.be.instanceOf(PublicKeyShareIsNotPresentError); - expect(e.getMember()).to.be.equal(quorumMembers[2]); - } - }); - }); - - describe('rotate', () => { - it('should rotate validator set with specified core height and entropy if height divisible by ROTATION_BLOCK_INTERVAL', async () => { - const height = Long.fromInt(ValidatorSet.ROTATION_BLOCK_INTERVAL); - - const result = await validatorSet.rotate( - height, - coreHeight, - rotationEntropy, - ); - - expect(result).to.be.true(); - - expect(smlStoreMock.getSMLbyHeight).to.be.calledOnceWithExactly(coreHeight); - - expect(getRandomQuorumMock).to.be.calledOnceWithExactly( - smlMock, - validatorSetLLMQType, - rotationEntropy, - coreHeight, - ); - - expect(fetchQuorumMembersMock).to.be.calledOnceWithExactly( - validatorSetLLMQType, - quorumEntry.quorumHash, - ); - - expect(smlStoreMock.getCurrentSML().getValidMasternodesList).to.be.calledOnce(); - }); - - it('should not rotate validator set if height not divisible by ROTATION_BLOCK_INTERVAL', async () => { - const height = Long.fromInt(42); - - const result = await validatorSet.rotate( - height, - coreHeight, - rotationEntropy, - ); - - expect(result).to.be.false(); - - expect(smlStoreMock.getSMLbyHeight).to.be.calledOnceWithExactly(coreHeight); - - expect(getRandomQuorumMock).to.not.be.called(); - - expect(fetchQuorumMembersMock).to.not.be.called(); - }); - }); - - describe('getQuorum', () => { - it('should return QuorumEntry', async () => { - await validatorSet.initialize(coreHeight); - - const result = validatorSet.getQuorum(); - - expect(result).to.equals(quorumEntry); - }); - - it('should thrown an error if ValidatorSet is not initialized', () => { - try { - validatorSet.getQuorum(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(ValidatorSetIsNotInitializedError); - } - }); - }); - - describe('getValidators', () => { - it('should return array of validators', async () => { - await validatorSet.initialize(coreHeight); - - const result = validatorSet.getValidators(); - - expect(result).to.have.lengthOf(2); - expect(result[0]).to.be.instanceOf(Validator); - expect(result[1]).to.be.instanceOf(Validator); - }); - - it('should thrown an error if ValidatorSet is not initialized', () => { - try { - validatorSet.getValidators(); - - expect.fail('should throw an error'); - } catch (e) { - expect(e).to.be.instanceOf(ValidatorSetIsNotInitializedError); - } - }); - }); -}); diff --git a/packages/rs-drive-nodejs/.eslintrc b/packages/rs-drive-nodejs/.eslintrc deleted file mode 100644 index 6de4b115694..00000000000 --- a/packages/rs-drive-nodejs/.eslintrc +++ /dev/null @@ -1,35 +0,0 @@ -{ - "extends": "airbnb-base", - "env": { - "es2021": true, - "node": true - }, - "rules": { - "no-plusplus": 0, - "eol-last": [ - "error", - "always" - ], - "no-continue": "off", - "class-methods-use-this": "off", - "no-await-in-loop": "off", - "no-restricted-syntax": [ - "error", - { - "selector": "LabeledStatement", - "message": "Labels are a form of GOTO; using them makes code confusing and hard to maintain and understand." - }, - { - "selector": "WithStatement", - "message": "`with` is disallowed in strict mode because it makes code impossible to predict and optimize." - } - ], - "curly": [ - "error", - "all" - ] - }, - "globals": { - "BigInt": true - } -} diff --git a/packages/rs-drive-nodejs/.gitignore b/packages/rs-drive-nodejs/.gitignore deleted file mode 100644 index b645ad69ce8..00000000000 --- a/packages/rs-drive-nodejs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -prebuilds -test_data diff --git a/packages/rs-drive-nodejs/.mocharc.yml b/packages/rs-drive-nodejs/.mocharc.yml deleted file mode 100644 index 53f2f870b5e..00000000000 --- a/packages/rs-drive-nodejs/.mocharc.yml +++ /dev/null @@ -1,2 +0,0 @@ -exit: true -timeout: 10000 diff --git a/packages/rs-drive-nodejs/Cargo.toml b/packages/rs-drive-nodejs/Cargo.toml deleted file mode 100644 index 6c38ec29284..00000000000 --- a/packages/rs-drive-nodejs/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "drive-nodejs" -version = "0.24.0-dev.1" -description = "GroveDB node.js bindings" -edition = "2021" -license = "MIT" -private = true - -[lib] -crate-type = ["cdylib"] - -[dependencies] -drive = { path = "../rs-drive", features = ["fixtures-and-mocks"] } -drive-abci = { path = "../rs-drive-abci" } -num = "0.4.0" - -[dependencies.neon] -version = "0.10.1" -default-features = false -features = ["napi-6", "event-queue-api", "try-catch-api"] - -[features] -enable-mocking = [] diff --git a/packages/rs-drive-nodejs/Drive.js b/packages/rs-drive-nodejs/Drive.js deleted file mode 100644 index d1ac2239a74..00000000000 --- a/packages/rs-drive-nodejs/Drive.js +++ /dev/null @@ -1,940 +0,0 @@ -const { promisify } = require('util'); -const cbor = require('cbor'); -const Document = require('@dashevo/dpp/lib/document/Document'); -const DataContract = require('@dashevo/dpp/lib/dataContract/DataContract'); -const Identity = require('@dashevo/dpp/lib/identity/Identity'); -const decodeProtocolEntityFactory = require('@dashevo/dpp/lib/decodeProtocolEntityFactory'); - -// This file is crated when run `npm run build`. The actual source file that -// exports those functions is ./src/lib.rs -const { - driveOpen, - driveClose, - driveCreateInitialStateStructure, - driveFetchContract, - driveCreateContract, - driveUpdateContract, - driveCreateDocument, - driveUpdateDocument, - driveDeleteDocument, - driveQueryDocuments, - driveProveDocumentsQuery, - driveInsertIdentity, - driveFetchIdentity, - driveFetchIdentityBalance, - driveFetchIdentityBalanceWithCosts, - driveFetchIdentityBalanceIncludeDebtWithCosts, - driveFetchProvedIdentity, - driveFetchManyProvedIdentities, - driveFetchIdentityWithCosts, - driveAddToIdentityBalance, - driveAddKeysToIdentity, - driveDisableIdentityKeys, - driveUpdateIdentityRevision, - driveRemoveFromIdentityBalance, - driveApplyFeesToIdentityBalance, - driveFetchLatestWithdrawalTransactionIndex, - abciInitChain, - abciBlockBegin, - abciBlockEnd, - abciAfterFinalizeBlock, - calculateStorageFeeDistributionAmountAndLeftovers, - driveFetchIdentitiesByPublicKeyHashes, - driveProveIdentitiesByPublicKeyHashes, - driveAddToSystemCredits, -} = require('neon-load-or-build')({ - dir: __dirname, -}); - -const GroveDB = require('./GroveDB'); -const FeeResult = require('./FeeResult'); - -const { appendStackAsync, appendStack } = require('./appendStack'); - -const decodeProtocolEntity = decodeProtocolEntityFactory(); - -// Convert the Drive methods from using callbacks to returning promises -const driveCloseAsync = appendStackAsync(promisify(driveClose)); -const driveCreateInitialStateStructureAsync = appendStackAsync( - promisify(driveCreateInitialStateStructure), -); -const driveFetchContractAsync = appendStackAsync(promisify(driveFetchContract)); -const driveCreateContractAsync = appendStackAsync(promisify(driveCreateContract)); -const driveUpdateContractAsync = appendStackAsync(promisify(driveUpdateContract)); -const driveCreateDocumentAsync = appendStackAsync(promisify(driveCreateDocument)); -const driveUpdateDocumentAsync = appendStackAsync(promisify(driveUpdateDocument)); -const driveDeleteDocumentAsync = appendStackAsync(promisify(driveDeleteDocument)); -const driveQueryDocumentsAsync = appendStackAsync(promisify(driveQueryDocuments)); -const driveProveDocumentsQueryAsync = appendStackAsync(promisify(driveProveDocumentsQuery)); -const driveFetchLatestWithdrawalTransactionIndexAsync = appendStackAsync( - promisify(driveFetchLatestWithdrawalTransactionIndex), -); -const driveInsertIdentityAsync = appendStackAsync(promisify(driveInsertIdentity)); -const driveFetchIdentityAsync = appendStackAsync(promisify(driveFetchIdentity)); -const driveFetchProvedIdentityAsync = appendStackAsync(promisify(driveFetchProvedIdentity)); -const driveFetchIdentityBalanceAsync = appendStackAsync(promisify(driveFetchIdentityBalance)); -const driveFetchIdentityBalanceWithCostsAsync = appendStackAsync( - promisify(driveFetchIdentityBalanceWithCosts), -); -const driveFetchIdentityBalanceIncludeDebtWithCostsAsync = appendStackAsync( - promisify(driveFetchIdentityBalanceIncludeDebtWithCosts), -); - -const driveFetchManyProvedIdentitiesAsync = appendStackAsync( - promisify(driveFetchManyProvedIdentities), -); -const driveFetchIdentityWithCostsAsync = appendStackAsync(promisify(driveFetchIdentityWithCosts)); -const driveAddToIdentityBalanceAsync = appendStackAsync(promisify(driveAddToIdentityBalance)); -const driveAddToSystemCreditsAsync = appendStackAsync(promisify(driveAddToSystemCredits)); -const driveFetchIdentitiesByPublicKeyHashesAsync = appendStackAsync( - promisify(driveFetchIdentitiesByPublicKeyHashes), -); -const driveProveIdentitiesByPublicKeyHashesAsync = appendStackAsync( - promisify(driveProveIdentitiesByPublicKeyHashes), -); -const driveAddKeysToIdentityAsync = appendStackAsync(promisify(driveAddKeysToIdentity)); -const driveDisableIdentityKeysAsync = appendStackAsync(promisify(driveDisableIdentityKeys)); -const driveUpdateIdentityRevisionAsync = appendStackAsync(promisify(driveUpdateIdentityRevision)); -const driveRemoveFromIdentityBalanceAsync = appendStackAsync( - promisify(driveRemoveFromIdentityBalance), -); -const driveApplyFeesToIdentityBalanceAsync = appendStackAsync( - promisify(driveApplyFeesToIdentityBalance), -); -const abciInitChainAsync = appendStackAsync(promisify(abciInitChain)); -const abciBlockBeginAsync = appendStackAsync(promisify(abciBlockBegin)); -const abciBlockEndAsync = appendStackAsync(promisify(abciBlockEnd)); -const abciAfterFinalizeBlockAsync = appendStackAsync(promisify(abciAfterFinalizeBlock)); - -const calculateStorageFeeDistributionAmountAndLeftoversWithStack = appendStack( - calculateStorageFeeDistributionAmountAndLeftovers, -); - -// Wrapper class for the boxed `Drive` for idiomatic JavaScript usage -class Drive { - /** - * @param {string} dbPath - * @param {Object} config - * @param {number} config.dataContractsGlobalCacheSize - * @param {number} config.dataContractsBlockCacheSize - */ - constructor(dbPath, config) { - this.drive = driveOpen(dbPath, config); - this.groveDB = new GroveDB(this.drive); - } - - /** - * @returns {GroveDB} - */ - getGroveDB() { - return this.groveDB; - } - - /** - * @returns {Promise} - */ - async close() { - return driveCloseAsync.call(this.drive); - } - - /** - * @param {boolean} [useTransaction=false] - * - * @returns {Promise<[number, number]>} - */ - async createInitialStateStructure(useTransaction = false) { - return driveCreateInitialStateStructureAsync.call(this.drive, useTransaction); - } - - /** - * @param {Buffer|Identifier} id - * @param {number} [epochIndex] - * @param {boolean} [useTransaction=false] - * - * @returns {Promise<[DataContract|null, FeeResult]>} - */ - async fetchContract(id, epochIndex = undefined, useTransaction = false) { - return driveFetchContractAsync.call( - this.drive, - Buffer.from(id), - epochIndex, - useTransaction, - ).then(([encodedDataContract, innerFeeResult]) => { - let dataContract = encodedDataContract; - - if (encodedDataContract !== null) { - const [protocolVersion, rawDataContract] = decodeProtocolEntity( - encodedDataContract, - ); - - rawDataContract.protocolVersion = protocolVersion; - - dataContract = new DataContract(rawDataContract); - } - - const result = [dataContract]; - - if (innerFeeResult) { - result.push(new FeeResult(innerFeeResult)); - } - - return result; - }); - } - - /** - * @param {DataContract} dataContract - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async createContract(dataContract, blockInfo, useTransaction = false, dryRun = false) { - return driveCreateContractAsync.call( - this.drive, - dataContract.toBuffer(), - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {DataContract} dataContract - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async updateContract(dataContract, blockInfo, useTransaction = false, dryRun = false) { - return driveUpdateContractAsync.call( - this.drive, - dataContract.toBuffer(), - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Document} document - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async createDocument(document, blockInfo, useTransaction = false, dryRun = false) { - return driveCreateDocumentAsync.call( - this.drive, - document.toBuffer(), - document.getDataContractId().toBuffer(), - document.getType(), - document.getOwnerId().toBuffer(), - true, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Document} document - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async updateDocument(document, blockInfo, useTransaction = false, dryRun = false) { - return driveUpdateDocumentAsync.call( - this.drive, - document.toBuffer(), - document.getDataContractId().toBuffer(), - document.getType(), - document.getOwnerId().toBuffer(), - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Identifier} dataContractId - * @param {string} documentType - * @param {Identifier} documentId - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async deleteDocument( - dataContractId, - documentType, - documentId, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveDeleteDocumentAsync.call( - this.drive, - documentId.toBuffer(), - dataContractId.toBuffer(), - documentType, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * - * @param {DataContract} dataContract - * @param {string} documentType - * @param {number} [epochIndex] - * @param [query] - * @param [query.where] - * @param [query.limit] - * @param [query.startAt] - * @param [query.startAfter] - * @param [query.orderBy] - * @param {boolean} [useTransaction=false] - * - * @returns {Promise<[Document[], number]>} - */ - async queryDocuments( - dataContract, - documentType, - epochIndex = undefined, - query = {}, - useTransaction = false, - ) { - const encodedQuery = await cbor.encodeAsync(query); - - const [encodedDocuments, , processingFee] = await driveQueryDocumentsAsync.call( - this.drive, - encodedQuery, - dataContract.getId().toBuffer(), - documentType, - epochIndex, - useTransaction, - ); - - const documents = encodedDocuments.map((encodedDocument) => { - const [protocolVersion, rawDocument] = decodeProtocolEntity(encodedDocument); - - rawDocument.$protocolVersion = protocolVersion; - - return new Document(rawDocument, dataContract); - }); - - return [ - documents, - processingFee, - ]; - } - - /** - * - * @param {DataContract} dataContract - * @param {string} documentType - * @param [query] - * @param [query.where] - * @param [query.limit] - * @param [query.startAt] - * @param [query.startAfter] - * @param [query.orderBy] - * @param {boolean} [useTransaction=false] - * - * @returns {Promise<[Document[], number]>} - */ - async proveDocumentsQuery(dataContract, documentType, query = {}, useTransaction = false) { - const encodedQuery = await cbor.encodeAsync(query); - - // eslint-disable-next-line no-return-await - return await driveProveDocumentsQueryAsync.call( - this.drive, - encodedQuery, - dataContract.getId().toBuffer(), - documentType, - useTransaction, - ); - } - - /** - * @param {Identity} identity - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async insertIdentity(identity, blockInfo, useTransaction = false, dryRun = false) { - return driveInsertIdentityAsync.call( - this.drive, - identity.toBuffer(), - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Buffer|Identifier} id - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async fetchIdentity(id, useTransaction = false) { - return driveFetchIdentityAsync.call( - this.drive, - Buffer.from(id), - useTransaction, - ).then((encodedIdentity) => { - if (encodedIdentity === null) { - return null; - } - - const [protocolVersion, rawIdentity] = decodeProtocolEntity( - encodedIdentity, - ); - - rawIdentity.protocolVersion = protocolVersion; - - return new Identity(rawIdentity); - }); - } - - /** - * @param {Buffer|Identifier} id - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async fetchIdentityBalance(id, useTransaction = false) { - return driveFetchIdentityBalanceAsync.call( - this.drive, - Buffer.from(id), - useTransaction, - ); - } - - /** - * @param {Buffer|Identifier} id - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise<[number, FeeResult]>} - */ - async fetchIdentityBalanceWithCosts(id, blockInfo, useTransaction = false, dryRun = false) { - return driveFetchIdentityBalanceWithCostsAsync.call( - this.drive, - Buffer.from(id), - blockInfo, - !dryRun, - useTransaction, - ).then(([balance, innerFeeResult]) => [balance, new FeeResult(innerFeeResult)]); - } - - /** - * @param {Buffer|Identifier} id - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise<[number|null, FeeResult]>} - */ - async fetchIdentityBalanceIncludeDebtWithCosts( - id, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveFetchIdentityBalanceIncludeDebtWithCostsAsync.call( - this.drive, - Buffer.from(id), - blockInfo, - !dryRun, - useTransaction, - ).then(([balance, innerFeeResult]) => [balance, new FeeResult(innerFeeResult)]); - } - - /** - * @param {Identifier} id - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async proveIdentity(id, useTransaction = false) { - return driveFetchProvedIdentityAsync.call( - this.drive, - Buffer.from(id), - useTransaction, - ); - } - - /** - * @param {Identifier[]} ids - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async proveManyIdentities(ids, useTransaction = false) { - return driveFetchManyProvedIdentitiesAsync.call( - this.drive, - ids.map((id) => Buffer.from(id)), - useTransaction, - ); - } - - /** - * @param {Buffer|Identifier} id - * @param {number} epochIndex - * @param {boolean} [useTransaction=false] - * - * @returns {Promise<[Identity|null, FeeResult]>} - */ - async fetchIdentityWithCosts(id, epochIndex, useTransaction = false) { - return driveFetchIdentityWithCostsAsync.call( - this.drive, - Buffer.from(id), - epochIndex, - useTransaction, - ).then(([encodedIdentity, innerFeeResult]) => { - let identity = encodedIdentity; - - if (encodedIdentity !== null) { - const [protocolVersion, rawIdentity] = decodeProtocolEntity( - encodedIdentity, - ); - - rawIdentity.protocolVersion = protocolVersion; - - identity = new Identity(rawIdentity); - } - - return [identity, new FeeResult(innerFeeResult)]; - }); - } - - /** - * @param {Identifier} identityId - * @param {number} amount - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async addToIdentityBalance( - identityId, - amount, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveAddToIdentityBalanceAsync.call( - this.drive, - identityId.toBuffer(), - amount, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Identifier} identityId - * @param {number} amount - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async removeFromIdentityBalance( - identityId, - amount, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveRemoveFromIdentityBalanceAsync.call( - this.drive, - identityId.toBuffer(), - amount, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Identifier} identityId - * @param {FeeResult} fees - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async applyFeesToIdentityBalance( - identityId, - fees, - useTransaction = false, - ) { - return driveApplyFeesToIdentityBalanceAsync.call( - this.drive, - identityId.toBuffer(), - fees.inner, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {number} amount - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async addToSystemCredits( - amount, - useTransaction = false, - ) { - return driveAddToSystemCreditsAsync.call( - this.drive, - amount, - useTransaction, - ); - } - - /** - * @param {Buffer[]} hashes - * @param {boolean} [useTransaction=false] - * - * @returns {Promise>} - */ - async fetchIdentitiesByPublicKeyHashes(hashes, useTransaction = false) { - return driveFetchIdentitiesByPublicKeyHashesAsync.call( - this.drive, - hashes.map((h) => Buffer.from(h)), - useTransaction, - ).then((encodedIdentities) => ( - encodedIdentities.map((encodedIdentity) => { - const [protocolVersion, rawIdentity] = decodeProtocolEntity( - encodedIdentity, - ); - - rawIdentity.protocolVersion = protocolVersion; - - return new Identity(rawIdentity); - }) - )); - } - - /** - * @param {Buffer[]} hashes - * @param {boolean} [useTransaction=false] - * - * @returns {Promise>} - */ - async proveIdentitiesByPublicKeyHashes(hashes, useTransaction = false) { - return driveProveIdentitiesByPublicKeyHashesAsync.call( - this.drive, - hashes.map((h) => Buffer.from(h)), - useTransaction, - ); - } - - /** - * @param {Identifier} identityId - * @param {IdentityPublicKey[]} keys - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async addKeysToIdentity( - identityId, - keys, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveAddKeysToIdentityAsync.call( - this.drive, - identityId.toBuffer(), - keys, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Identifier} identityId - * @param {number[]} keyIds - * @param {number} disableAt - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async disableIdentityKeys( - identityId, - keyIds, - disableAt, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveDisableIdentityKeysAsync.call( - this.drive, - identityId.toBuffer(), - keyIds, - disableAt, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * @param {Identifier} identityId - * @param {number} revision - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async updateIdentityRevision( - identityId, - revision, - blockInfo, - useTransaction = false, - dryRun = false, - ) { - return driveUpdateIdentityRevisionAsync.call( - this.drive, - identityId.toBuffer(), - revision, - blockInfo, - !dryRun, - useTransaction, - ).then((innerFeeResult) => new FeeResult(innerFeeResult)); - } - - /** - * Fetch the latest index of the withdrawal transaction in a queue - * - * @param {RawBlockInfo} blockInfo - * @param {boolean} [useTransaction=false] - * @param {boolean} [dryRun=false] - * - * @returns {Promise} - */ - async fetchLatestWithdrawalTransactionIndex(blockInfo, useTransaction = false, dryRun = false) { - return driveFetchLatestWithdrawalTransactionIndexAsync.call( - this.drive, - blockInfo, - !dryRun, - useTransaction, - ); - } - - /** - * Get the ABCI interface - * @returns {RSAbci} - */ - getAbci() { - const { drive } = this; - - /** - * @typedef RSAbci - */ - return { - /** - * ABCI init chain - * - * @param {InitChainRequest} request - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async initChain(request, useTransaction = false) { - const requestBytes = cbor.encode(request); - - const responseBytes = await abciInitChainAsync.call( - drive, - requestBytes, - useTransaction, - ); - - return cbor.decode(responseBytes); - }, - - /** - * ABCI block begin - * - * @param {BlockBeginRequest} request - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async blockBegin(request, useTransaction = false) { - const requestBytes = cbor.encode({ - ...request, - // cborium doesn't eat Buffers - proposerProTxHash: Array.from(request.proposerProTxHash), - validatorSetQuorumHash: Array.from(request.validatorSetQuorumHash), - }); - - const responseBytes = await abciBlockBeginAsync.call( - drive, - requestBytes, - useTransaction, - ); - - return cbor.decode(responseBytes); - }, - - /** - * ABCI block end - * - * @param {BlockEndRequest} request - * @param {boolean} [useTransaction=false] - * - * @returns {Promise} - */ - async blockEnd(request, useTransaction = false) { - const responseBytes = await abciBlockEndAsync.call( - drive, - request, - useTransaction, - ); - - return cbor.decode(responseBytes); - }, - - /** - * ABCI after finalize block - * - * @param {AfterFinalizeBlockRequest} request - * - * @returns {Promise} - */ - async afterFinalizeBlock(request) { - const requestBytes = cbor.encode({ - ...request, - // cborium doesn't eat Buffers - updatedDataContractIds: request.updatedDataContractIds - .map((identifier) => Array.from(identifier)), - }); - - const responseBytes = await abciAfterFinalizeBlockAsync.call( - drive, - requestBytes, - ); - - return cbor.decode(responseBytes); - }, - }; - } -} - -// eslint-disable-next-line max-len -Drive.calculateStorageFeeDistributionAmountAndLeftovers = calculateStorageFeeDistributionAmountAndLeftoversWithStack; -Drive.FeeResult = FeeResult; - -/** - * @typedef RawBlockInfo - * @property {number} height - * @property {number} epoch - * @property {number} timeMs - */ - -/** - * @typedef InitChainRequest - * @property {number} genesisTimeMs - * @property {SystemIdentityPublicKeys} systemIdentityPublicKeys - */ - -/** - * @typedef SystemIdentityPublicKeys - * @property {RequiredIdentityPublicKeysSet} masternodeRewardSharesContractOwner - * @property {RequiredIdentityPublicKeysSet} featureFlagsContractOwner - * @property {RequiredIdentityPublicKeysSet} dpnsContractOwner - * @property {RequiredIdentityPublicKeysSet} withdrawalsContractOwner - * @property {RequiredIdentityPublicKeysSet} dashpayContractOwner - */ - -/** - * @typedef RequiredIdentityPublicKeysSet - * @property {Buffer} master - * @property {Buffer} high - */ - -/** - * @typedef InitChainResponse - */ - -/** - * @typedef BlockBeginRequest - * @property {number} blockHeight - * @property {number} blockTimeMs - timestamp in milliseconds - * @property {number} [previousBlockTimeMs] - timestamp in milliseconds - * @property {Buffer} proposerProTxHash - * @property {Buffer} validatorSetQuorumHash - * @property {number} lastSyncedCoreHeight - * @property {number} coreChainLockedHeight, - * @property {number} proposedAppVersion - * @property {number} totalHpmns - */ - -/** - * @typedef BlockBeginResponse - * @property {Buffer[]} unsignedWithdrawalTransactions - * @property {EpochInfo} epochInfo - */ - -/** - * @typedef EpochInfo - * @property {number} currentEpochIndex - * @property {boolean} isEpochChange - * @property {number} [previousEpochIndex] - Available only on epoch change - */ - -/** - * @typedef BlockEndRequest - * @property {BlockFees} fees - */ - -/** - * @typedef BlockFees - * @property {number} storageFee - * @property {number} processingFee - * @property {Object} refundsPerEpoch - */ - -/** - * @typedef BlockEndResponse - * @property {number} [proposersPaidCount] - * @property {number} [paidEpochIndex] - * @property {number} [refundedEpochsCount] - */ - -/** - * @typedef AfterFinalizeBlockRequest - * @property {Identifier[]|Buffer[]} updatedDataContractIds - */ - -/** - * @typedef AfterFinalizeBlockResponse - */ - -module.exports = Drive; diff --git a/packages/rs-drive-nodejs/FeeResult.js b/packages/rs-drive-nodejs/FeeResult.js deleted file mode 100644 index 50a7b120e10..00000000000 --- a/packages/rs-drive-nodejs/FeeResult.js +++ /dev/null @@ -1,95 +0,0 @@ -// This file is crated when run `npm run build`. The actual source file that -// exports those functions is ./src/lib.rs -const { - feeResultAdd, - feeResultGetStorageFee, - feeResultGetProcessingFee, - feeResultAddFees, - feeResultCreate, - feeResultGetRefunds, - feeResultSumRefundsPerEpoch, -} = require('neon-load-or-build')({ - dir: __dirname, -}); - -const { appendStack } = require('./appendStack'); - -const feeResultAddWithStack = appendStack(feeResultAdd); -const feeResultAddFeesWithStack = appendStack(feeResultAddFees); -const feeResultGetStorageFeeWithStack = appendStack(feeResultGetStorageFee); -const feeResultGetProcessingFeeWithStack = appendStack(feeResultGetProcessingFee); -const feeResultCreateWithStack = appendStack(feeResultCreate); -const feeResultGetRefundsWithStack = appendStack(feeResultGetRefunds); -const feeResultSumRefundsPerEpochWithStack = appendStack(feeResultSumRefundsPerEpoch); - -class FeeResult { - constructor(inner) { - this.inner = inner; - } - - /** - * Processing fees - * - * @returns {number} - */ - get processingFee() { - return feeResultGetProcessingFeeWithStack.call(this.inner); - } - - /** - * Storage fees - * - * @returns {number} - */ - get storageFee() { - return feeResultGetStorageFeeWithStack.call(this.inner); - } - - /** - * Credit refunds - * - * @return {{identifier: Buffer, creditsPerEpoch: Object}[]} - */ - get feeRefunds() { - return feeResultGetRefundsWithStack.call(this.inner); - } - - /** - * Sum credit refunds per epoch - * - * @returns {Object}[]} - */ - sumFeeRefundsPerEpoch() { - return feeResultSumRefundsPerEpochWithStack.call(this.inner); - } - - /** - * Adds and self assigns result between two Fee Results - * - * @param {FeeResult} feeResult - */ - add(feeResult) { - this.inner = feeResultAddWithStack.call(this.inner, feeResult.inner); - } - - /** - * @param {number} storageFee - * @param {number} processingFee - */ - addFees(storageFee, processingFee) { - feeResultAddFeesWithStack.call(this.inner, storageFee, processingFee); - } - - /** - * Create new fee result - * - * @returns {FeeResult} - */ - static create(storageFee, processingFee, feeRefunds) { - const inner = feeResultCreateWithStack(storageFee, processingFee, feeRefunds); - - return new FeeResult(inner); - } -} - -module.exports = FeeResult; diff --git a/packages/rs-drive-nodejs/GroveDB.js b/packages/rs-drive-nodejs/GroveDB.js deleted file mode 100644 index b020affb1f4..00000000000 --- a/packages/rs-drive-nodejs/GroveDB.js +++ /dev/null @@ -1,342 +0,0 @@ -const { promisify } = require('util'); - -// This file is crated when run `npm run build`. The actual source file that -// exports those functions is ./src/lib.rs -const { - groveDbInsert, - groveDbGet, - groveDbFlush, - groveDbStartTransaction, - groveDbCommitTransaction, - groveDbRollbackTransaction, - groveDbAbortTransaction, - groveDbIsTransactionStarted, - groveDbDelete, - groveDbInsertIfNotExists, - groveDbPutAux, - groveDbDeleteAux, - groveDbGetAux, - groveDbQuery, - groveDbProveQuery, - groveDbRootHash, - groveDbProveQueryMany, -} = require('neon-load-or-build')({ - dir: __dirname, -}); - -const { appendStackAsync } = require('./appendStack'); - -const groveDbGetAsync = appendStackAsync(promisify(groveDbGet)); -const groveDbInsertAsync = appendStackAsync(promisify(groveDbInsert)); -const groveDbInsertIfNotExistsAsync = appendStackAsync(promisify(groveDbInsertIfNotExists)); -const groveDbDeleteAsync = appendStackAsync(promisify(groveDbDelete)); -const groveDbFlushAsync = appendStackAsync(promisify(groveDbFlush)); -const groveDbStartTransactionAsync = appendStackAsync(promisify(groveDbStartTransaction)); -const groveDbCommitTransactionAsync = appendStackAsync(promisify(groveDbCommitTransaction)); -const groveDbRollbackTransactionAsync = appendStackAsync(promisify(groveDbRollbackTransaction)); -const groveDbIsTransactionStartedAsync = appendStackAsync(promisify(groveDbIsTransactionStarted)); -const groveDbAbortTransactionAsync = appendStackAsync(promisify(groveDbAbortTransaction)); -const groveDbPutAuxAsync = appendStackAsync(promisify(groveDbPutAux)); -const groveDbDeleteAuxAsync = appendStackAsync(promisify(groveDbDeleteAux)); -const groveDbGetAuxAsync = appendStackAsync(promisify(groveDbGetAux)); -const groveDbQueryAsync = appendStackAsync(promisify(groveDbQuery)); -const groveDbProveQueryAsync = appendStackAsync(promisify(groveDbProveQuery)); -const groveDbProveQueryManyAsync = appendStackAsync(promisify(groveDbProveQueryMany)); -const groveDbRootHashAsync = appendStackAsync(promisify(groveDbRootHash)); - -// Wrapper class for the boxed `GroveDB` for idiomatic JavaScript usage -class GroveDB { - /** - * @param drive - */ - constructor(drive) { - this.db = drive; - } - - /** - * @param {Buffer[]} path - * @param {Buffer} key - * @param {boolean} [useTransaction=false] - * @returns {Promise} - */ - async get(path, key, useTransaction = false) { - return groveDbGetAsync.call(this.db, path, key, useTransaction); - } - - /** - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Element} value - * @param {boolean} [useTransaction=false] - * @returns {Promise<*>} - */ - async insert(path, key, value, useTransaction = false) { - return groveDbInsertAsync.call(this.db, path, key, value, useTransaction); - } - - /** - * @param {Buffer[]} path - * @param {Buffer} key - * @param {Element} value - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async insertIfNotExists(path, key, value, useTransaction = false) { - return groveDbInsertIfNotExistsAsync.call(this.db, path, key, value, useTransaction); - } - - /** - * - * @param {Buffer[]} path - * @param {Buffer} key - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async delete(path, key, useTransaction = false) { - return groveDbDeleteAsync.call(this.db, path, key, useTransaction); - } - - /** - * Flush data on the disk - * - * @returns {Promise} - */ - async flush() { - return groveDbFlushAsync.call(this.db); - } - - /** - * Start a transaction with isolated scope - * - * Write operations will be allowed only for the transaction - * until it's committed - * - * @return {Promise} - */ - async startTransaction() { - return groveDbStartTransactionAsync.call(this.db); - } - - /** - * Commit transaction - * - * Transaction should be started before - * - * @return {Promise} - */ - async commitTransaction() { - return groveDbCommitTransactionAsync.call(this.db); - } - - /** - * Rollback transaction to this initial state when it was created - * - * @returns {Promise} - */ - async rollbackTransaction() { - return groveDbRollbackTransactionAsync.call(this.db); - } - - /** - * Returns true if transaction started - * - * @returns {Promise} - */ - async isTransactionStarted() { - return groveDbIsTransactionStartedAsync.call(this.db); - } - - /** - * Aborts transaction - * - * @returns {Promise} - */ - async abortTransaction() { - return groveDbAbortTransactionAsync.call(this.db); - } - - /** - * Put auxiliary data - * - * @param {Buffer} key - * @param {Buffer} value - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async putAux(key, value, useTransaction = false) { - return groveDbPutAuxAsync.call(this.db, key, value, useTransaction); - } - - /** - * Delete auxiliary data - * - * @param {Buffer} key - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async deleteAux(key, useTransaction = false) { - return groveDbDeleteAuxAsync.call(this.db, key, useTransaction); - } - - /** - * Get auxiliary data - * - * @param {Buffer} key - * @param {boolean} [useTransaction=false] - * @return {Promise} - */ - async getAux(key, useTransaction = false) { - return groveDbGetAuxAsync.call(this.db, key, useTransaction); - } - - /** - * Get data using query. - * - * @param {PathQuery} query - * @param {boolean} [skipCache=false] - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async query(query, skipCache = false, useTransaction = false) { - return groveDbQueryAsync.call(this.db, query, skipCache, useTransaction); - } - - /** - * Get proof using query. - * - * @param {PathQuery} query - * @param {boolean} [verbose=false] - * @param {boolean} [useTransaction=false] - * @return {Promise<*>} - */ - async proveQuery(query, verbose = false, useTransaction = false) { - return groveDbProveQueryAsync.call(this.db, query, verbose, useTransaction); - } - - /** - * Get proof using query. - * - * @param {PathQuery[]} queries - * @param {boolean} [useTransaction=false] - * @return {Promise} - */ - async proveQueryMany(queries, useTransaction = false) { - return groveDbProveQueryManyAsync.call(this.db, queries, useTransaction); - } - - /** - * Get root hash - * - * @param {boolean} [useTransaction=false] - * @returns {Promise} - */ - async getRootHash(useTransaction = false) { - return groveDbRootHashAsync.call(this.db, useTransaction); - } -} - -/** - * @typedef Element - * @property {"item"|"reference"|"tree"} type - element type. Can be "item", "reference" or "tree" - * @property {number} [epoch] - epoch storage flag - * @property {Buffer} [ownerId] - ownerId storage flag - * @property {Buffer|Buffer[]|Object} [value] - element value - */ - -/** - * @typedef PathQuery - * @property {Buffer[]} path - * @property {SizedQuery} query - */ - -/** - * @typedef SizedQuery - * @property {Query} query - * @property {number} [limit] - * @property {number} [offset] - */ - -/** - * @typedef Query - * @property {Array< - * QueryItemKey| - * QueryItemKey| - * QueryItemRange| - * QueryItemRangeInclusive| - * QueryItemRangeFull| - * QueryItemRangeFrom| - * QueryItemRangeTo| - * QueryItemRangeToInclusive| - * QueryItemRangeAfter| - * QueryItemRangeAfterTo| - * QueryItemRangeAfterToInclusive - * >} [items] - * @property {Buffer} [subqueryPath] - * @property {Query} [subquery] - * @property {boolean} [leftToRight] - */ - -/** - * @typedef QueryItemKey - * @property {"key"} type - * @property {Buffer} key - */ - -/** - * @typedef QueryItemRange - * @property {"range"} type - * @property {Buffer} from - * @property {Buffer} to - */ - -/** - * @typedef QueryItemRangeInclusive - * @property {"rangeInclusive"} type - * @property {Buffer} from - * @property {Buffer} to - */ - -/** - * @typedef QueryItemRangeFull - * @property {"rangeFull"} type - */ - -/** - * @typedef QueryItemRangeFrom - * @property {"rangeFrom"} type - * @property {Buffer} from - */ - -/** - * @typedef QueryItemRangeTo - * @property {"rangeTo"} type - * @property {Buffer} to - */ - -/** - * @typedef QueryItemRangeToInclusive - * @property {"rangeToInclusive"} type - * @property {Buffer} to - */ - -/** - * @typedef QueryItemRangeAfter - * @property {"rangeAfter"} type - * @property {Buffer} after - */ - -/** - * @typedef QueryItemRangeAfterTo - * @property {"rangeAfterTo"} type - * @property {Buffer} after - * @property {Buffer} to - */ - -/** - * @typedef QueryItemRangeAfterToInclusive - * @property {"rangeAfterToInclusive"} type - * @property {Buffer} after - * @property {Buffer} to - */ - -module.exports = GroveDB; diff --git a/packages/rs-drive-nodejs/appendStack.js b/packages/rs-drive-nodejs/appendStack.js deleted file mode 100644 index 6e8489361cc..00000000000 --- a/packages/rs-drive-nodejs/appendStack.js +++ /dev/null @@ -1,36 +0,0 @@ -/** - * @param {Function} fn - * @returns {(function(...[*]): Promise<*>)} - */ -function appendStackAsync(fn) { - return async function appendStackWrapper(...args) { - try { - return await fn.call(this, ...args); - } catch (e) { - e.stack = (new Error(e.message)).stack; - - throw e; - } - }; -} - -/** - * @param {Function} fn - * @returns {(function(...[*]): *)} - */ -function appendStack(fn) { - return function appendStackWrapper(...args) { - try { - return fn.call(this, ...args); - } catch (e) { - e.stack = (new Error(e.message)).stack; - - throw e; - } - }; -} - -module.exports = { - appendStack, - appendStackAsync, -}; diff --git a/packages/rs-drive-nodejs/docker/build.sh b/packages/rs-drive-nodejs/docker/build.sh deleted file mode 100755 index 5a69bcd6e32..00000000000 --- a/packages/rs-drive-nodejs/docker/build.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env bash - -## Setup arguments -while getopts t:a:l: flag -do - case "${flag}" in - t) target=${OPTARG};; - a) arch=${OPTARG};; - l) libc=${OPTARG};; - *) echo "invalid arguments" && exit 1;; - esac -done - -## Install multilib -apt update -apt install -y gcc-multilib -if [[ $target = "aarch64-unknown-linux-gnu" ]] -then - apt install -y gcc-aarch64-linux-gnu libstdc++-11-dev-arm64-cross -fi - -## Update toolchain -rustup update stable - -## Install build target -rustup target install $target - -chmod 777 -R /root/.cargo -mkdir -p /github/workspace/target -chmod 777 -R /github/workspace/target - -## Install Node.JS -curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash - -apt install -y nodejs - -corepack enable - -yarn install - -CARGO_BUILD_TARGET=$target \ -CARGO_BUILD_PROFILE=release \ -ARCH=$arch \ -LIBC=$libc \ -yarn workspace @dashevo/rs-drive run build diff --git a/packages/rs-drive-nodejs/package.json b/packages/rs-drive-nodejs/package.json deleted file mode 100644 index eb665132ece..00000000000 --- a/packages/rs-drive-nodejs/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@dashevo/rs-drive", - "version": "0.24.0-dev.16", - "description": "Node.JS binding for Rust Drive", - "main": "Drive.js", - "scripts": { - "build": "yarn exec scripts/build.sh", - "test": "NODE_ENV=test ultra --build && mocha test", - "lint": "eslint ." - }, - "files": [ - "prebuilds", - "Drive.js", - "GroveDB.js", - "appendStack.js", - "src" - ], - "license": "MIT", - "devDependencies": { - "@dashevo/dashcore-lib": "~0.20.0", - "@dashevo/withdrawals-contract": "workspace:*", - "chai": "^4.3.4", - "dirty-chai": "^2.0.1", - "eslint": "^7.32.0", - "eslint-config-airbnb-base": "^14.2.1", - "eslint-plugin-import": "^2.24.2", - "mocha": "^9.1.2", - "neon-cli": "^0.10.1", - "ultra-runner": "^3.10.5" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/dashevo/rs-drive.git" - }, - "keywords": [ - "Dash Platform", - "Drive" - ], - "bugs": { - "url": "https://github.com/dashevo/rs-drive/issues" - }, - "homepage": "https://github.com/dashevo/rs-drive#readme", - "dependencies": { - "@dashevo/dpp": "workspace:*", - "cargo-cp-artifact": "^0.1.6", - "cbor": "^8.0.0", - "neon-load-or-build": "^2.2.2", - "neon-tag-prebuild": "github:shumkov/neon-tag-prebuild#patch-1" - } -} diff --git a/packages/rs-drive-nodejs/scripts/build.sh b/packages/rs-drive-nodejs/scripts/build.sh deleted file mode 100755 index 6e169fdf681..00000000000 --- a/packages/rs-drive-nodejs/scripts/build.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -PROFILE_ARG="" -FEATURE_FLAG="" - -if [ -n "$CARGO_BUILD_PROFILE" ]; then - if [ "$CARGO_BUILD_PROFILE" == "release" ]; then - PROFILE_ARG="--release" - elif [ "$CARGO_BUILD_PROFILE" != "debug" ]; then - PROFILE_ARG="--profile $CARGO_BUILD_PROFILE" - fi -fi - -if [ -n "$NODE_ENV" ]; then - if [ "$NODE_ENV" == "test" ]; then - FEATURE_FLAG="--features enable-mocking" - fi -fi - -cargo-cp-artifact -ac drive-nodejs native/index.node -- \ - cargo build --message-format=json-render-diagnostics $PROFILE_ARG $FEATURE_FLAG \ - && neon-tag-prebuild \ - && rm -rf native diff --git a/packages/rs-drive-nodejs/src/converter.rs b/packages/rs-drive-nodejs/src/converter.rs deleted file mode 100644 index 13d49f334c4..00000000000 --- a/packages/rs-drive-nodejs/src/converter.rs +++ /dev/null @@ -1,534 +0,0 @@ -use drive::dpp::block::block_info::BlockInfo; -use drive::dpp::block::epoch::Epoch; -use drive::dpp::identity::{IdentityPublicKey, KeyID, KeyType, Purpose, SecurityLevel}; -use drive::dpp::platform_value::BinaryData; -use drive::drive::flags::StorageFlags; -use drive::fee::credits::Credits; -use drive::fee::epoch::CreditsPerEpoch; -use drive::grovedb::reference_path::ReferencePathType; -use drive::grovedb::{Element, PathQuery, Query, SizedQuery}; -use neon::prelude::*; -use neon::types::buffer::TypedArray; -use num::FromPrimitive; -use std::borrow::Borrow; -use std::num::ParseIntError; - -fn element_to_string(element: &Element) -> &'static str { - match element { - Element::Item(..) => "item", - Element::SumItem(..) => "sumItem", - Element::Reference(..) => "reference", - Element::Tree(..) => "tree", - Element::SumTree(..) => "sumTree", - } -} - -pub fn js_object_to_element<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let js_element_type: Handle = js_object.get(cx, "type")?; - - let element_type: String = js_element_type.value(cx); - - let js_element_epoch: Option> = js_object.get_opt(cx, "epoch")?; - - let element_flags = if let Some(js_epoch) = js_element_epoch { - let epoch = u16::try_from(js_epoch.value(cx) as i64) - .or_else(|_| cx.throw_range_error("`epochs` must fit in u16"))?; - - let js_maybe_owner_id: Option> = js_object.get_opt(cx, "ownerId")?; - - let maybe_owner_id = js_maybe_owner_id - .map(|js_buffer| js_buffer_to_identifier(cx, js_buffer)) - .transpose()?; - - let storage_flags = StorageFlags::new_single_epoch(epoch, maybe_owner_id); - - storage_flags.to_some_element_flags() - } else { - None - }; - - match element_type.as_str() { - "item" => { - let js_buffer: Handle = js_object.get(cx, "value")?; - let item = js_buffer_to_vec_u8(cx, js_buffer); - - Ok(Element::new_item_with_flags(item, element_flags)) - } - "reference" => { - let js_object: Handle = js_object.get(cx, "value")?; - let reference = js_object_to_reference(cx, js_object)?; - - Ok(Element::new_reference_with_flags(reference, element_flags)) - } - "tree" => Ok(Element::empty_tree_with_flags(element_flags)), - _ => cx.throw_error(format!("Unexpected element type {}", element_type)), - } -} - -fn js_object_to_reference<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let js_reference_type: Handle = js_object.get(cx, "type")?; - let reference_type: String = js_reference_type.value(cx); - - match reference_type.as_str() { - "absolutePathReference" => { - let js_path: Handle = js_object.get(cx, "path")?; - let path = js_array_of_buffers_to_vec(cx, js_path)?; - - Ok(ReferencePathType::AbsolutePathReference(path)) - } - "upstreamRootHeightReference" => { - let js_path: Handle = js_object.get(cx, "path")?; - let path = js_array_of_buffers_to_vec(cx, js_path)?; - - let js_relativity_index: Handle = js_object.get(cx, "relativityIndex")?; - let relativity_index_f64: f64 = js_relativity_index.value(cx); - let relativity_index_option: Option = FromPrimitive::from_f64(relativity_index_f64); - let relativity_index: u8 = relativity_index_option - .ok_or(()) - .or_else(|_| cx.throw_error("cannot convert relativity_index from f64 to u8"))?; - - Ok(ReferencePathType::UpstreamRootHeightReference( - relativity_index, - path, - )) - } - "upstreamFromElementHeightReference" => { - let js_path: Handle = js_object.get(cx, "path")?; - let path = js_array_of_buffers_to_vec(cx, js_path)?; - - let js_relativity_index: Handle = js_object.get(cx, "relativityIndex")?; - let relativity_index_f64: f64 = js_relativity_index.value(cx); - let relativity_index_option: Option = FromPrimitive::from_f64(relativity_index_f64); - let relativity_index: u8 = relativity_index_option - .ok_or(()) - .or_else(|_| cx.throw_error("cannot convert relativity_index from f64 to u8"))?; - - Ok(ReferencePathType::UpstreamFromElementHeightReference( - relativity_index, - path, - )) - } - "cousinReference" => { - let js_key: Handle = js_object.get(cx, "key")?; - let key = js_buffer_to_vec_u8(cx, js_key); - - Ok(ReferencePathType::CousinReference(key)) - } - "siblingReference" => { - let js_key: Handle = js_object.get(cx, "key")?; - let key = js_buffer_to_vec_u8(cx, js_key); - - Ok(ReferencePathType::SiblingReference(key)) - } - _ => cx.throw_error(format!("Unexpected reference type {}", reference_type)), - } -} - -pub fn element_to_js_object<'a, C: Context<'a>>( - cx: &mut C, - element: Element, -) -> NeonResult> { - let js_object = cx.empty_object(); - let js_type_string = cx.string(element_to_string(&element)); - js_object.set(cx, "type", js_type_string)?; - - let maybe_js_value: Option> = match element { - Element::Item(item, _) => { - let js_buffer = JsBuffer::external(cx, item); - Some(js_buffer.upcast()) - } - Element::SumItem(number, _) => { - let js_number = cx.number(number as f64).upcast(); - Some(js_number) - } - Element::Reference(reference, _, _) => { - let reference = reference_to_dictionary(cx, reference)?; - Some(reference) - } - Element::Tree(Some(tree), _) | Element::SumTree(Some(tree), ..) => { - let js_buffer = JsBuffer::external(cx, tree); - Some(js_buffer.upcast()) - } - Element::Tree(None, _) | Element::SumTree(None, ..) => None, - }; - - if let Some(js_value) = maybe_js_value { - js_object.set(cx, "value", js_value)?; - } - - Ok(js_object.upcast()) -} - -pub fn nested_vecs_to_js<'a, C: Context<'a>>( - cx: &mut C, - v: Vec>, -) -> NeonResult> { - let js_array: Handle = cx.empty_array(); - - for (index, bytes) in v.iter().enumerate() { - let js_buffer = JsBuffer::external(cx, bytes.clone()); - let js_value = js_buffer.as_value(cx); - js_array.set(cx, index as u32, js_value)?; - } - - Ok(js_array.upcast()) -} - -pub fn reference_to_dictionary<'a, C: Context<'a>>( - cx: &mut C, - reference: ReferencePathType, -) -> NeonResult> { - let js_object: Handle = cx.empty_object(); - - match reference { - ReferencePathType::AbsolutePathReference(path) => { - let js_type_name = cx.string("absolutePathReference"); - let js_path = nested_vecs_to_js(cx, path)?; - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "path", js_path)?; - } - ReferencePathType::UpstreamRootHeightReference(relativity_index, path) => { - let js_type_name = cx.string("upstreamRootHeightReference"); - let js_relativity_index = cx.number(relativity_index); - let js_path = nested_vecs_to_js(cx, path)?; - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "relativityIndex", js_relativity_index)?; - js_object.set(cx, "path", js_path)?; - } - ReferencePathType::UpstreamFromElementHeightReference(relativity_index, path) => { - let js_type_name = cx.string("upstreamFromElementHeightReference"); - let js_relativity_index = cx.number(relativity_index); - let js_path = nested_vecs_to_js(cx, path)?; - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "relativityIndex", js_relativity_index)?; - js_object.set(cx, "path", js_path)?; - } - ReferencePathType::CousinReference(key) => { - let js_type_name = cx.string("cousinReference"); - let js_key = JsBuffer::external(cx, key); - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "key", js_key)?; - } - ReferencePathType::SiblingReference(key) => { - let js_type_name = cx.string("siblingReference"); - let js_key = JsBuffer::external(cx, key); - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "key", js_key)?; - } - ReferencePathType::RemovedCousinReference(path) => { - let js_type_name = cx.string("removedCousinReference"); - let js_path = nested_vecs_to_js(cx, path)?; - - js_object.set(cx, "type", js_type_name)?; - js_object.set(cx, "path", js_path)?; - } - } - - Ok(js_object.upcast()) -} - -pub fn js_buffer_to_identifier<'a, C: Context<'a>>( - cx: &mut C, - js_buffer: Handle, -) -> NeonResult<[u8; 32]> { - // let guard = cx.lock(); - - let key_memory_view = js_buffer.borrow(); - - // let key_buffer = js_buffer.deref(); - // let key_memory_view = js_buffer.borrow(&guard); - let key_slice: &[u8] = key_memory_view.as_slice(cx); - <[u8; 32]>::try_from(key_slice).or_else(|_| cx.throw_type_error("hash must be 32 bytes long")) -} - -pub fn js_buffer_to_vec_u8<'a, C: Context<'a>>(cx: &mut C, js_buffer: Handle) -> Vec { - // let guard = cx.lock(); - - let key_memory_view = js_buffer.borrow(); - - // let key_buffer = js_buffer.deref(); - // let key_memory_view = js_buffer.borrow(&guard); - let key_slice: &[u8] = key_memory_view.as_slice(cx); - key_slice.to_vec() -} - -pub fn js_array_of_buffers_to_vec<'a, C: Context<'a>>( - cx: &mut C, - js_array: Handle, -) -> NeonResult>> { - let buf_vec = js_array.to_vec(cx)?; - let mut vec: Vec> = Vec::with_capacity(buf_vec.len()); - - for buf in buf_vec { - let js_buffer_handle = buf.downcast_or_throw::(cx)?; - vec.push(js_buffer_to_vec_u8(cx, js_buffer_handle)); - } - - Ok(vec) -} - -pub fn js_array_of_buffers_to_identifiers<'a, C: Context<'a>>( - cx: &mut C, - js_array: Handle, -) -> NeonResult> { - let buf_vec = js_array.to_vec(cx)?; - let mut vec: Vec<[u8; 32]> = Vec::with_capacity(buf_vec.len()); - - for buf in buf_vec { - let js_buffer_handle = buf.downcast_or_throw::(cx)?; - vec.push(js_buffer_to_identifier(cx, js_buffer_handle)?); - } - - Ok(vec) -} - -pub fn js_value_to_option<'a, T: Value, C: Context<'a>>( - cx: &mut C, - js_value: Handle<'a, JsValue>, -) -> NeonResult>> { - if js_value.is_a::(cx) || js_value.is_a::(cx) { - Ok(None) - } else { - Ok(Some(js_value.downcast_or_throw::(cx)?)) - } -} - -fn js_object_get_vec_u8<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, - field: &str, -) -> NeonResult> { - let buffer: Handle = js_object.get(cx, field)?; - - Ok(js_buffer_to_vec_u8(cx, buffer)) -} - -fn js_object_to_query<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let items: Handle = js_object.get(cx, "items")?; - let mut query = Query::new(); - for js_item in items.to_vec(cx)? { - let item = js_item.downcast_or_throw::(cx)?; - - let item_type: Handle = item.get(cx, "type")?; - let item_type = item_type.value(cx); - - match item_type.as_ref() { - "key" => { - query.insert_key(js_object_get_vec_u8(cx, item, "key")?); - } - "range" => { - let from = js_object_get_vec_u8(cx, item, "from")?; - let to = js_object_get_vec_u8(cx, item, "to")?; - query.insert_range(from..to); - } - "rangeInclusive" => { - let from = js_object_get_vec_u8(cx, item, "from")?; - let to = js_object_get_vec_u8(cx, item, "to")?; - query.insert_range_inclusive(from..=to); - } - "rangeFull" => { - query.insert_all(); - } - "rangeFrom" => { - query.insert_range_from(js_object_get_vec_u8(cx, item, "from")?..); - } - "rangeTo" => { - query.insert_range_to(..js_object_get_vec_u8(cx, item, "to")?); - } - "rangeToInclusive" => { - query.insert_range_to_inclusive(..=js_object_get_vec_u8(cx, item, "to")?); - } - "rangeAfter" => { - query.insert_range_after(js_object_get_vec_u8(cx, item, "after")?..); - } - "rangeAfterTo" => { - let after = js_object_get_vec_u8(cx, item, "after")?; - let to = js_object_get_vec_u8(cx, item, "to")?; - query.insert_range_after_to(after..to); - } - "rangeAfterToInclusive" => { - let after = js_object_get_vec_u8(cx, item, "after")?; - let to = js_object_get_vec_u8(cx, item, "to")?; - query.insert_range_after_to_inclusive(after..=to); - } - _ => { - cx.throw_range_error("query item type is not supported")?; - } - } - } - - let js_subquery_path = js_object.get(cx, "subqueryPath")?; - let subquery_path = js_value_to_option::(cx, js_subquery_path)? - .map(|x| js_array_of_buffers_to_vec(cx, x)) - .transpose()?; - let js_subquery = js_object.get(cx, "subquery")?; - let subquery = js_value_to_option::(cx, js_subquery)? - .map(|x| js_object_to_query(cx, x)) - .transpose()?; - let js_left_to_right = js_object.get(cx, "leftToRight")?; - let left_to_right = - js_value_to_option::(cx, js_left_to_right)?.map(|x| x.value(cx)); - - query.default_subquery_branch.subquery_path = subquery_path; - query.default_subquery_branch.subquery = subquery.map(Box::new); - query.left_to_right = left_to_right.unwrap_or(true); - - Ok(query) -} - -fn js_object_to_sized_query<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let query: Handle = js_object.get(cx, "query")?; - let query = js_object_to_query(cx, query)?; - - let js_limit = js_object.get(cx, "limit")?; - let limit: Option = js_value_to_option::(cx, js_limit)? - .map(|x| { - u16::try_from(x.value(cx) as i64) - .or_else(|_| cx.throw_range_error("`limit` must fit in u16")) - }) - .transpose()?; - let js_offset = js_object.get(cx, "offset")?; - let offset: Option = js_value_to_option::(cx, js_offset)? - .map(|x| { - u16::try_from(x.value(cx) as i64) - .or_else(|_| cx.throw_range_error("`offset` must fit in u16")) - }) - .transpose()?; - - Ok(SizedQuery::new(query, limit, offset)) -} - -pub fn js_path_query_to_path_query<'a, C: Context<'a>>( - cx: &mut C, - js_path_query: Handle, -) -> NeonResult { - let js_path = js_path_query.get(cx, "path")?; - let path = js_array_of_buffers_to_vec(cx, js_path)?; - let js_query = js_path_query.get(cx, "query")?; - let query = js_object_to_sized_query(cx, js_query)?; - - Ok(PathQuery::new(path, query)) -} - -pub fn js_object_to_block_info<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let js_height: Handle = js_object.get(cx, "height")?; - let js_epoch: Handle = js_object.get(cx, "epoch")?; - let js_time: Handle = js_object.get(cx, "timeMs")?; - - let epoch = Epoch::new(js_epoch.value(cx) as u16).unwrap(); - - let block_info = BlockInfo { - height: js_height.value(cx) as u64, - time_ms: js_time.value(cx) as u64, - epoch, - core_height: 1, - }; - - Ok(block_info) -} - -pub fn js_object_to_identity_public_key<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let js_id: Handle = js_object.get(cx, "id")?; - let js_purpose: Handle = js_object.get(cx, "purpose")?; - let js_security_level: Handle = js_object.get(cx, "securityLevel")?; - let js_key_type: Handle = js_object.get(cx, "type")?; - let js_read_only: Handle = js_object.get(cx, "readOnly")?; - let js_data: Handle = js_object.get(cx, "data")?; - let js_disabled_at: Handle = js_object.get(cx, "disabledAt")?; - - let id = js_id.value(cx) as KeyID; - - let purpose = Purpose::try_from(js_purpose.value(cx) as u8) - .or_else(|_| cx.throw_range_error("`purpose` value is incorrect"))?; - - let security_level = SecurityLevel::try_from(js_security_level.value(cx) as u8) - .or_else(|_| cx.throw_range_error("`securityLevel` value is incorrect"))?; - - let key_type = KeyType::try_from(js_key_type.value(cx) as u8) - .or_else(|_| cx.throw_range_error("`keyType` value is incorrect"))?; - - let read_only = js_read_only.value(cx); - - let data = js_buffer_to_vec_u8(cx, js_data); - - let disabled_at: Option = js_value_to_option::(cx, js_disabled_at)? - .map(|x| { - u64::try_from(x.value(cx) as i64) - .or_else(|_| cx.throw_range_error("`offset` must fit in u16")) - }) - .transpose()?; - - Ok(IdentityPublicKey { - id, - purpose, - security_level, - key_type, - read_only, - data: BinaryData::new(data), - disabled_at, - }) -} - -pub fn js_array_to_keys<'a, C: Context<'a>>( - cx: &mut C, - js_array: Handle, -) -> NeonResult> { - let keys = js_array - .to_vec(cx)? - .into_iter() - .map(|js_value| { - let js_key = js_value.downcast_or_throw::(cx)?; - let key = js_object_to_identity_public_key(cx, js_key)?; - - Ok(key) - }) - .collect::>()?; - - Ok(keys) -} - -pub fn js_object_to_fee_refunds<'a, C: Context<'a>>( - cx: &mut C, - js_object: Handle, -) -> NeonResult { - let mut fee_refunds: CreditsPerEpoch = Default::default(); - - for js_epoch_index_value in js_object.get_own_property_names(cx)?.to_vec(cx)? { - let js_epoch_index = js_epoch_index_value.downcast_or_throw::(cx)?; - - let epoch_index = js_epoch_index - .value(cx) - .parse() - .or_else(|e: ParseIntError| cx.throw_error(e.to_string()))?; - - let js_credits: Handle = js_object.get(cx, js_epoch_index)?; - let credits = js_credits.value(cx) as Credits; - - fee_refunds.insert(epoch_index, credits); - } - - Ok(fee_refunds) -} diff --git a/packages/rs-drive-nodejs/src/fee/mod.rs b/packages/rs-drive-nodejs/src/fee/mod.rs deleted file mode 100644 index 2b0f5c68e78..00000000000 --- a/packages/rs-drive-nodejs/src/fee/mod.rs +++ /dev/null @@ -1,39 +0,0 @@ -use drive::fee::credits::Credits; -use drive::fee::epoch::distribution::calculate_storage_fee_refund_amount_and_leftovers; -use drive::fee::epoch::EpochIndex; -use neon::prelude::*; - -pub mod result; - -pub fn js_calculate_storage_fee_distribution_amount_and_leftovers( - mut cx: FunctionContext, -) -> JsResult { - let js_storage_fees = cx.argument::(0)?; - let storage_fees = js_storage_fees.value(&mut cx) as Credits; - - let js_start_epoch_index = cx.argument::(1)?; - - let start_epoch_index = EpochIndex::try_from(js_start_epoch_index.value(&mut cx) as i64) - .or_else(|_| cx.throw_range_error("`startEpochIndex` must fit in u16"))?; - - let js_skip_up_to_epoch_index = cx.argument::(2)?; - let current_epoch_index = EpochIndex::try_from(js_skip_up_to_epoch_index.value(&mut cx) as i64) - .or_else(|_| cx.throw_range_error("`startEpochIndex` must fit in u16"))?; - - let (amount, leftovers) = calculate_storage_fee_refund_amount_and_leftovers( - storage_fees, - start_epoch_index, - current_epoch_index, - ) - .or_else(|e| cx.throw_error(e.to_string()))?; - - let js_array = cx.empty_array(); - - let js_amount = cx.number(amount as f64); - let js_leftovers = cx.number(leftovers as f64); - - js_array.set(&mut cx, 0, js_amount)?; - js_array.set(&mut cx, 1, js_leftovers)?; - - Ok(js_array) -} diff --git a/packages/rs-drive-nodejs/src/fee/result.rs b/packages/rs-drive-nodejs/src/fee/result.rs deleted file mode 100644 index 759c8fa9756..00000000000 --- a/packages/rs-drive-nodejs/src/fee/result.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::converter::{js_buffer_to_identifier, js_object_to_fee_refunds}; -use drive::fee::result::refunds::{CreditsPerEpochByIdentifier, FeeRefunds}; -use drive::fee::result::FeeResult; -use neon::prelude::*; -use std::ops::Deref; - -pub struct FeeResultWrapper(FeeResult); - -impl FeeResultWrapper { - pub fn new(fee_result: FeeResult) -> Self { - FeeResultWrapper(fee_result) - } - - pub fn create(mut cx: FunctionContext) -> JsResult> { - let storage_fee = cx.argument::(0)?.value(&mut cx) as u64; - let processing_fee = cx.argument::(1)?.value(&mut cx) as u64; - let js_fee_refunds = cx.argument::(2)?.to_vec(&mut cx)?; - - let mut credits_per_epoch_by_identifier = CreditsPerEpochByIdentifier::new(); - for item in js_fee_refunds { - let js_refunds = item.downcast_or_throw::(&mut cx)?; - - let js_identifier: Handle = js_refunds.get(&mut cx, "identifier")?; - let identifier = js_buffer_to_identifier(&mut cx, js_identifier)?; - - let js_credits_per_epoch: Handle = - js_refunds.get(&mut cx, "creditsPerEpoch")?; - - let credits_per_epoch = js_object_to_fee_refunds(&mut cx, js_credits_per_epoch)?; - - credits_per_epoch_by_identifier.insert(identifier, credits_per_epoch); - } - - let fee_result = FeeResult { - storage_fee, - processing_fee, - fee_refunds: FeeRefunds(credits_per_epoch_by_identifier), - ..Default::default() - }; - - Ok(cx.boxed(Self::new(fee_result))) - } - - pub fn get_storage_fee(mut cx: FunctionContext) -> JsResult { - let fee_result_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // TODO: We might lose with the conversion - Ok(cx.number(fee_result_self.0.storage_fee as f64)) - } - - pub fn get_processing_fee(mut cx: FunctionContext) -> JsResult { - let fee_result_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // TODO: We might lose with the conversion - Ok(cx.number(fee_result_self.0.processing_fee as f64)) - } - - pub fn add(mut cx: FunctionContext) -> JsResult> { - let fee_result_wrapper_to_add = cx.argument::>(0)?; - - let fee_result_wrapper_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // TODO: Figure out how to get mutable link from JsBox - let mut fee_result_sum = fee_result_wrapper_self.deref().deref().deref().clone(); - - // TODO: To avoid clone we need to be able to pass a reference to - // FeeResult#checked_add_assign - let fee_result_to_add = fee_result_wrapper_to_add.deref().deref().deref().clone(); - - fee_result_sum - .checked_add_assign(fee_result_to_add) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.boxed(Self::new(fee_result_sum))) - } - - pub fn add_fees(mut cx: FunctionContext) -> JsResult> { - let storage_fee = cx.argument::(0)?.value(&mut cx) as u64; - let processing_fee = cx.argument::(1)?.value(&mut cx) as u64; - - let fee_result_wrapper_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // TODO: Figure out how to get mutable link from JsBox - let mut fee_result_sum = fee_result_wrapper_self.deref().deref().deref().clone(); - - let fee_result_to_add = FeeResult::default_with_fees(storage_fee, processing_fee); - - fee_result_sum - .checked_add_assign(fee_result_to_add) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.boxed(Self::new(fee_result_sum))) - } - - pub fn get_refunds(mut cx: FunctionContext) -> JsResult { - let fee_result_wrapper_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // Clone fee result because IntMap doesn't implement iterator for reference - let fee_result = fee_result_wrapper_self.deref().deref().deref().clone(); - - let js_fee_refunds: Handle = cx.empty_array(); - - for (index, (identifier, credits_per_epoch)) in - fee_result.fee_refunds.into_iter().enumerate() - { - let js_epoch_index_map = cx.empty_object(); - - for (epoch, credits) in credits_per_epoch { - // TODO: We could miss fees here - let js_credits = cx.number(credits as f64); - - js_epoch_index_map.set(&mut cx, epoch.to_string().as_str(), js_credits)?; - } - - let js_identity_to_epochs = cx.empty_object(); - - let js_identifier = JsBuffer::external(&mut cx, identifier); - - js_identity_to_epochs.set(&mut cx, "identifier", js_identifier)?; - js_identity_to_epochs.set(&mut cx, "creditsPerEpoch", js_epoch_index_map)?; - - js_fee_refunds.set(&mut cx, index as u32, js_identity_to_epochs)?; - } - - Ok(js_fee_refunds) - } - - pub fn get_refunds_per_epoch(mut cx: FunctionContext) -> JsResult { - let fee_result_wrapper_self = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - // Clone fee result because IntMap doesn't implement iterator for reference - let fee_result = fee_result_wrapper_self.deref().deref().deref().clone(); - - let js_credits_per_epoch = cx.empty_object(); - - for (epoch_index, epoch_credits) in fee_result.fee_refunds.sum_per_epoch() { - // TODO: We could miss fees here - let js_credits = cx.number(epoch_credits as f64); - - js_credits_per_epoch.set(&mut cx, epoch_index.to_string().as_str(), js_credits)?; - } - - Ok(js_credits_per_epoch) - } -} - -impl Finalize for FeeResultWrapper {} - -impl Deref for FeeResultWrapper { - type Target = FeeResult; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/packages/rs-drive-nodejs/src/lib.rs b/packages/rs-drive-nodejs/src/lib.rs deleted file mode 100644 index eeb250c775e..00000000000 --- a/packages/rs-drive-nodejs/src/lib.rs +++ /dev/null @@ -1,3682 +0,0 @@ -mod converter; -mod fee; - -use drive::drive::config::DriveConfig; -use drive_abci::config::{CoreConfig, CoreRpcConfig, PlatformConfig}; - -use std::ops::Deref; -use std::{option::Option::None, path::Path, sync::mpsc, thread}; - -use crate::converter::js_object_to_fee_refunds; -use crate::fee::result::FeeResultWrapper; - -use drive::dpp::block::epoch::Epoch; -use drive::dpp::identity::{KeyID, TimestampMillis}; -use drive::dpp::prelude::Revision; -use drive::dpp::Convertible; -use drive::drive::flags::StorageFlags; -use drive::drive::query::QuerySerializedDocumentsOutcome; -use drive::error::Error; -use drive::fee::credits::Credits; -use drive::grovedb::{PathQuery, Transaction}; -use drive::query::TransactionArg; -use drive_abci::abci::messages::{ - AfterFinalizeBlockRequest, BlockBeginRequest, BlockEndRequest, BlockFees, InitChainRequest, - Serializable, -}; -use drive_abci::platform::Platform; -use drive_abci::rpc::core::DefaultCoreRPC; -use fee::js_calculate_storage_fee_distribution_amount_and_leftovers; -use neon::prelude::*; - -type PlatformCallback = - Box FnOnce(&'a Platform, TransactionArg, &Channel) + Send>; -type UnitCallback = Box; -type ErrorCallback = Box) + Send>; -type TransactionCallback = - Box, Result<(), String>, &Channel) + Send>; - -// Messages sent on the drive channel -enum PlatformWrapperMessage { - // Callback to be executed - Callback(PlatformCallback), - // Indicates that the thread should be stopped and connection closed - Close(UnitCallback), - StartTransaction(TransactionCallback), - CommitTransaction(ErrorCallback), - RollbackTransaction(ErrorCallback), - AbortTransaction(ErrorCallback), - Flush(UnitCallback), -} - -struct PlatformWrapper { - tx: mpsc::Sender, -} - -// Internal wrapper logic. Needed to avoid issues with passing threads to -// node.js. Avoiding thread conflicts by having a dedicated thread for the -// groveDB instance and uses events to communicate with it -impl PlatformWrapper { - // Creates a new instance of `DriveWrapper` - // - // 1. Creates a connection and a channel - // 2. Spawns a thread and moves the channel receiver and connection to it - // 3. On a separate thread, read closures off the channel and execute with - // access to the connection. - fn new(cx: &mut FunctionContext) -> NeonResult { - // Drive's configuration - let path_string = cx.argument::(0)?.value(cx); - let platform_config = cx.argument::(1)?; - - let drive_config: Handle = platform_config.get(cx, "drive")?; - let core_config: Handle = platform_config.get(cx, "core")?; - let core_rpc_config: Handle = core_config.get(cx, "rpc")?; - - let js_core_rpc_url: Handle = core_rpc_config.get(cx, "url")?; - let js_core_rpc_username: Handle = core_rpc_config.get(cx, "username")?; - let js_core_rpc_password: Handle = core_rpc_config.get(cx, "password")?; - - let core_rpc_url = js_core_rpc_url.value(cx); - let core_rpc_username = js_core_rpc_username.value(cx); - let core_rpc_password = js_core_rpc_password.value(cx); - - let js_data_contracts_cache_size: Handle = - drive_config.get(cx, "dataContractsGlobalCacheSize")?; - let data_contracts_global_cache_size = - u64::try_from(js_data_contracts_cache_size.value(cx) as i64).or_else(|_| { - cx.throw_range_error("`dataContractsGlobalCacheSize` must fit in u64") - })?; - - let js_data_contracts_transactional_cache_size: Handle = - drive_config.get(cx, "dataContractsBlockCacheSize")?; - let data_contracts_block_cache_size = u64::try_from( - js_data_contracts_transactional_cache_size.value(cx) as i64, - ) - .or_else(|_| cx.throw_range_error("`dataContractsBlockCacheSize` must fit in u64"))?; - - // Channel for sending callbacks to execute on the Drive connection thread - let (tx, rx) = mpsc::channel::(); - - // Create an `Channel` for calling back to JavaScript. It is more efficient - // to create a single channel and re-use it for all database callbacks. - // The JavaScript process will not exit as long as this channel has not been - // dropped. - let channel = cx.channel(); - - let sender = tx.clone(); - - // Spawn a thread for processing database queries - // This will not block the JavaScript main thread and will continue executing - // concurrently. - thread::spawn(move || { - let path = Path::new(&path_string); - // Open a connection to groveDb, this will be moved to a separate thread - - let drive_config = DriveConfig { - data_contracts_global_cache_size, - data_contracts_block_cache_size, - ..Default::default() - }; - //core_addr: Vec<&str> - let core_addr: Vec<&str> = core_rpc_url.split(':').collect(); - let core_host = core_addr.first().expect("missing core address"); - let core_port = core_addr - .get(1) - .expect("missing port number in core address"); - let core_config = CoreConfig { - rpc: CoreRpcConfig { - host: core_host.to_string(), - port: core_port.to_string(), - - username: core_rpc_username, - password: core_rpc_password, - }, - ..Default::default() - }; - - let platform_config = PlatformConfig { - drive: Some(drive_config), - core: core_config, - verify_sum_trees: true, - ..Default::default() - }; - - // TODO: think how to pass this error to JS - let mut platform: Platform = - Platform::::open(path, Some(platform_config)).unwrap(); - - // if cfg!(feature = "enable-mocking") { - // platform.mock_core_rpc_client(); - // } - - let mut maybe_transaction: Option = None; - - // Blocks until a callback is available - // When the instance of `Database` is dropped, the channel will be closed - // and `rx.recv()` will return an `Err`, ending the loop and terminating - // the thread. - while let Ok(message) = rx.recv() { - match message { - PlatformWrapperMessage::Callback(callback) => { - // The connection and channel are owned by the thread, but _lent_ to - // the callback. The callback has exclusive access to the connection - // for the duration of the callback. - callback(&platform, maybe_transaction.as_ref(), &channel); - } - // Immediately close the connection, even if there are pending messages - PlatformWrapperMessage::Close(callback) => { - drop(maybe_transaction); - drop(platform); - - callback(&channel); - break; - } - // Flush message - PlatformWrapperMessage::Flush(callback) => { - platform.drive.grove.flush().unwrap(); - callback(&channel); - } - PlatformWrapperMessage::StartTransaction(callback) => { - let result = if maybe_transaction.is_some() { - Err("transaction is already started".to_string()) - } else { - let transaction = platform.drive.grove.start_transaction(); - - maybe_transaction = Some(transaction); - - Ok(()) - }; - - callback(sender.clone(), result, &channel); - } - PlatformWrapperMessage::CommitTransaction(callback) => { - let result = if maybe_transaction.is_some() { - let mut drive_cache = platform.drive.cache.write().unwrap(); - - drive_cache.cached_contracts.merge_block_cache(); - - drive_cache.cached_contracts.clear_block_cache(); - - platform - .drive - .commit_transaction(maybe_transaction.take().unwrap()) - .map_err(|err| err.to_string()) - } else { - Err("transaction is not started".to_string()) - }; - - callback(&channel, result); - } - PlatformWrapperMessage::RollbackTransaction(callback) => { - let result = if let Some(transaction) = &maybe_transaction { - let mut drive_cache = platform.drive.cache.write().unwrap(); - - drive_cache.cached_contracts.clear_block_cache(); - - platform - .drive - .rollback_transaction(transaction) - .map_err(|err| err.to_string()) - } else { - Err("transaction is not started".to_string()) - }; - - callback(&channel, result); - } - PlatformWrapperMessage::AbortTransaction(callback) => { - let result = if maybe_transaction.is_some() { - let mut drive_cache = platform.drive.cache.write().unwrap(); - - drive_cache.cached_contracts.clear_block_cache(); - - drop(maybe_transaction.take()); - - Ok(()) - } else { - Err("transaction is not started".to_string()) - }; - - callback(&channel, result); - } - } - } - }); - - Ok(Self { tx }) - } - - // Idiomatic rust would take an owned `self` to prevent use after close - // However, it's not possible to prevent JavaScript from continuing to hold a - // closed database - fn close( - &self, - callback: impl FnOnce(&Channel) + Send + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::Close(Box::new(callback))) - } - - fn send_to_drive_thread( - &self, - callback: impl for<'a> FnOnce(&'a Platform, TransactionArg, &Channel) - + Send - + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::Callback(Box::new(callback))) - } - - fn start_transaction( - &self, - callback: impl FnOnce(mpsc::Sender, Result<(), String>, &Channel) - + Send - + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::StartTransaction(Box::new(callback))) - } - - fn commit_transaction( - &self, - callback: impl FnOnce(&Channel, Result<(), String>) + Send + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::CommitTransaction(Box::new( - callback, - ))) - } - - fn rollback_transaction( - &self, - callback: impl FnOnce(&Channel, Result<(), String>) + Send + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::RollbackTransaction(Box::new( - callback, - ))) - } - - fn abort_transaction( - &self, - callback: impl FnOnce(&Channel, Result<(), String>) + Send + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::AbortTransaction(Box::new(callback))) - } - - // Idiomatic rust would take an owned `self` to prevent use after close - // However, it's not possible to prevent JavaScript from continuing to hold a - // closed database - fn flush( - &self, - callback: impl FnOnce(&Channel) + Send + 'static, - ) -> Result<(), mpsc::SendError> { - self.tx - .send(PlatformWrapperMessage::Flush(Box::new(callback))) - } -} - -// Ensures that DriveWrapper is properly disposed when the corresponding JS -// object gets garbage collected -impl Finalize for PlatformWrapper {} - -// External wrapper logic -impl PlatformWrapper { - // Create a new instance of `Drive` and place it inside a `JsBox` - // JavaScript can hold a reference to a `JsBox`, but the contents are opaque - fn js_open(mut cx: FunctionContext) -> JsResult> { - let drive_wrapper = - PlatformWrapper::new(&mut cx).or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.boxed(drive_wrapper)) - } - - /// Sends a message to the DB thread to stop the thread and dispose the - /// groveDb instance owned by it, then calls js callback passed as a first - /// argument to the function - fn js_close(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - drive - .close(|channel| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = - vec![task_context.null().upcast()]; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_create_initial_state_structure(mut cx: FunctionContext) -> JsResult { - let js_using_transaction = cx.argument::(0)?; - let js_callback = cx.argument::(1)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let execution_result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .create_initial_state_structure(transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match execution_result { - Ok(_) => vec![task_context.null().upcast()], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_contract(mut cx: FunctionContext) -> JsResult { - let js_contract_id = cx.argument::(0)?; - let js_maybe_epoch_index = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - let js_callback = cx.argument::(3)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - - let maybe_epoch: Option = if !js_maybe_epoch_index.is_a::(&mut cx) { - let js_epoch_index = js_maybe_epoch_index.downcast_or_throw::(&mut cx)?; - - let epoch_index = u16::try_from(js_epoch_index.value(&mut cx) as i64) - .or_else(|_| cx.throw_range_error("`epochs` must fit in u16"))?; - - let epoch = Epoch::new(epoch_index).unwrap(); - - Some(epoch) - } else { - None - }; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .get_contract_with_fetch_info( - contract_id, - maybe_epoch.as_ref(), - true, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok((maybe_fee_result, maybe_contract_fetch_info)) => { - let js_result = task_context.empty_array(); - - let js_contract: Handle = - if let Some(contract_fetch_info) = maybe_contract_fetch_info { - let contract_cbor = contract_fetch_info - .contract - .to_buffer() - .or_else(|_| { - task_context - .throw_range_error("can't serialize contract") - })?; - - JsBuffer::external(&mut task_context, contract_cbor) - .upcast() - } else { - task_context.null().upcast() - }; - - js_result.set(&mut task_context, 0, js_contract)?; - - if let Some(fee_result) = maybe_fee_result { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - js_result.set(&mut task_context, 1, js_fee_result)?; - } - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_create_contract(mut cx: FunctionContext) -> JsResult { - let js_contract_cbor = cx.argument::(0)?; - let js_block_info = cx.argument::(1)?; - let js_apply = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let contract_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_contract_cbor); - let apply = js_apply.value(&mut cx); - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .insert_contract_cbor( - contract_cbor, - None, - block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_update_contract(mut cx: FunctionContext) -> JsResult { - let js_contract_cbor = cx.argument::(0)?; - let js_block_info = cx.argument::(1)?; - let js_apply = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let contract_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_contract_cbor); - let apply = js_apply.value(&mut cx); - - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .update_contract_cbor( - contract_cbor, - None, - block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_create_document(mut cx: FunctionContext) -> JsResult { - let js_document_cbor = cx.argument::(0)?; - let js_contract_id = cx.argument::(1)?; - let js_document_type_name = cx.argument::(2)?; - let js_owner_id = cx.argument::(3)?; - let js_override_document = cx.argument::(4)?; - let js_block_info = cx.argument::(5)?; - let js_apply = cx.argument::(6)?; - let js_using_transaction = cx.argument::(7)?; - let js_callback = cx.argument::(8)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let document_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_document_cbor); - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - let document_type_name = js_document_type_name.value(&mut cx); - let owner_id = converter::js_buffer_to_identifier(&mut cx, js_owner_id)?; - let override_document = js_override_document.value(&mut cx); - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let storage_flags = - StorageFlags::new_single_epoch(block_info.epoch.index, Some(owner_id)); - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .add_serialized_document_for_contract_id( - &document_cbor, - contract_id, - &document_type_name, - Some(owner_id), - override_document, - block_info, - apply, - storage_flags.into_optional_cow(), - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_update_document(mut cx: FunctionContext) -> JsResult { - let js_document_cbor = cx.argument::(0)?; - let js_contract_id = cx.argument::(1)?; - let js_document_type_name = cx.argument::(2)?; - let js_owner_id = cx.argument::(3)?; - let js_block_info = cx.argument::(4)?; - let js_apply = cx.argument::(5)?; - let js_using_transaction = cx.argument::(6)?; - let js_callback = cx.argument::(7)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let document_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_document_cbor); - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - let document_type_name = js_document_type_name.value(&mut cx); - let owner_id = converter::js_buffer_to_identifier(&mut cx, js_owner_id)?; - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let storage_flags = - StorageFlags::new_single_epoch(block_info.epoch.index, Some(owner_id)); - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .update_document_for_contract_id( - &document_cbor, - contract_id, - &document_type_name, - Some(owner_id), - block_info, - apply, - storage_flags.into_optional_cow(), - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_delete_document(mut cx: FunctionContext) -> JsResult { - let js_document_id = cx.argument::(0)?; - let js_contract_id = cx.argument::(1)?; - let js_document_type_name = cx.argument::(2)?; - let js_block_info = cx.argument::(3)?; - let js_apply = cx.argument::(4)?; - let js_using_transaction = cx.argument::(5)?; - let js_callback = cx.argument::(6)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let document_id = converter::js_buffer_to_identifier(&mut cx, js_document_id)?; - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - let document_type_name = js_document_type_name.value(&mut cx); - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .delete_document_for_contract_id( - document_id, - contract_id, - &document_type_name, - None, - block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_insert_identity_cbor(mut cx: FunctionContext) -> JsResult { - let js_identity_cbor = cx.argument::(0)?; - let js_block_info = cx.argument::(1)?; - let js_apply = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_identity_cbor); - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .add_new_identity_from_cbor_encoded_bytes( - identity_cbor, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identity(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_full_identity(identity_id, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(maybe_identity) => { - if let Some(identity) = maybe_identity { - match identity.to_buffer() { - Ok(serialized_identity) => { - let js_serialized_identity = JsBuffer::external( - &mut task_context, - serialized_identity, - ); - - vec![ - task_context.null().upcast(), - js_serialized_identity.upcast(), - ] - } - Err(e) => { - let err_message = - format!("can't serialise identities: {}", e); - - vec![task_context.error(err_message)?.upcast()] - } - } - } else { - vec![task_context.null().upcast(), task_context.null().upcast()] - } - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identity_balance(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_identity_balance(identity_id, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(maybe_balance) => { - if let Some(credits) = maybe_balance { - let value = JsNumber::new(&mut task_context, credits as f64); - vec![task_context.null().upcast(), value.upcast()] - } else { - vec![task_context.null().upcast(), task_context.null().upcast()] - } - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identity_balance_include_debt_with_costs( - mut cx: FunctionContext, - ) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_block_info = cx.argument::(1)?; - let js_apply = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - - let apply = js_apply.value(&mut cx); - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_identity_balance_include_debt_with_costs( - identity_id, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok((maybe_balance, fee_result)) => { - let js_result = task_context.empty_array(); - - let js_balance: Handle = if let Some(credits) = - maybe_balance - { - let value = JsNumber::new(&mut task_context, credits as f64); - value.upcast() - } else { - task_context.null().upcast() - }; - - js_result.set(&mut task_context, 0, js_balance)?; - - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - js_result.set(&mut task_context, 1, js_fee_result)?; - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identity_balance_with_costs(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_block_info = cx.argument::(1)?; - let js_apply = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - - let apply = js_apply.value(&mut cx); - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_identity_balance_with_costs( - identity_id, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok((maybe_balance, fee_result)) => { - let js_result = task_context.empty_array(); - - let js_balance: Handle = if let Some(credits) = - maybe_balance - { - let value = JsNumber::new(&mut task_context, credits as f64); - value.upcast() - } else { - task_context.null().upcast() - }; - - js_result.set(&mut task_context, 0, js_balance)?; - - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - js_result.set(&mut task_context, 1, js_fee_result)?; - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_proved_identity(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .prove_full_identity(identity_id, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(identity_proof) => { - let js_identity_proof = - JsBuffer::external(&mut task_context, identity_proof); - - vec![task_context.null().upcast(), js_identity_proof.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_many_proved_identities(mut cx: FunctionContext) -> JsResult { - let js_identity_ids = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_ids = converter::js_array_of_buffers_to_identifiers(&mut cx, js_identity_ids)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .proved_full_identities(&identity_ids, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(identities_proof) => { - let js_identities_proof = - JsBuffer::external(&mut task_context, identities_proof); - - vec![task_context.null().upcast(), js_identities_proof.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identities_by_public_key_hashes(mut cx: FunctionContext) -> JsResult { - let js_public_key_hashes = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let public_key_hashes: Vec<[u8; 20]> = - converter::js_array_of_buffers_to_vec(&mut cx, js_public_key_hashes)? - .into_iter() - .map(|hash| { - hash.try_into() - .or_else(|_| cx.throw_error("invalid hash size")) - }) - .collect::>()?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result: Result>>, String> = - transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_full_identities_by_unique_public_key_hashes( - &public_key_hashes, - transaction_arg, - ) - .map_err(|err| err.to_string()) - .and_then(|hashes_to_identities| { - hashes_to_identities - .into_values() - .filter(|identity| identity.is_some()) - .map(|identity| identity.map(|i| i.to_buffer()).transpose()) - .collect::>() - .map_err(|err| err.to_string()) - }) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(hashes_to_identities) => { - let js_array = task_context.empty_array(); - - hashes_to_identities.into_iter().enumerate().try_for_each( - |(i, identity_bytes)| { - let value: Handle = if let Some(bytes) = - identity_bytes - { - JsBuffer::external(&mut task_context, bytes).upcast() - } else { - task_context.null().upcast() - }; - - js_array.set(&mut task_context, i as u32, value).map(|_| ()) - }, - )?; - - vec![task_context.null().upcast(), js_array.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_prove_identities_by_public_key_hashes(mut cx: FunctionContext) -> JsResult { - let js_public_key_hashes = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let public_key_hashes: Vec<[u8; 20]> = - converter::js_array_of_buffers_to_vec(&mut cx, js_public_key_hashes)? - .into_iter() - .map(|hash| { - hash.try_into() - .or_else(|_| cx.throw_error("invalid hash size")) - }) - .collect::>()?; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result: Result, String> = - transaction_result.and_then(|transaction_arg| { - platform - .drive - .prove_full_identities_by_unique_public_key_hashes( - &public_key_hashes, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(proof) => { - let js_proof = JsBuffer::external(&mut task_context, proof); - - vec![task_context.null().upcast(), js_proof.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_fetch_identity_with_costs(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_epoch_index = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - let js_callback = cx.argument::(3)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let epoch_index = u16::try_from(js_epoch_index.value(&mut cx) as i64) - .or_else(|_| cx.throw_range_error("`epochs` must fit in u16"))?; - - let epoch = Epoch::new(epoch_index).unwrap(); - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .fetch_full_identity_with_costs(identity_id, &epoch, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok((maybe_identity, fee_result)) => { - let js_result = task_context.empty_array(); - - let js_identity: Handle = - if let Some(identity) = maybe_identity { - let serialized_identity = - identity.to_buffer().or_else(|e| { - task_context.throw_error(format!( - "can't serialize identity: {}", - e - )) - })?; - - JsBuffer::external(&mut task_context, serialized_identity) - .upcast() - } else { - task_context.null().upcast() - }; - - js_result.set(&mut task_context, 0, js_identity)?; - - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - js_result.set(&mut task_context, 1, js_fee_result)?; - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_add_to_identity_balance(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_balance_to_add = cx.argument::(1)?; - let js_block_info = cx.argument::(2)?; - let js_apply = cx.argument::(3)?; - let js_using_transaction = cx.argument::(4)?; - let js_callback = cx.argument::(5)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - let balance_to_add = js_balance_to_add.value(&mut cx) as u64; - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .add_to_identity_balance( - identity_id, - balance_to_add, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_remove_from_identity_balance(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_amount = cx.argument::(1)?; - let js_block_info = cx.argument::(2)?; - let js_apply = cx.argument::(3)?; - let js_using_transaction = cx.argument::(4)?; - let js_callback = cx.argument::(5)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - let amount = js_amount.value(&mut cx) as u64; - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .remove_from_identity_balance( - identity_id, - amount, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_apply_fees_to_identity_balance(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_fee_result = cx.argument::>(1)?; - let js_using_transaction = cx.argument::(2)?; - let js_callback = cx.argument::(3)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let fee_result = js_fee_result.deref().deref().deref().clone(); - let balance_change = fee_result.into_balance_change(identity_id); - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .apply_balance_change_from_fee_to_identity( - balance_change, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(outcome) => { - let js_fee_result = task_context - .boxed(FeeResultWrapper::new(outcome.actual_fee_paid)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_add_to_system_credits(mut cx: FunctionContext) -> JsResult { - let js_amount = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - let js_callback = cx.argument::(2)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let amount = js_amount.value(&mut cx) as Credits; - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .add_to_system_credits(amount, transaction_arg) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(()) => { - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_add_keys_to_identity(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_keys_to_add = cx.argument::(1)?; - let js_block_info = cx.argument::(2)?; - let js_apply = cx.argument::(3)?; - let js_using_transaction = cx.argument::(4)?; - let js_callback = cx.argument::(5)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - let keys_to_add = converter::js_array_to_keys(&mut cx, js_keys_to_add)?; - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .add_new_keys_to_identity( - identity_id, - keys_to_add, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_disable_identity_keys(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_key_ids = cx.argument::(1)?; - let js_disable_at = cx.argument::(2)?; - let js_block_info = cx.argument::(3)?; - let js_apply = cx.argument::(4)?; - let js_using_transaction = cx.argument::(5)?; - let js_callback = cx.argument::(6)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let key_ids = js_key_ids - .to_vec(&mut cx)? - .into_iter() - .map(|js_value| { - let js_key = js_value.downcast_or_throw::(&mut cx)?; - let key = KeyID::try_from(js_key.value(&mut cx) as u64) - .or_else(|_| cx.throw_range_error("key id must be u32"))?; - - Ok(key) - }) - .collect::, _>>()?; - - let disabled_at = js_disable_at.value(&mut cx) as TimestampMillis; - - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .disable_identity_keys( - identity_id, - key_ids, - disabled_at, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_update_identity_revision(mut cx: FunctionContext) -> JsResult { - let js_identity_id = cx.argument::(0)?; - let js_revision = cx.argument::(1)?; - let js_block_info = cx.argument::(2)?; - let js_apply = cx.argument::(3)?; - let js_using_transaction = cx.argument::(4)?; - let js_callback = cx.argument::(5)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let identity_id = converter::js_buffer_to_identifier(&mut cx, js_identity_id)?; - - let revision = js_revision.value(&mut cx) as Revision; - - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let apply = js_apply.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .update_identity_revision( - identity_id, - revision, - &block_info, - apply, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(fee_result) => { - let js_fee_result = - task_context.boxed(FeeResultWrapper::new(fee_result)); - - // First parameter of JS callbacks is error, which is null in this case - vec![task_context.null().upcast(), js_fee_result.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_query_documents(mut cx: FunctionContext) -> JsResult { - let js_query_cbor = cx.argument::(0)?; - let js_contract_id = cx.argument::(1)?; - let js_document_type_name = cx.argument::(2)?; - let js_maybe_epoch_index = cx.argument::(3)?; - // TODO We need dry run for validation - let js_using_transaction = cx.argument::(4)?; - let js_callback = cx.argument::(5)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let query_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_query_cbor); - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - let document_type_name = js_document_type_name.value(&mut cx); - - let maybe_epoch: Option = if !js_maybe_epoch_index.is_a::(&mut cx) { - let js_epoch_index = js_maybe_epoch_index.downcast_or_throw::(&mut cx)?; - - let epoch_index = u16::try_from(js_epoch_index.value(&mut cx) as i64) - .or_else(|_| cx.throw_range_error("`epochs` must fit in u16"))?; - - let epoch = Epoch::new(epoch_index).unwrap(); - - Some(epoch) - } else { - None - }; - - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .query_documents_cbor_with_document_type_lookup( - &query_cbor, - contract_id, - document_type_name.as_str(), - maybe_epoch.as_ref(), - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(QuerySerializedDocumentsOutcome { - items, - skipped, - cost, - }) => { - let js_array: Handle = task_context.empty_array(); - let js_vecs = - converter::nested_vecs_to_js(&mut task_context, items)?; - let js_num = task_context.number(skipped).upcast::(); - let js_cost = task_context.number(cost as f64).upcast::(); - - js_array.set(&mut task_context, 0, js_vecs)?; - js_array.set(&mut task_context, 1, js_num)?; - js_array.set(&mut task_context, 2, js_cost)?; - - vec![task_context.null().upcast(), js_array.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_prove_documents_query(mut cx: FunctionContext) -> JsResult { - let js_query_cbor = cx.argument::(0)?; - let js_contract_id = cx.argument::(1)?; - let js_document_type_name = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - - let js_callback = cx.argument::(4)?.root(&mut cx); - - let drive = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let query_cbor = converter::js_buffer_to_vec_u8(&mut cx, js_query_cbor); - let contract_id = converter::js_buffer_to_identifier(&mut cx, js_contract_id)?; - let document_type_name = js_document_type_name.value(&mut cx); - let using_transaction = js_using_transaction.value(&mut cx); - - drive - .send_to_drive_thread(move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - platform - .drive - .query_proof_of_documents_using_contract_id_using_cbor_encoded_query_with_cost( - &query_cbor, - contract_id, - document_type_name.as_str(), - None, - None, - transaction_arg, - ) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok((proof, processing_cost)) => { - let js_array: Handle = task_context.empty_array(); - let js_buffer = JsBuffer::external(&mut task_context, proof); - let js_processing_cost = task_context.number(processing_cost as f64); - - js_array.set(&mut task_context, 0, js_buffer)?; - js_array.set(&mut task_context, 1, js_processing_cost)?; - - vec![task_context.null().upcast(), js_array.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_start_transaction(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.start_transaction(|_, result, channel| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(_) => { - vec![task_context.null().upcast()] - } - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_commit_transaction(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.commit_transaction(|channel, result| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(_) => vec![task_context.null().upcast()], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_rollback_transaction(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.rollback_transaction(|channel, result| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(_) => vec![task_context.null().upcast()], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_abort_transaction(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.abort_transaction(|channel, result| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(_) => vec![task_context.null().upcast()], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_is_transaction_started(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |_platform: &Platform, transaction, channel| { - let result = transaction.is_some(); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - // First parameter of JS callbacks is error, which is null in this case - let callback_arguments: Vec> = vec![ - task_context.null().upcast(), - task_context.boolean(result).upcast(), - ]; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_get(mut cx: FunctionContext) -> JsResult { - let js_path = cx.argument::(0)?; - let js_key = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - - let js_callback = cx.argument::(3)?.root(&mut cx); - - let path = converter::js_array_of_buffers_to_vec(&mut cx, js_path)?; - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - - let using_transaction = js_using_transaction.value(&mut cx); - - // Get the `this` value as a `JsBox` - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - let path_slice = path.iter().map(|fragment| fragment.as_slice()); - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .get(path_slice, &key, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(element) => { - // First parameter of JS callbacks is error, which is null in this case - vec![ - task_context.null().upcast(), - converter::element_to_js_object(&mut task_context, element)?, - ] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_insert(mut cx: FunctionContext) -> JsResult { - let js_path = cx.argument::(0)?; - let js_key = cx.argument::(1)?; - let js_element = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - - let js_callback = cx.argument::(4)?.root(&mut cx); - - let path = converter::js_array_of_buffers_to_vec(&mut cx, js_path)?; - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - let element = converter::js_object_to_element(&mut cx, js_element)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - // Get the `this` value as a `JsBox` - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - let path_slice = path.iter().map(|fragment| fragment.as_slice()); - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .insert(path_slice, &key, element, None, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(_) => vec![task_context.null().upcast()], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_insert_if_not_exists(mut cx: FunctionContext) -> JsResult { - let js_path = cx.argument::(0)?; - let js_key = cx.argument::(1)?; - let js_element = cx.argument::(2)?; - let js_using_transaction = cx.argument::(3)?; - - let js_callback = cx.argument::(4)?.root(&mut cx); - - let path = converter::js_array_of_buffers_to_vec(&mut cx, js_path)?; - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - let element = converter::js_object_to_element(&mut cx, js_element)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - // Get the `this` value as a `JsBox` - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let path_slice: Vec<&[u8]> = - path.iter().map(|fragment| fragment.as_slice()).collect(); - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .insert_if_not_exists(path_slice, key.as_slice(), element, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(is_inserted) => vec![ - task_context.null().upcast(), - task_context - .boolean(is_inserted) - .as_value(&mut task_context), - ], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - fn js_grove_db_put_aux(mut cx: FunctionContext) -> JsResult { - let js_key = cx.argument::(0)?; - let js_value = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - - let js_callback = cx.argument::(3)?.root(&mut cx); - - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - let value = converter::js_buffer_to_vec_u8(&mut cx, js_value); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .put_aux(&key, &value, None, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(()) => { - vec![task_context.null().upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_delete_aux(mut cx: FunctionContext) -> JsResult { - let js_key = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - - let js_callback = cx.argument::(2)?.root(&mut cx); - - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .delete_aux(&key, None, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(()) => { - vec![task_context.null().upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_get_aux(mut cx: FunctionContext) -> JsResult { - let js_key = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - - let js_callback = cx.argument::(2)?.root(&mut cx); - - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let using_transaction = js_using_transaction.value(&mut cx); - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .get_aux(&key, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(value) => { - if let Some(value) = value { - vec![ - task_context.null().upcast(), - JsBuffer::external(&mut task_context, value).upcast(), - ] - } else { - vec![task_context.null().upcast(), task_context.null().upcast()] - } - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_query(mut cx: FunctionContext) -> JsResult { - let js_path_query = cx.argument::(0)?; - let js_skip_cache = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - - let js_callback = cx.argument::(3)?.root(&mut cx); - - let path_query = converter::js_path_query_to_path_query(&mut cx, js_path_query)?; - - let skip_cache = js_skip_cache.value(&mut cx); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .query_item_value(&path_query, !skip_cache, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok((values, skipped)) => { - let js_array: Handle = task_context.empty_array(); - let js_vecs = converter::nested_vecs_to_js(&mut task_context, values)?; - let js_num = task_context.number(skipped).upcast::(); - - js_array.set(&mut task_context, 0, js_vecs)?; - js_array.set(&mut task_context, 1, js_num)?; - - vec![task_context.null().upcast(), js_array.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_prove_query(mut cx: FunctionContext) -> JsResult { - let js_path_query = cx.argument::(0)?; - let js_get_verbose_proof = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - - let js_callback = cx.argument::(3)?.root(&mut cx); - - let path_query = converter::js_path_query_to_path_query(&mut cx, js_path_query)?; - - let get_verbose_proof = js_get_verbose_proof.value(&mut cx); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .get_proved_path_query(&path_query, get_verbose_proof, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(proof) => { - let js_buffer = JsBuffer::external(&mut task_context, proof); - let js_value = js_buffer.as_value(&mut task_context); - - vec![task_context.null().upcast(), js_value.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_prove_query_many(mut cx: FunctionContext) -> JsResult { - let js_path_queries = cx.argument::(0)?; - let js_using_transaction = cx.argument::(1)?; - - if js_using_transaction.value(&mut cx) { - cx.throw_type_error("transaction is not supported")?; - } - - let js_callback = cx.argument::(2)?.root(&mut cx); - - let js_path_queries = js_path_queries.to_vec(&mut cx)?; - let mut path_queries: Vec = Vec::with_capacity(js_path_queries.len()); - - for js_path_query in js_path_queries { - let js_path_query = js_path_query.downcast_or_throw::(&mut cx)?; - path_queries.push(converter::js_path_query_to_path_query( - &mut cx, - js_path_query, - )?); - } - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread(move |platform: &Platform, _, channel| { - let grove_db = &platform.drive.grove; - - let path_queries = path_queries.iter().collect(); - - let result = grove_db.prove_query_many(path_queries).unwrap(); - - channel.send(move |mut task_context| { - let this = task_context.undefined(); - let callback = js_callback.into_inner(&mut task_context); - - let callback_arguments = match result { - Ok(proof) => { - let js_buffer = JsBuffer::external(&mut task_context, proof); - let js_value = js_buffer.as_value(&mut task_context); - - vec![task_context.null().upcast(), js_value.upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err.to_string())?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - /// Flush data on disc and then calls js callback passed as a first - /// argument to the function - fn js_grove_db_flush(mut cx: FunctionContext) -> JsResult { - let js_callback = cx.argument::(0)?.root(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.flush(|channel| { - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = vec![task_context.null().upcast()]; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }) - .or_else(|err| cx.throw_error(err.to_string()))?; - - Ok(cx.undefined()) - } - - /// Returns root hash or empty buffer - fn js_grove_db_root_hash(mut cx: FunctionContext) -> JsResult { - let js_using_transaction = cx.argument::(0)?; - - let js_callback = cx.argument::(1)?.root(&mut cx); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .root_hash(transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(hash) => vec![ - task_context.null().upcast(), - JsBuffer::external(&mut task_context, hash).upcast(), - ], - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_grove_db_delete(mut cx: FunctionContext) -> JsResult { - let js_path = cx.argument::(0)?; - let js_key = cx.argument::(1)?; - - let js_using_transaction = cx.argument::(2)?; - - let js_callback = cx.argument::(3)?.root(&mut cx); - - let path = converter::js_array_of_buffers_to_vec(&mut cx, js_path)?; - let key = converter::js_buffer_to_vec_u8(&mut cx, js_key); - - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let grove_db = &platform.drive.grove; - - let path_slice: Vec<&[u8]> = - path.iter().map(|fragment| fragment.as_slice()).collect(); - let result = transaction_result.and_then(|transaction_arg| { - grove_db - .delete(path_slice, key.as_slice(), None, transaction_arg) - .unwrap() - .map_err(Error::GroveDB) - .map_err(|err| err.to_string()) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - let callback_arguments: Vec> = match result { - Ok(()) => { - vec![task_context.null().upcast()] - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } - - fn js_abci_init_chain(mut cx: FunctionContext) -> JsResult { - //this needs to be removed - todo!(); - // let js_request = cx.argument::(0)?; - // let js_using_transaction = cx.argument::(1)?; - // - // let js_callback = cx.argument::(2)?.root(&mut cx); - // - // let using_transaction = js_using_transaction.value(&mut cx); - // - // let db = cx - // .this() - // .downcast_or_throw::, _>(&mut cx)?; - // - // let request_bytes = converter::js_buffer_to_vec_u8(&mut cx, js_request); - // - // db.send_to_drive_thread(move |platform: &Platform, transaction, channel| { - // let transaction_result = if using_transaction { - // if transaction.is_none() { - // Err("transaction is not started".to_string()) - // } else { - // Ok(transaction) - // } - // } else { - // Ok(None) - // }; - // - // let result = transaction_result.and_then(|transaction_arg| { - // InitChainRequest::from_bytes(&request_bytes) - // .and_then(|request| platform.init_chain(request.into())) - // .map_err(|e| e.to_string()) - // }); - // - // channel.send(move |mut task_context| { - // let callback = js_callback.into_inner(&mut task_context); - // let this = task_context.undefined(); - // - // let callback_arguments: Vec> = match result { - // Ok(response_bytes) => { - // let value = JsBuffer::external(&mut task_context, response_bytes); - // - // vec![task_context.null().upcast(), value.upcast()] - // } - // - // // Convert the error to a JavaScript exception on failure - // Err(err) => vec![task_context.error(err)?.upcast()], - // }; - // - // callback.call(&mut task_context, this, callback_arguments)?; - // - // Ok(()) - // }); - // }) - // .or_else(|err| cx.throw_error(err.to_string()))?; - // - // // The result is returned through the callback, not through direct return - // Ok(cx.undefined()) - } - - fn js_abci_block_begin(mut cx: FunctionContext) -> JsResult { - //this needs to be removed - todo!() - // let js_request = cx.argument::(0)?; - // let js_using_transaction = cx.argument::(1)?; - // - // let js_callback = cx.argument::(2)?.root(&mut cx); - // - // let using_transaction = js_using_transaction.value(&mut cx); - // - // let db = cx - // .this() - // .downcast_or_throw::, _>(&mut cx)?; - // - // let request_bytes = converter::js_buffer_to_vec_u8(&mut cx, js_request); - // - // db.send_to_drive_thread(move |platform: &Platform, transaction, channel| { - // let transaction_result = if using_transaction { - // if transaction.is_none() { - // Err("transaction is not started".to_string()) - // } else { - // Ok(transaction) - // } - // } else { - // Ok(None) - // }; - // - // let result = transaction_result.and_then(|transaction_arg| { - // BlockBeginRequest::from_bytes(&request_bytes) - // .and_then(|request| platform.block_begin(request, transaction_arg)) - // .and_then(|response| response.to_bytes()) - // .map_err(|e| e.to_string()) - // }); - // - // channel.send(move |mut task_context| { - // let callback = js_callback.into_inner(&mut task_context); - // let this = task_context.undefined(); - // - // let callback_arguments: Vec> = match result { - // Ok(response_bytes) => { - // let value = JsBuffer::external(&mut task_context, response_bytes); - // - // vec![task_context.null().upcast(), value.upcast()] - // } - // - // // Convert the error to a JavaScript exception on failure - // Err(err) => vec![task_context.error(err)?.upcast()], - // }; - // - // callback.call(&mut task_context, this, callback_arguments)?; - // - // Ok(()) - // }); - // }) - // .or_else(|err| cx.throw_error(err.to_string()))?; - // - // // The result is returned through the callback, not through direct return - // Ok(cx.undefined()) - } - - fn js_abci_block_end(mut cx: FunctionContext) -> JsResult { - //this needs to be removed - todo!() - // let js_request = cx.argument::(0)?; - // - // let js_using_transaction = cx.argument::(1)?; - // - // let js_callback = cx.argument::(2)?.root(&mut cx); - // - // let using_transaction = js_using_transaction.value(&mut cx); - // - // let db = cx - // .this() - // .downcast_or_throw::, _>(&mut cx)?; - // - // let js_fees: Handle = js_request.get(&mut cx, "fees")?; - // - // let js_processing_fee: Handle = js_fees.get(&mut cx, "processingFee")?; - // let processing_fee = js_processing_fee.value(&mut cx) as u64; - // - // let js_storage_fee: Handle = js_fees.get(&mut cx, "storageFee")?; - // let storage_fee = js_storage_fee.value(&mut cx) as u64; - // - // let js_refunds_per_epoch: Handle = js_fees.get(&mut cx, "refundsPerEpoch")?; - // - // let refunds_per_epoch = js_object_to_fee_refunds(&mut cx, js_refunds_per_epoch)?; - // - // db.send_to_drive_thread(move |platform: &Platform, transaction, channel| { - // let transaction_result = if using_transaction { - // if transaction.is_none() { - // Err("transaction is not started".to_string()) - // } else { - // Ok(transaction) - // } - // } else { - // Ok(None) - // }; - // - // let result = transaction_result.and_then(|transaction_arg| { - // let request = BlockEndRequest { - // fees: BlockFees { - // processing_fee, - // storage_fee, - // refunds_per_epoch, - // }, - // }; - // - // platform - // .block_end(request, transaction_arg) - // .and_then(|response| response.to_bytes()) - // .map_err(|e| e.to_string()) - // }); - // - // channel.send(move |mut task_context| { - // let callback = js_callback.into_inner(&mut task_context); - // let this = task_context.undefined(); - // - // let callback_arguments: Vec> = match result { - // Ok(response_bytes) => { - // let value = JsBuffer::external(&mut task_context, response_bytes); - // - // vec![task_context.null().upcast(), value.upcast()] - // } - // - // // Convert the error to a JavaScript exception on failure - // Err(err) => vec![task_context.error(err)?.upcast()], - // }; - // - // callback.call(&mut task_context, this, callback_arguments)?; - // - // Ok(()) - // }); - // }) - // .or_else(|err| cx.throw_error(err.to_string()))?; - // - // // The result is returned through the callback, not through direct return - // Ok(cx.undefined()) - } - - fn js_abci_after_finalize_block(mut cx: FunctionContext) -> JsResult { - //this needs to be removed - todo!(); - // let js_request = cx.argument::(0)?; - // let js_callback = cx.argument::(1)?.root(&mut cx); - // - // let db = cx - // .this() - // .downcast_or_throw::, _>(&mut cx)?; - // - // let request_bytes = converter::js_buffer_to_vec_u8(&mut cx, js_request); - // - // db.send_to_drive_thread(move |platform: &Platform, _, channel| { - // let result = AfterFinalizeBlockRequest::from_bytes(&request_bytes) - // .and_then(|request| platform.after_finalize_block(request)) - // .and_then(|response| response.to_bytes()); - // - // channel.send(move |mut task_context| { - // let callback = js_callback.into_inner(&mut task_context); - // let this = task_context.undefined(); - // - // let callback_arguments: Vec> = match result { - // Ok(response_bytes) => { - // let value = JsBuffer::external(&mut task_context, response_bytes); - // - // vec![task_context.null().upcast(), value.upcast()] - // } - // - // // Convert the error to a JavaScript exception on failure - // Err(err) => vec![task_context.error(err.to_string())?.upcast()], - // }; - // - // callback.call(&mut task_context, this, callback_arguments)?; - // - // Ok(()) - // }); - // }) - // .or_else(|err| cx.throw_error(err.to_string()))?; - // - // // The result is returned through the callback, not through direct return - // Ok(cx.undefined()) - } - - fn js_fetch_latest_withdrawal_transaction_index( - mut cx: FunctionContext, - ) -> JsResult { - let js_block_info = cx.argument::(0)?; - let js_apply = cx.argument::(1)?; - let js_using_transaction = cx.argument::(2)?; - let js_callback = cx.argument::(3)?.root(&mut cx); - - let apply = js_apply.value(&mut cx); - let block_info = converter::js_object_to_block_info(&mut cx, js_block_info)?; - let using_transaction = js_using_transaction.value(&mut cx); - - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - db.send_to_drive_thread( - move |platform: &Platform, transaction, channel| { - let transaction_result = if using_transaction { - if transaction.is_none() { - Err("transaction is not started".to_string()) - } else { - Ok(transaction) - } - } else { - Ok(None) - }; - - let result = transaction_result.and_then(|transaction_arg| { - let mut drive_operation_types = vec![]; - - let result = platform - .drive - .fetch_and_remove_latest_withdrawal_transaction_index_operations( - &mut drive_operation_types, - transaction_arg, - ) - .map_err(|err| err.to_string())?; - - platform - .drive - .apply_drive_operations( - drive_operation_types, - apply, - &block_info, - transaction_arg, - ) - .map_err(|err| err.to_string())?; - - Ok(result) - }); - - channel.send(move |mut task_context| { - let callback = js_callback.into_inner(&mut task_context); - let this = task_context.undefined(); - - let callback_arguments: Vec> = match result { - Ok(index) => { - let index_f64 = index as f64; - if index_f64 as u64 != index { - vec![task_context - .error("could not convert withdrawal transaction index to f64")? - .upcast()] - } else { - let value = JsNumber::new(&mut task_context, index_f64); - - vec![task_context.null().upcast(), value.upcast()] - } - } - - // Convert the error to a JavaScript exception on failure - Err(err) => vec![task_context.error(err)?.upcast()], - }; - - callback.call(&mut task_context, this, callback_arguments)?; - - Ok(()) - }); - }, - ) - .or_else(|err| cx.throw_error(err.to_string()))?; - - // The result is returned through the callback, not through direct return - Ok(cx.undefined()) - } -} - -#[neon::main] -fn main(mut cx: ModuleContext) -> NeonResult<()> { - cx.export_function("driveOpen", PlatformWrapper::js_open)?; - cx.export_function("driveClose", PlatformWrapper::js_close)?; - cx.export_function( - "driveCreateInitialStateStructure", - PlatformWrapper::js_create_initial_state_structure, - )?; - cx.export_function("driveFetchContract", PlatformWrapper::js_fetch_contract)?; - cx.export_function("driveCreateContract", PlatformWrapper::js_create_contract)?; - cx.export_function("driveUpdateContract", PlatformWrapper::js_update_contract)?; - cx.export_function("driveCreateDocument", PlatformWrapper::js_create_document)?; - cx.export_function("driveUpdateDocument", PlatformWrapper::js_update_document)?; - cx.export_function("driveDeleteDocument", PlatformWrapper::js_delete_document)?; - cx.export_function( - "driveInsertIdentity", - PlatformWrapper::js_insert_identity_cbor, - )?; - cx.export_function("driveFetchIdentity", PlatformWrapper::js_fetch_identity)?; - cx.export_function( - "driveFetchIdentityBalance", - PlatformWrapper::js_fetch_identity_balance, - )?; - cx.export_function( - "driveFetchIdentityBalanceWithCosts", - PlatformWrapper::js_fetch_identity_balance_with_costs, - )?; - cx.export_function( - "driveFetchIdentityBalanceIncludeDebtWithCosts", - PlatformWrapper::js_fetch_identity_balance_include_debt_with_costs, - )?; - cx.export_function( - "driveFetchProvedIdentity", - PlatformWrapper::js_fetch_proved_identity, - )?; - cx.export_function( - "driveFetchManyProvedIdentities", - PlatformWrapper::js_fetch_many_proved_identities, - )?; - cx.export_function( - "driveFetchIdentityWithCosts", - PlatformWrapper::js_fetch_identity_with_costs, - )?; - cx.export_function( - "driveAddToIdentityBalance", - PlatformWrapper::js_add_to_identity_balance, - )?; - cx.export_function( - "driveRemoveFromIdentityBalance", - PlatformWrapper::js_remove_from_identity_balance, - )?; - cx.export_function( - "driveApplyFeesToIdentityBalance", - PlatformWrapper::js_apply_fees_to_identity_balance, - )?; - cx.export_function( - "driveAddToSystemCredits", - PlatformWrapper::js_add_to_system_credits, - )?; - cx.export_function( - "driveFetchIdentitiesByPublicKeyHashes", - PlatformWrapper::js_fetch_identities_by_public_key_hashes, - )?; - cx.export_function( - "driveProveIdentitiesByPublicKeyHashes", - PlatformWrapper::js_prove_identities_by_public_key_hashes, - )?; - cx.export_function( - "driveAddKeysToIdentity", - PlatformWrapper::js_add_keys_to_identity, - )?; - cx.export_function( - "driveDisableIdentityKeys", - PlatformWrapper::js_disable_identity_keys, - )?; - cx.export_function( - "driveUpdateIdentityRevision", - PlatformWrapper::js_update_identity_revision, - )?; - - cx.export_function("driveQueryDocuments", PlatformWrapper::js_query_documents)?; - - cx.export_function( - "driveProveDocumentsQuery", - PlatformWrapper::js_prove_documents_query, - )?; - - cx.export_function( - "driveFetchLatestWithdrawalTransactionIndex", - PlatformWrapper::js_fetch_latest_withdrawal_transaction_index, - )?; - - cx.export_function("groveDbInsert", PlatformWrapper::js_grove_db_insert)?; - cx.export_function( - "groveDbInsertIfNotExists", - PlatformWrapper::js_grove_db_insert_if_not_exists, - )?; - cx.export_function("groveDbGet", PlatformWrapper::js_grove_db_get)?; - cx.export_function("groveDbDelete", PlatformWrapper::js_grove_db_delete)?; - cx.export_function("groveDbFlush", PlatformWrapper::js_grove_db_flush)?; - cx.export_function( - "groveDbStartTransaction", - PlatformWrapper::js_grove_db_start_transaction, - )?; - cx.export_function( - "groveDbIsTransactionStarted", - PlatformWrapper::js_grove_db_is_transaction_started, - )?; - cx.export_function( - "groveDbCommitTransaction", - PlatformWrapper::js_grove_db_commit_transaction, - )?; - cx.export_function( - "groveDbRollbackTransaction", - PlatformWrapper::js_grove_db_rollback_transaction, - )?; - cx.export_function( - "groveDbAbortTransaction", - PlatformWrapper::js_grove_db_abort_transaction, - )?; - cx.export_function("groveDbPutAux", PlatformWrapper::js_grove_db_put_aux)?; - cx.export_function("groveDbDeleteAux", PlatformWrapper::js_grove_db_delete_aux)?; - cx.export_function("groveDbGetAux", PlatformWrapper::js_grove_db_get_aux)?; - cx.export_function("groveDbQuery", PlatformWrapper::js_grove_db_query)?; - cx.export_function( - "groveDbProveQuery", - PlatformWrapper::js_grove_db_prove_query, - )?; - cx.export_function( - "groveDbProveQueryMany", - PlatformWrapper::js_grove_db_prove_query_many, - )?; - cx.export_function("groveDbRootHash", PlatformWrapper::js_grove_db_root_hash)?; - - cx.export_function("abciInitChain", PlatformWrapper::js_abci_init_chain)?; - cx.export_function("abciBlockBegin", PlatformWrapper::js_abci_block_begin)?; - cx.export_function("abciBlockEnd", PlatformWrapper::js_abci_block_end)?; - cx.export_function( - "abciAfterFinalizeBlock", - PlatformWrapper::js_abci_after_finalize_block, - )?; - - cx.export_function( - "feeResultGetProcessingFee", - FeeResultWrapper::get_processing_fee, - )?; - cx.export_function("feeResultGetStorageFee", FeeResultWrapper::get_storage_fee)?; - cx.export_function("feeResultAdd", FeeResultWrapper::add)?; - cx.export_function("feeResultAddFees", FeeResultWrapper::add_fees)?; - cx.export_function("feeResultCreate", FeeResultWrapper::create)?; - cx.export_function("feeResultGetRefunds", FeeResultWrapper::get_refunds)?; - cx.export_function( - "feeResultSumRefundsPerEpoch", - FeeResultWrapper::get_refunds_per_epoch, - )?; - - cx.export_function( - "calculateStorageFeeDistributionAmountAndLeftovers", - js_calculate_storage_fee_distribution_amount_and_leftovers, - )?; - - Ok(()) -} diff --git a/packages/rs-drive-nodejs/test/.eslintrc b/packages/rs-drive-nodejs/test/.eslintrc deleted file mode 100644 index 720ced73852..00000000000 --- a/packages/rs-drive-nodejs/test/.eslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "env": { - "node": true, - "mocha": true - }, - "rules": { - "import/no-extraneous-dependencies": "off" - }, - "globals": { - "expect": true - } -} diff --git a/packages/rs-drive-nodejs/test/Drive.spec.js b/packages/rs-drive-nodejs/test/Drive.spec.js deleted file mode 100644 index 931d7d34a07..00000000000 --- a/packages/rs-drive-nodejs/test/Drive.spec.js +++ /dev/null @@ -1,1181 +0,0 @@ -const fs = require('fs'); - -const { PrivateKey } = require('@dashevo/dashcore-lib'); - -const { expect, use } = require('chai'); -use(require('dirty-chai')); - -const DashPlatformProtocol = require('@dashevo/dpp'); - -const Document = require('@dashevo/dpp/lib/document/Document'); -const Identifier = require('@dashevo/dpp/lib/Identifier'); - -const getDataContractFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); -const getDocumentsFixture = require('@dashevo/dpp/lib/test/fixtures/getDocumentsFixture'); -const getIdentityFixture = require('@dashevo/dpp/lib/test/fixtures/getIdentityFixture'); -const generateRandomIdentifier = require('@dashevo/dpp/lib/test/utils/generateRandomIdentifier'); - -const withdrawalContractDocumentsSchema = require('@dashevo/withdrawals-contract/schema/withdrawals-documents.json'); -const withdrawalContractIds = require('@dashevo/withdrawals-contract/lib/systemIds'); - -const { - expectFeeResult, -} = require('./utils'); - -const Drive = require('../Drive'); - -const FeeResult = require('../FeeResult'); - -const TEST_DATA_PATH = './test_data'; - -describe('Drive', function main() { - this.timeout(10000); - - let drive; - let dataContract; - let identity; - let blockInfo; - let documents; - let initialRootHash; - let withdrawalsDataContract; - - beforeEach(async () => { - drive = new Drive(TEST_DATA_PATH, { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - const dpp = new DashPlatformProtocol({ - stateRepository: { - fetchDataContract: () => { }, - }, - }); - - await dpp.initialize(); - - withdrawalsDataContract = dpp.dataContract.create( - generateRandomIdentifier(), - withdrawalContractDocumentsSchema, - ); - - withdrawalsDataContract.id = Identifier.from(withdrawalContractIds.contractId); - - dataContract = getDataContractFixture(); - identity = getIdentityFixture(); - - blockInfo = { - height: 1, - epoch: 1, - timeMs: new Date().getTime(), - }; - - documents = getDocumentsFixture(dataContract); - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - afterEach(async () => { - await drive.close(); - - fs.rmSync(TEST_DATA_PATH, { recursive: true }); - }); - - describe('#createInitialStateStructure', () => { - it('should create initial tree structure', async () => { - const result = await drive.createInitialStateStructure(); - - // eslint-disable-next-line no-unused-expressions - expect(result).to.be.undefined; - }); - }); - - describe('#fetchContract', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if contract not exists', async () => { - const result = await drive.fetchContract(Buffer.alloc(32), blockInfo.epoch); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [fetchedDataContract, feeResult] = result; - - expect(fetchedDataContract).to.be.null(); - - expect(feeResult).to.be.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - - it('should return contract if contract is present', async () => { - await drive.createContract(dataContract, blockInfo); - - const result = await drive.fetchContract(dataContract.getId(), blockInfo.epoch); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [fetchedDataContract, feeResult] = result; - - expect(fetchedDataContract.toBuffer()).to.deep.equal(dataContract.toBuffer()); - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - - it('should return contract without fee result if epoch is not passed', async () => { - await drive.createContract(dataContract, blockInfo); - - const result = await drive.fetchContract(dataContract.getId()); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(1); - - const [fetchedDataContract] = result; - - expect(fetchedDataContract.toBuffer()).to.deep.equal(dataContract.toBuffer()); - }); - }); - - describe('#createContract', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should create contract', async () => { - const result = await drive.createContract(dataContract, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - - it('should not create contract with dry run flag', async () => { - const result = await drive.createContract(dataContract, blockInfo, undefined, true); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#updateContract', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - - dataContract.setDocumentSchema('newDocumentType', { - type: 'object', - properties: { - newProperty: { - type: 'string', - }, - }, - additionalProperties: false, - }); - }); - - it('should update existing contract', async () => { - const result = await drive.updateContract(dataContract, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - - it('should not create contract with dry run flag', async () => { - const result = await drive.updateContract(dataContract, blockInfo, undefined, true); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#createDocument', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - context('without indices', () => { - it('should create a document', async () => { - const documentWithoutIndices = documents[0]; - - const result = await drive.createDocument(documentWithoutIndices, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - context('with indices', () => { - it('should create a document', async () => { - const documentWithIndices = documents[3]; - - const result = await drive.createDocument(documentWithIndices, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - it('should not create a document with dry run flag', async () => { - const documentWithoutIndices = documents[0]; - - const result = await drive.createDocument(documentWithoutIndices, blockInfo, undefined, true); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#updateDocument', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - context('without indices', () => { - it('should update a document', async () => { - // Create a document - const documentWithoutIndices = documents[0]; - - await drive.createDocument(documentWithoutIndices, blockInfo); - - // Update the document - documentWithoutIndices.set('name', 'Boooooooooooob'); - - const result = await drive.updateDocument(documentWithoutIndices, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - context('with indices', () => { - it('should update the document', async () => { - // Create a document - const documentWithIndices = documents[3]; - - await drive.createDocument(documentWithIndices, blockInfo); - - // Update the document - documentWithIndices.set('firstName', 'Bob'); - - const result = await drive.updateDocument(documentWithIndices, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - it('should not update a document with dry run flag', async () => { - const documentWithoutIndices = documents[0]; - - documentWithoutIndices.set('name', 'Boooooooooooooooooooooob'); - - const result = await drive.updateDocument(documentWithoutIndices, blockInfo, undefined, true); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.be.greaterThan(0); - expect(result.storageFee).to.be.greaterThan(0, 'storage fee must be higher than 0'); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#deleteDocument', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - context('without indices', () => { - it('should delete the document', async () => { - // Create a document - const documentWithoutIndices = documents[3]; - - await drive.createDocument(documentWithoutIndices, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - - const result = await drive.deleteDocument( - dataContract.getId(), - documentWithoutIndices.getType(), - documentWithoutIndices.getId(), - blockInfo, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.be.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - context('with indices', () => { - it('should delete the document', async () => { - // Create a document - const documentWithIndices = documents[3]; - - await drive.createDocument(documentWithIndices, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - - const result = await drive.deleteDocument( - dataContract.getId(), - documentWithIndices.getType(), - documentWithIndices.getId(), - blockInfo, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.be.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - it('should not delete the document with dry run flag', async () => { - // Create a document - const documentWithoutIndices = documents[3]; - - await drive.createDocument(documentWithoutIndices, blockInfo); - - initialRootHash = await drive.getGroveDB().getRootHash(); - - const result = await drive.deleteDocument( - dataContract.getId(), - documentWithoutIndices.getType(), - documentWithoutIndices.getId(), - blockInfo, - undefined, - true, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.be.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#queryDocuments', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - }); - - it('should query existing documents', async () => { - // Create documents - await Promise.all( - documents.map((document) => drive.createDocument(document, blockInfo)), - ); - - // eslint-disable-next-line no-unused-vars - const [fetchedDocuments, processingCost] = await drive.queryDocuments(dataContract, 'indexedDocument', undefined, { - where: [['lastName', '==', 'Kennedy']], - }); - - expect(fetchedDocuments).to.have.lengthOf(1); - expect(fetchedDocuments[0]).to.be.an.instanceOf(Document); - expect(fetchedDocuments[0].toObject()).to.deep.equal(documents[4].toObject()); - - // costs are not calculating without block info - expect(processingCost).to.be.equal(0); - }); - - it('should query existing documents again', async () => { - // Create documents - await Promise.all( - documents.map((document) => drive.createDocument(document, blockInfo)), - ); - - // eslint-disable-next-line no-unused-vars - const [fetchedDocuments, processingCost] = await drive.queryDocuments(dataContract, 'indexedDocument', blockInfo.epoch, { - where: [['lastName', '==', 'Kennedy']], - }); - - expect(fetchedDocuments).to.have.lengthOf(1); - expect(fetchedDocuments[0]).to.be.an.instanceOf(Document); - expect(fetchedDocuments[0].toObject()).to.deep.equal(documents[4].toObject()); - - expect(processingCost).to.be.greaterThan(0); - }); - - it('should return empty array if documents are not exist', async () => { - // eslint-disable-next-line no-unused-vars - const [fetchedDocuments, processingCost] = await drive.queryDocuments(dataContract, 'indexedDocument', blockInfo.epoch, { - where: [['lastName', '==', 'Kennedy']], - }); - - expect(fetchedDocuments).to.have.lengthOf(0); - expect(processingCost).to.be.greaterThan(0); - }); - }); - - describe('#proveDocumentsQuery', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - await drive.createContract(dataContract, blockInfo); - }); - - it('should query existing documents', async () => { - // Create documents - await Promise.all( - documents.map((document) => drive.createDocument(document, blockInfo)), - ); - - const result = await drive.proveDocumentsQuery(dataContract, 'indexedDocument', { - where: [['lastName', '==', 'Kennedy']], - }); - - expect(result).to.have.lengthOf(2); - - const [proofs, processingCost] = result; - expect(proofs).to.be.an.instanceOf(Buffer); - expect(proofs.length).to.be.greaterThan(0); - - // TODO: We do not calculating processing costs for poofs yet - expect(processingCost).to.equal(0); - }); - }); - - describe('#insertIdentity', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should create identity if not exists', async () => { - const result = await drive.insertIdentity(identity, blockInfo); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.not.deep.equals(initialRootHash); - }); - }); - - describe('#fetchIdentity', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if identity not exists', async () => { - const result = await drive.fetchIdentity(Buffer.alloc(32)); - - expect(result).to.be.null(); - }); - - it('should return identity if it is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.fetchIdentity(identity.getId()); - - expect(result.toBuffer()).to.deep.equal(identity.toBuffer()); - }); - }); - - describe('#fetchIdentityWithCosts', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if contract not exists', async () => { - const result = await drive.fetchIdentityWithCosts(Buffer.alloc(32), blockInfo.epoch); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [fetchedIdentity, feeResult] = result; - - expect(fetchedIdentity).to.be.null(); - - expect(feeResult).to.be.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - - it('should return contract if contract is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.fetchIdentityWithCosts(identity.getId(), blockInfo.epoch); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [fetchedIdentity, feeResult] = result; - - expect(fetchedIdentity.toBuffer()).to.deep.equal(identity.toBuffer()); - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - }); - - describe('#fetchIdentityBalance', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if identity not exists', async () => { - const result = await drive.fetchIdentityBalance(Buffer.alloc(32)); - - expect(result).to.be.null(); - }); - - it('should return balance if identity is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const balance = await drive.fetchIdentityBalance(identity.getId()); - - expect(balance).to.deep.equal(identity.getBalance()); - }); - }); - - describe('#fetchIdentityBalanceWithCosts', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if identity not exists', async () => { - const result = await drive.fetchIdentityBalanceWithCosts(Buffer.alloc(32), blockInfo); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [balance, feeResult] = result; - - expect(balance).to.be.null(); - - expect(feeResult).to.be.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - - it('should return contract if identity is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.fetchIdentityBalanceWithCosts(identity.getId(), blockInfo); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [balance, feeResult] = result; - - expect(balance).to.equal(identity.getBalance()); - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - }); - - describe('#fetchIdentityBalanceIncludeDebtWithCosts', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return null if identity not exists', async () => { - const result = await drive.fetchIdentityBalanceIncludeDebtWithCosts( - Buffer.alloc(32), - blockInfo, - ); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [balance, feeResult] = result; - - expect(balance).to.be.null(); - - expect(feeResult).to.be.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - - it('should return balance if identity is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.fetchIdentityBalanceIncludeDebtWithCosts( - identity.getId(), - blockInfo, - ); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.have.lengthOf(2); - - const [balance, feeResult] = result; - - expect(balance).to.equal(identity.getBalance()); - - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - }); - }); - - describe('#addToIdentityBalance', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should add to balance', async () => { - await drive.insertIdentity(identity, blockInfo); - - const amount = 100; - - const result = await drive.addToIdentityBalance( - identity.getId(), - amount, - blockInfo, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getBalance()).to.equals(identity.getBalance() + amount); - }); - - it('should not update state with dry run', async () => { - initialRootHash = await drive.getGroveDB().getRootHash(); - - const result = await drive.addToIdentityBalance( - identity.getId(), - 100, - blockInfo, - false, - true, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#removeFromIdentitiyBalance', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should remove from balance', async () => { - await drive.insertIdentity(identity, blockInfo); - - const amount = 2; - - const result = await drive.removeFromIdentityBalance( - identity.getId(), - amount, - blockInfo, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getBalance()).to.equals( - identity.getBalance() - amount, - ); - }); - - it('should not update state with dry run', async () => { - initialRootHash = await drive.getGroveDB().getRootHash(); - - const amount = 2; - - const result = await drive.removeFromIdentityBalance( - identity.getId(), - amount, - blockInfo, - false, - true, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#applyFeesToIdentityBalance', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should change balance according to provided fees', async () => { - blockInfo.epoch = 3; - - await drive.insertIdentity(identity, blockInfo); - - const feeResult = FeeResult.create(10000, 10, [{ - identifier: identity.getId().toBuffer(), - creditsPerEpoch: { 0: 1000000 }, - }]); - - const result = await drive.applyFeesToIdentityBalance( - identity.getId(), - feeResult, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getBalance()).to.not.equals( - identity.getBalance(), - ); - }); - }); - - describe('#addToSystemCredits', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should add to system credits', async () => { - await drive.addToSystemCredits( - 100, - ); - }); - }); - - describe('#fetchIdentitiesByPublicKeyHashes', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should return empty array if identity not exists', async () => { - const result = await drive.fetchIdentitiesByPublicKeyHashes([Buffer.alloc(20)]); - - expect(result).to.be.instanceOf(Array); - expect(result).to.be.empty(); - }); - - it('should return identities if it is present', async () => { - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.fetchIdentitiesByPublicKeyHashes( - identity.getPublicKeys().map((k) => k.hash()), - ); - - expect(result).to.deep.equal(identity.getPublicKeys().map(() => identity)); - }); - }); - - describe('#addKeysToIdentity', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should add keys to identity', async () => { - const keysToAdd = [identity.getPublicKeys().pop()]; - - await drive.insertIdentity(identity, blockInfo); - - const result = await drive.addKeysToIdentity( - identity.getId(), - keysToAdd, - blockInfo, - ); - - expectFeeResult(result); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getPublicKeys()).to.have.lengthOf( - identity.getPublicKeys().length + keysToAdd.length, - ); - }); - - it('should not update state with dry run', async () => { - initialRootHash = await drive.getGroveDB().getRootHash(); - - const keysToAdd = [identity.getPublicKeys().pop()]; - - const result = await drive.addKeysToIdentity( - identity.getId(), - keysToAdd, - blockInfo, - false, - true, - ); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#disableIdentityKeys', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should disable specified identity keys', async () => { - await drive.insertIdentity(identity, blockInfo); - - const keyIds = identity.getPublicKeys().map((key) => key.getId()); - const disableAt = Date.now(); - - const result = await drive.disableIdentityKeys( - identity.getId(), - keyIds, - disableAt, - blockInfo, - ); - - expectFeeResult(result); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getPublicKeys()).to.have.lengthOf(identity.getPublicKeys().length); - - fetchedIdentity.getPublicKeys().forEach((key) => { - expect(key.getDisabledAt()).to.equals(disableAt); - }); - }); - - it('should not update state with dry run', async () => { - const keyIds = identity.getPublicKeys().map((key) => key.getId()); - const disableAt = Date.now(); - - const result = await drive.disableIdentityKeys( - identity.getId(), - keyIds, - disableAt, - blockInfo, - false, - true, - ); - - expectFeeResult(result); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#updateIdentityRevision', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - - initialRootHash = await drive.getGroveDB().getRootHash(); - }); - - it('should update identity revision', async () => { - await drive.insertIdentity(identity, blockInfo); - - const revision = 2; - - const result = await drive.updateIdentityRevision( - identity.getId(), - revision, - blockInfo, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - const fetchedIdentity = await drive.fetchIdentity(identity.getId()); - - expect(fetchedIdentity.getRevision()).to.equals(revision); - }); - - it('should not update state with dry run', async () => { - const result = await drive.updateIdentityRevision( - identity.getId(), - 2, - blockInfo, - false, - true, - ); - - expect(result).to.be.an.instanceOf(FeeResult); - - expect(result.processingFee).to.greaterThan(0, 'processing fee must be higher than 0'); - expect(result.storageFee).to.be.equal(0, 'storage fee must be equal to 0'); - - expect(await drive.getGroveDB().getRootHash()).to.deep.equals(initialRootHash); - }); - }); - - describe('#fetchLatestWithdrawalTransactionIndex', () => { - beforeEach(async () => { - await drive.createInitialStateStructure(); - }); - - it('should return 0 on the first call', async () => { - const result = await drive.fetchLatestWithdrawalTransactionIndex({ - height: 1, - epoch: 1, - timeMs: (new Date()).getTime(), - }); - - expect(result).to.equal(0); - }); - }); - - describe('ABCI', () => { - let initChainRequest; - - function generateRequiredIdentityPublicKeysSet() { - return { - master: new PrivateKey().toPublicKey().toBuffer(), - high: new PrivateKey().toPublicKey().toBuffer(), - }; - } - - beforeEach(() => { - initChainRequest = { - genesisTimeMs: Date.now(), - systemIdentityPublicKeys: { - masternodeRewardSharesContractOwner: generateRequiredIdentityPublicKeysSet(), - featureFlagsContractOwner: generateRequiredIdentityPublicKeysSet(), - dpnsContractOwner: generateRequiredIdentityPublicKeysSet(), - withdrawalsContractOwner: generateRequiredIdentityPublicKeysSet(), - dashpayContractOwner: generateRequiredIdentityPublicKeysSet(), - }, - }; - }); - - describe('InitChain', () => { - it('should successfully init chain', async () => { - const response = await drive.getAbci().initChain(initChainRequest); - - expect(response).to.be.empty('object'); - }); - }); - - describe('BlockBegin', () => { - beforeEach(async () => { - await drive.getAbci().initChain(initChainRequest); - }); - - it('should process a block without previous block time', async () => { - const request = { - blockHeight: 1, - blockTimeMs: (new Date()).getTime(), - proposerProTxHash: Buffer.alloc(32, 1), - proposedAppVersion: 1, - validatorSetQuorumHash: Buffer.alloc(32, 2), - lastSyncedCoreHeight: 1, - coreChainLockedHeight: 1, - totalHpmns: 100, - }; - - const response = await drive.getAbci().blockBegin(request); - - expect(response.unsignedWithdrawalTransactions).to.be.empty(); - expect(response.epochInfo).to.deep.equal({ - currentEpochIndex: 0, - isEpochChange: true, - previousEpochIndex: null, - }); - }); - - it('should process a block with previous block time', async () => { - const blockTimeMs = (new Date()).getTime(); - - await drive.getAbci().blockBegin({ - blockHeight: 1, - blockTimeMs, - proposerProTxHash: Buffer.alloc(32, 1), - proposedAppVersion: 1, - validatorSetQuorumHash: Buffer.alloc(32, 2), - lastSyncedCoreHeight: 1, - coreChainLockedHeight: 1, - totalHpmns: 100, - }); - - const response = await drive.getAbci().blockBegin({ - blockHeight: 2, - blockTimeMs: blockTimeMs + 100, - proposerProTxHash: Buffer.alloc(32, 1), - previousBlockTimeMs: blockTimeMs, - proposedAppVersion: 1, - validatorSetQuorumHash: Buffer.alloc(32, 2), - lastSyncedCoreHeight: 1, - coreChainLockedHeight: 1, - totalHpmns: 100, - }); - - expect(response.unsignedWithdrawalTransactions).to.be.empty(); - expect(response.epochInfo).to.deep.equal({ - currentEpochIndex: 0, - isEpochChange: false, - previousEpochIndex: null, - }); - }); - }); - - describe('BlockEnd', () => { - beforeEach(async () => { - await drive.getAbci().initChain(initChainRequest); - - await drive.getAbci().blockBegin({ - blockHeight: 1, - blockTimeMs: (new Date()).getTime(), - proposedAppVersion: 1, - proposerProTxHash: Buffer.alloc(32, 1), - validatorSetQuorumHash: Buffer.alloc(32, 2), - lastSyncedCoreHeight: 1, - coreChainLockedHeight: 1, - totalHpmns: 100, - }); - }); - - it('should process a block', async () => { - const request = { - fees: { - storageFee: 0, - processingFee: 0, - refundsPerEpoch: {}, - }, - }; - - const response = await drive.getAbci().blockEnd(request); - - expect(response).to.have.property('proposersPaidCount'); - expect(response).to.have.property('paidEpochIndex'); - expect(response).to.have.property('refundedEpochsCount'); - }); - }); - - describe('AfterFinalizeBlock', () => { - beforeEach(async function beforeEach() { - this.timeout(10000); - - await drive.getAbci().initChain(initChainRequest); - - await drive.createContract(dataContract, blockInfo); - await drive.createContract(withdrawalsDataContract, blockInfo); - - await drive.getAbci().blockBegin({ - blockHeight: 1, - blockTimeMs: (new Date()).getTime(), - proposedAppVersion: 1, - proposerProTxHash: Buffer.alloc(32, 1), - validatorSetQuorumHash: Buffer.alloc(32, 2), - lastSyncedCoreHeight: 1, - coreChainLockedHeight: 1, - totalHpmns: 100, - }); - - await drive.getAbci().blockEnd({ - fees: { - storageFee: 0, - processingFee: 0, - refundsPerEpoch: {}, - }, - }); - }); - - it('should process a block', async function it() { - this.timeout(10000); - - const request = { - updatedDataContractIds: [dataContract.getId()], - }; - - const response = await drive.getAbci().afterFinalizeBlock(request); - - expect(response).to.be.empty(); - }); - }); - }); - - describe('.calculateStorageFeeDistributionAmountAndLeftovers', () => { - it('should calculate amount and leftovers', () => { - const result = Drive.calculateStorageFeeDistributionAmountAndLeftovers(1000, 1, 2); - - expect(result).to.be.an.instanceOf(Array); - expect(result).to.be.lengthOf(2); - - const [amount, leftovers] = result; - - expect(amount).to.equals(556); - expect(leftovers).to.equals(440); - }); - }); -}); diff --git a/packages/rs-drive-nodejs/test/GroveDB.spec.js b/packages/rs-drive-nodejs/test/GroveDB.spec.js deleted file mode 100644 index 0e2000d161a..00000000000 --- a/packages/rs-drive-nodejs/test/GroveDB.spec.js +++ /dev/null @@ -1,1240 +0,0 @@ -const fs = require('fs'); - -const { expect, use } = require('chai'); -use(require('dirty-chai')); - -const Drive = require('../Drive'); - -const TEST_DATA_PATH = './test_data'; - -describe('GroveDB', () => { - let drive; - let groveDb; - let treeKey; - let itemKey; - let itemValue; - let rootTreePath; - let itemTreePath; - let otherTreeKey; - - beforeEach(() => { - drive = new Drive(TEST_DATA_PATH, { - drive: { - dataContractsGlobalCacheSize: 500, - dataContractsBlockCacheSize: 500, - }, - core: { - rpc: { - url: '127.0.0.1', - username: '', - password: '', - }, - }, - }); - - groveDb = drive.getGroveDB(); - - treeKey = Buffer.from('test_tree'); - itemKey = Buffer.from('test_key'); - itemValue = Buffer.from('very nice test value'); - - rootTreePath = []; - itemTreePath = [treeKey]; - - otherTreeKey = Buffer.from('other_tree'); - }); - - afterEach(async () => { - await drive.close(); - - fs.rmSync(TEST_DATA_PATH, { recursive: true }); - }); - - it('should store and retrieve reference', async () => { - await groveDb.insert( - rootTreePath, - otherTreeKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - await groveDb.insert( - [otherTreeKey], - itemKey, - { - type: 'reference', - epoch: 0, - value: { - type: 'absolutePathReference', - path: [...itemTreePath, itemKey], - }, - }, - ); - - const result = await groveDb.get( - [otherTreeKey], - itemKey, - ); - - expect(result).to.exist(); - expect(result.type).to.equals('item'); - expect(result.value).to.deep.equals(itemValue); - }); - - it('should store and retrieve a value', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - const element = await groveDb.get(itemTreePath, itemKey); - - expect(element.type).to.be.equal('item'); - expect(element.value).to.deep.equal(itemValue); - }); - - it('should store and delete a value', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - // Get item - const element = await groveDb.get(itemTreePath, itemKey); - - expect(element.type).to.be.equal('item'); - expect(element.value).to.deep.equal(itemValue); - - // Delete an item from the subtree - await groveDb.delete( - itemTreePath, - itemKey, - ); - - try { - await groveDb.get(itemTreePath, itemKey); - - expect.fail('Expected to throw en error'); - } catch (e) { - expect(e.message).to.be.equal('grovedb: path key not found: key not found in Merk for get: 746573745f6b6579'); - } - }); - - describe('#get', () => { - it('should return error if key is not exist', async () => { - try { - await groveDb.get([], Buffer.from('nothing')); - - expect.fail('should throw an error'); - } catch (e) { - expect(e.message).to.equal('grovedb: path key not found: key not found in Merk for get: 6e6f7468696e67'); - // appendStack wrapper should add call stack to neon binding errors - expect(e.stack).to.not.equal('grovedb: path key not found: key not found in Merk for get: 6e6f7468696e67'); - expect(e.stack).to.be.a('string').and.satisfy((msg) => ( - msg.startsWith('Error: grovedb: path key not found: key not found in Merk for get: 6e6f7468696e67') - )); - } - }); - }); - - describe('#startTransaction', () => { - it('should not allow to read transactional data from main database until it\'s committed', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree' }, - ); - - await groveDb.startTransaction(); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - true, - ); - - // Inserted value is not yet commited, but can be retrieved by `get` - // with `useTransaction` flag. - const elementInTransaction = await groveDb.get(itemTreePath, itemKey, true); - - expect(elementInTransaction.type).to.be.equal('item'); - expect(elementInTransaction.value).to.deep.equal(itemValue); - - // ... and using `get` without the flag should return no value - try { - await groveDb.get(itemTreePath, itemKey); - - expect.fail('Expected to throw an error'); - } catch (e) { - expect(e.message).to.be.equal('grovedb: path key not found: key not found in Merk for get: 746573745f6b6579'); - } - }); - }); - - describe('#commitTransaction', () => { - it('should commit transactional data to main database', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.startTransaction(); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - true, - ); - - // ... and using `get` without the flag should return no value - try { - await groveDb.get(itemTreePath, itemKey); - - expect.fail('Expected to throw an error'); - } catch (e) { - expect(e.message).to.be.equal('grovedb: path key not found: key not found in Merk for get: 746573745f6b6579'); - } - - await groveDb.commitTransaction(); - - // When committed, the value should be accessible without running transaction - const element = await groveDb.get(itemTreePath, itemKey); - expect(element.type).to.be.equal('item'); - expect(element.value).to.deep.equal(itemValue); - }); - }); - - describe('#rollbackTransaction', () => { - it('should rollaback transaction state to its initial state', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.startTransaction(); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - true, - ); - - // Should rollback inserted item - await groveDb.rollbackTransaction(); - - try { - await groveDb.get(itemTreePath, itemKey); - - expect.fail('Expected to throw an error'); - } catch (e) { - expect(e.message).to.be.equal('grovedb: path key not found: key not found in Merk for get: 746573745f6b6579'); - } - }); - }); - - describe('#isTransactionStarted', () => { - it('should return true if transaction is started', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0, value: Buffer.alloc(32) }, - ); - - await groveDb.startTransaction(); - - const result = await groveDb.isTransactionStarted(); - - // eslint-disable-next-line no-unused-expressions - expect(result).to.be.true; - }); - - it('should return false if transaction is not started', async () => { - const result = await groveDb.isTransactionStarted(); - - // eslint-disable-next-line no-unused-expressions - expect(result).to.be.false; - }); - }); - - describe('#abortTransaction', () => { - it('should abort transaction', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.startTransaction(); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - true, - ); - - // Should abort inserted item - await groveDb.abortTransaction(); - - const isTransactionStarted = await groveDb.isTransactionStarted(); - - // eslint-disable-next-line no-unused-expressions - expect(isTransactionStarted).to.be.false; - - try { - await groveDb.get(itemTreePath, itemKey); - - expect.fail('Expected to throw an error'); - } catch (e) { - expect(e.message).to.be.equal('grovedb: path key not found: key not found in Merk for get: 746573745f6b6579'); - } - }); - }); - - describe('#insertIfNotExists', () => { - it('should insert a value if key is not exist yet', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - // Inserting an item into the subtree - await groveDb.insertIfNotExists( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - const element = await groveDb.get(itemTreePath, itemKey); - - expect(element.type).to.equal('item'); - expect(element.value).to.deep.equal(itemValue); - }); - - it('shouldn\'t overwrite already stored value', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - const newItemValue = Buffer.from('replaced item value'); - - // Inserting an item into the subtree - await groveDb.insertIfNotExists( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: newItemValue }, - ); - - const element = await groveDb.get(itemTreePath, itemKey); - - expect(element.type).to.equal('item'); - expect(element.value).to.deep.equal(itemValue); - }); - }); - - describe('#insert', () => { - it('should be able to insert a tree', async () => { - await groveDb.insert( - [], - Buffer.from('test_tree'), - { type: 'tree', epoch: 0 }, - ); - }); - - it('should throw when trying to insert non-existent element type', async () => { - const path = []; - const key = Buffer.from('test_key'); - - try { - await groveDb.insert( - path, - key, - { type: 'not_a_tree', epoch: 0 }, - ); - - expect.fail('Expected to throw en error'); - } catch (e) { - expect(e.message).to.be.equal('Unexpected element type not_a_tree'); - } - }); - }); - - describe('auxiliary data methods', () => { - let key; - let value; - - beforeEach(() => { - key = Buffer.from('aux_key'); - value = Buffer.from('ayy'); - }); - - it('should be able to store and get aux data', async () => { - await groveDb.putAux(key, value); - - const result = await groveDb.getAux(key); - - expect(result).to.deep.equal(value); - }); - - it('should be able to insert and delete aux data', async () => { - await groveDb.putAux(key, value); - - await groveDb.deleteAux(key); - - const result = await groveDb.getAux(key); - - // eslint-disable-next-line no-unused-expressions - expect(result).to.be.null; - }); - }); - - describe('#query', () => { - let aValue; - let aKey; - let bValue; - let bKey; - let cValue; - let cKey; - - beforeEach(async () => { - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - aValue = Buffer.from('a'); - aKey = Buffer.from('aKey'); - bValue = Buffer.from('b'); - bKey = Buffer.from('bKey'); - cValue = Buffer.from('c'); - cKey = Buffer.from('cKey'); - - await groveDb.insert( - itemTreePath, - aKey, - { type: 'item', epoch: 0, value: aValue }, - ); - - await groveDb.insert( - itemTreePath, - bKey, - { type: 'item', epoch: 0, value: bValue }, - ); - - await groveDb.insert( - itemTreePath, - cKey, - { type: 'item', epoch: 0, value: cValue }, - ); - }); - - it('should be able to use limit', async () => { - const query = { - path: itemTreePath, - query: { - limit: 1, - query: { - items: [ - { - type: 'rangeFrom', - from: bValue, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to use offset', async () => { - const query = { - path: itemTreePath, - query: { - offset: 1, - query: { - items: [ - { - type: 'rangeFrom', - from: bValue, - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - cValue, - ]); - - expect(skipped).to.equals(1); - }); - - it('should be able to retrieve data using `key`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'key', - key: aKey, - }, - { - type: 'key', - key: bKey, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `range`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'range', - from: aKey, - to: cKey, - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeInclusive`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeInclusive', - from: aKey, - to: bKey, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeFull`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeFull', - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - cValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeFrom`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeFrom', - from: bKey, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - bValue, - cValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeTo`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeTo', - to: cKey, - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeToInclusive`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeToInclusive', - to: cKey, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - aValue, - bValue, - cValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeAfter`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeAfter', - after: aKey, - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - bValue, - cValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeAfterTo`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeAfterTo', - after: aKey, - to: cKey, - }, - ], - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - bValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data using `rangeAfterToInclusive`', async () => { - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeAfterToInclusive', - after: aKey, - to: cKey, - }, - ], - }, - - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - bValue, - cValue, - ]); - - expect(skipped).to.equals(0); - }); - - it('should be able to retrieve data with subquery', async () => { - // Prepare tree structure - const dKey = Buffer.from('dKey'); - const daValue = Buffer.from('da'); - const dbValue = Buffer.from('db'); - const dcValue = Buffer.from('dc'); - const eaValue = Buffer.from('ea'); - const eaKey = Buffer.from('eaKey'); - const ebValue = Buffer.from('eb'); - - const dPath = [...itemTreePath]; - - dPath.push(dKey); - - await groveDb.insert( - itemTreePath, - dKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - dPath, - Buffer.from('daKey'), - { type: 'item', epoch: 0, value: daValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dbKey'), - { type: 'item', epoch: 0, value: dbValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dcKey'), - { type: 'item', epoch: 0, value: dcValue }, - ); - - const eKey = Buffer.from('eKey'); - - const ePath = [...itemTreePath]; - ePath.push(eKey); - await groveDb.insert( - itemTreePath, - eKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - ePath, - Buffer.from('eaKey'), - { type: 'item', epoch: 0, value: eaValue }, - ); - - await groveDb.insert( - ePath, - Buffer.from('ebKey'), - { type: 'item', epoch: 0, value: ebValue }, - ); - - // This should give us only last subtree and apply subquery to it - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeAfter', - after: dKey, - }, - ], - subquery: { - items: [ - { - type: 'rangeAfter', - after: eaKey, - }, - ], - }, - }, - }, - }; - - const result = await groveDb.query(query); - - expect(result).to.have.a.lengthOf(2); - - const [elementValues, skipped] = result; - - expect(elementValues).to.deep.equals([ - ebValue, - ]); - - expect(skipped).to.equals(0); - }); - }); - - describe('#proveQuery', () => { - let dPath; - let dKey; - let ePath; - - let daValue; - let dbValue; - let dcValue; - let eaValue; - let eaKey; - let ebValue; - - beforeEach(async () => { - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - dKey = Buffer.from('dKey'); - daValue = Buffer.from('da'); - dbValue = Buffer.from('db'); - dcValue = Buffer.from('dc'); - eaValue = Buffer.from('ea'); - eaKey = Buffer.from('eaKey'); - ebValue = Buffer.from('eb'); - - dPath = [...itemTreePath]; - dPath.push(dKey); - await groveDb.insert( - itemTreePath, - dKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - dPath, - Buffer.from('daKey'), - { type: 'item', epoch: 0, value: daValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dbKey'), - { type: 'item', epoch: 0, value: dbValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dcKey'), - { type: 'item', epoch: 0, value: dcValue }, - ); - - const eKey = Buffer.from('eKey'); - ePath = [...itemTreePath]; - ePath.push(eKey); - await groveDb.insert( - itemTreePath, - eKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - ePath, - Buffer.from('eaKey'), - { type: 'item', epoch: 0, value: eaValue }, - ); - - await groveDb.insert( - ePath, - Buffer.from('ebKey'), - { type: 'item', epoch: 0, value: ebValue }, - ); - }); - - it('should be able to retrieve provable data with subquery', async () => { - // This should give us only last subtree and apply subquery to it - const query = { - path: itemTreePath, - query: { - query: { - items: [ - { - type: 'rangeAfter', - after: dKey, - }, - ], - subquery: { - items: [ - { - type: 'rangeAfter', - after: eaKey, - }, - ], - }, - }, - }, - }; - - const result = await groveDb.proveQuery(query); - - expect(result).to.exist(); - - expect(result).to.be.instanceOf(Buffer); - expect(result).to.have.lengthOf(213); - }); - }); - - describe('#proveQueryMany', () => { - let dPath; - let dKey; - let ePath; - - let daValue; - let dbValue; - let dcValue; - let eaValue; - let eaKey; - let ebValue; - - beforeEach(async () => { - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - dKey = Buffer.from('dKey'); - daValue = Buffer.from('da'); - dbValue = Buffer.from('db'); - dcValue = Buffer.from('dc'); - eaValue = Buffer.from('ea'); - eaKey = Buffer.from('eaKey'); - ebValue = Buffer.from('eb'); - - dPath = [...itemTreePath]; - dPath.push(dKey); - await groveDb.insert( - itemTreePath, - dKey, - { type: 'tree', epoch: 0 }, - ); - - await groveDb.insert( - dPath, - Buffer.from('daKey'), - { type: 'item', epoch: 0, value: daValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dbKey'), - { type: 'item', epoch: 0, value: dbValue }, - ); - - await groveDb.insert( - dPath, - Buffer.from('dcKey'), - { type: 'item', epoch: 0, value: dcValue }, - ); - - const eKey = Buffer.from('eKey'); - ePath = [...itemTreePath]; - ePath.push(eKey); - await groveDb.insert( - itemTreePath, - eKey, - { type: 'tree' }, - ); - - await groveDb.insert( - ePath, - Buffer.from('eaKey'), - { type: 'item', epoch: 0, value: eaValue }, - ); - - const ownerId = Buffer.alloc(32).fill('c'); - - await groveDb.insert( - ePath, - Buffer.from('ebKey'), - { - type: 'item', - epoch: 0, - ownerId, - value: ebValue, - }, - ); - }); - - it('should be able to prove query', async () => { - const query1 = { - path: ePath, - query: { - query: { - items: [ - { - type: 'key', - key: dKey, - }, - ], - }, - }, - }; - - const query2 = { - path: dPath, - query: { - query: { - items: [ - { - type: 'key', - key: eaKey, - }, - ], - }, - }, - }; - - const result = await groveDb.proveQueryMany([query1, query2]); - - expect(result).to.exist(); - - expect(result).to.be.instanceOf(Buffer); - expect(result).to.have.lengthOf(348); - }); - }); - - describe('#flush', () => { - it('should flush data on disc', async () => { - await groveDb.insert( - [], - Buffer.from('test_tree'), - { type: 'tree', epoch: 0 }, - ); - - await groveDb.flush(); - }); - }); - - describe('#getRootHash', () => { - it('should return empty root hash if there is no data', async () => { - const result = await groveDb.getRootHash(); - - expect(result).to.deep.equal(Buffer.alloc(32)); - - // Get root hash for transaction too - await groveDb.startTransaction(); - - const transactionalResult = await groveDb.getRootHash(true); - - expect(transactionalResult).to.deep.equal(Buffer.alloc(32)); - }); - - it('should root hash', async () => { - // Making a subtree to insert items into - await groveDb.insert( - rootTreePath, - treeKey, - { type: 'tree', epoch: 0 }, - ); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - itemKey, - { type: 'item', epoch: 0, value: itemValue }, - ); - - await groveDb.startTransaction(); - - // Inserting an item into the subtree - await groveDb.insert( - itemTreePath, - Buffer.from('transactional_test_key'), - { type: 'item', epoch: 0, value: itemValue }, - true, - ); - - const result = await groveDb.getRootHash(); - const transactionalResult = await groveDb.getRootHash(true); - - // Hashes shouldn't be equal - expect(result).to.not.deep.equal(transactionalResult); - - // Hashes shouldn't be empty - - // eslint-disable-next-line no-unused-expressions - expect(result >= Buffer.alloc(32)).to.be.true; - - // eslint-disable-next-line no-unused-expressions - expect(transactionalResult >= Buffer.alloc(32)).to.be.true; - }); - }); -}); diff --git a/packages/rs-drive-nodejs/test/utils.js b/packages/rs-drive-nodejs/test/utils.js deleted file mode 100644 index c5e0fd37539..00000000000 --- a/packages/rs-drive-nodejs/test/utils.js +++ /dev/null @@ -1,16 +0,0 @@ -const { expect } = require('chai'); -const FeeResult = require('../FeeResult'); - -/** - * @param {FeeResult} feeResult - */ -function expectFeeResult(feeResult) { - expect(feeResult).to.be.an.instanceOf(FeeResult); - - expect(feeResult.processingFee).to.be.greaterThan(0, 'processing fee must be higher than 0'); - expect(feeResult.storageFee).to.be.greaterThan(0, 'storage fee must be higher than 0'); -} - -module.exports = { - expectFeeResult, -}; diff --git a/yarn.lock b/yarn.lock index 8a95a3b3940..5a245765a17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1281,17 +1281,6 @@ __metadata: languageName: node linkType: hard -"@dashevo/abci@github:dashpay/js-abci#09f72120bc2059144f72eb7a246d632ead3fc3c6": - version: 0.24.0-dev.1 - resolution: "@dashevo/abci@https://github.com/dashpay/js-abci.git#commit=09f72120bc2059144f72eb7a246d632ead3fc3c6" - dependencies: - "@dashevo/protobufjs": 6.10.5 - bl: ^1.2.3 - protocol-buffers-encodings: ^1.1.0 - checksum: aaf41ab7fada6504606daf6ef238f2240bac4307ecde77bd77b8c10aecfd0b73fb8cfb40b2ad91a5bc6440572c93580da51013e188bb85dc46c4120b7c8c2236 - languageName: node - linkType: hard - "@dashevo/bench-suite@workspace:packages/bench-suite": version: 0.0.0-use.local resolution: "@dashevo/bench-suite@workspace:packages/bench-suite" @@ -1631,63 +1620,6 @@ __metadata: languageName: unknown linkType: soft -"@dashevo/drive@workspace:packages/js-drive": - version: 0.0.0-use.local - resolution: "@dashevo/drive@workspace:packages/js-drive" - dependencies: - "@dashevo/abci": "github:dashpay/js-abci#09f72120bc2059144f72eb7a246d632ead3fc3c6" - "@dashevo/dapi-grpc": "workspace:*" - "@dashevo/dashcore-lib": ~0.20.0 - "@dashevo/dashd-rpc": ^18.2.0 - "@dashevo/dashpay-contract": "workspace:*" - "@dashevo/dp-services-ctl": "github:dashevo/js-dp-services-ctl#v0.19-dev" - "@dashevo/dpns-contract": "workspace:*" - "@dashevo/dpp": "workspace:*" - "@dashevo/feature-flags-contract": "workspace:*" - "@dashevo/grpc-common": "workspace:*" - "@dashevo/masternode-reward-shares-contract": "workspace:*" - "@dashevo/rs-drive": "workspace:*" - "@dashevo/withdrawals-contract": "workspace:*" - "@types/pino": ^6.3.0 - ajv: ^8.6.0 - ajv-keywords: ^5.0.0 - awilix: ^4.2.6 - babel-eslint: ^10.1.0 - blake3: ^2.1.4 - bs58: ^4.0.1 - cbor: ^8.0.0 - chai: ^4.3.4 - chai-as-promised: ^7.1.1 - chai-string: ^1.5.0 - chalk: ^4.1.0 - dirty-chai: ^2.0.1 - dotenv-expand: ^5.1.0 - dotenv-safe: ^8.2.0 - eslint: ^7.32.0 - eslint-config-airbnb-base: ^14.2.1 - eslint-plugin-import: ^2.24.2 - find-my-way: ^2.2.2 - js-merkle: ^0.1.5 - levelup: ^4.4.0 - lodash: ^4.17.21 - long: ^5.2.0 - memdown: ^5.1.0 - mocha: ^9.1.2 - moment: ^2.29.4 - node-graceful: ^3.0.1 - nyc: ^15.1.0 - pino: ^6.4.0 - pino-multi-stream: ^5.2.0 - pino-pretty: ^4.0.3 - rimraf: ^3.0.2 - setimmediate: ^1.0.5 - sinon: ^11.1.2 - sinon-chai: ^3.7.0 - through2: ^3.0.1 - zeromq: ^5.2.8 - languageName: unknown - linkType: soft - "@dashevo/feature-flags-contract@workspace:*, @dashevo/feature-flags-contract@workspace:packages/feature-flags-contract": version: 0.0.0-use.local resolution: "@dashevo/feature-flags-contract@workspace:packages/feature-flags-contract" @@ -1873,28 +1805,6 @@ __metadata: languageName: node linkType: hard -"@dashevo/rs-drive@workspace:*, @dashevo/rs-drive@workspace:packages/rs-drive-nodejs": - version: 0.0.0-use.local - resolution: "@dashevo/rs-drive@workspace:packages/rs-drive-nodejs" - dependencies: - "@dashevo/dashcore-lib": ~0.20.0 - "@dashevo/dpp": "workspace:*" - "@dashevo/withdrawals-contract": "workspace:*" - cargo-cp-artifact: ^0.1.6 - cbor: ^8.0.0 - chai: ^4.3.4 - dirty-chai: ^2.0.1 - eslint: ^7.32.0 - eslint-config-airbnb-base: ^14.2.1 - eslint-plugin-import: ^2.24.2 - mocha: ^9.1.2 - neon-cli: ^0.10.1 - neon-load-or-build: ^2.2.2 - neon-tag-prebuild: "github:shumkov/neon-tag-prebuild#patch-1" - ultra-runner: ^3.10.5 - languageName: unknown - linkType: soft - "@dashevo/wallet-lib@workspace:*, @dashevo/wallet-lib@workspace:packages/wallet-lib": version: 0.0.0-use.local resolution: "@dashevo/wallet-lib@workspace:packages/wallet-lib" @@ -2119,13 +2029,6 @@ __metadata: languageName: node linkType: hard -"@hapi/bourne@npm:^2.0.0": - version: 2.0.0 - resolution: "@hapi/bourne@npm:2.0.0" - checksum: 2ea0922101d3fecec43428194c72c5dbe0be908dd7ad07347879dc720820ac410ead79a4c349a2e1726e8af062464160c6d32b6566bbc4c60865923f9d7dd006 - languageName: node - linkType: hard - "@humanwhocodes/config-array@npm:^0.5.0": version: 0.5.0 resolution: "@humanwhocodes/config-array@npm:0.5.0" @@ -3136,37 +3039,6 @@ __metadata: languageName: node linkType: hard -"@types/pino-pretty@npm:*": - version: 4.7.3 - resolution: "@types/pino-pretty@npm:4.7.3" - dependencies: - "@types/node": "*" - "@types/pino": 6.3 - checksum: 40fe67e73d26242d1f741ba62bd57aa4ce34842376878137f16befde3df0dd5ee39c30bc89da3d5e99848f69b00b73010863a740fd469585e0852ea656cb5b7b - languageName: node - linkType: hard - -"@types/pino-std-serializers@npm:*": - version: 2.4.1 - resolution: "@types/pino-std-serializers@npm:2.4.1" - dependencies: - "@types/node": "*" - checksum: a156e25882db9aade2576dbe6414379efcdd4fad24211d3f22f20e0cd4bee569215799ee5cd9b2b15282f18461a8a54573ff42bf6bee5d35b72513be2f78bdec - languageName: node - linkType: hard - -"@types/pino@npm:6.3, @types/pino@npm:^6.3.0": - version: 6.3.12 - resolution: "@types/pino@npm:6.3.12" - dependencies: - "@types/node": "*" - "@types/pino-pretty": "*" - "@types/pino-std-serializers": "*" - sonic-boom: ^2.1.0 - checksum: 801735146669312d02459781e5180220630eaef643da36dc5a9a97520e7ecc3da7270f31a86fcdcb1dc835073c9143fc628024ba5e3a0ea7cbb86aada4897709 - languageName: node - linkType: hard - "@types/qs@npm:*": version: 6.9.7 resolution: "@types/qs@npm:6.9.7" @@ -3745,17 +3617,6 @@ __metadata: languageName: node linkType: hard -"ajv-keywords@npm:^5.0.0": - version: 5.0.0 - resolution: "ajv-keywords@npm:5.0.0" - dependencies: - fast-deep-equal: ^3.1.3 - peerDependencies: - ajv: ^8.0.0 - checksum: 239dd46383a861f9e1dda1f463542ddfa07b4aed886eccb2a4328672c886030b5fdbb7869e0e293ba5549c9b86b23b40fa0e3c0785047e081302f00e41b1e4c1 - languageName: node - linkType: hard - "ajv@npm:^6.10.0, ajv@npm:^6.10.2, ajv@npm:^6.12.4, ajv@npm:^6.12.5": version: 6.12.6 resolution: "ajv@npm:6.12.6" @@ -3986,32 +3847,6 @@ __metadata: languageName: node linkType: hard -"args@npm:^5.0.1": - version: 5.0.1 - resolution: "args@npm:5.0.1" - dependencies: - camelcase: 5.0.0 - chalk: 2.4.2 - leven: 2.1.0 - mri: 1.1.4 - checksum: 51e2a05f32d15b8e292f000e6b232118df61b8f4fd446b17bb4e99df9ab47fe2c4a01924d7f967a6f08e82f9c19be277b08ed22bceff058aca849144ef8efed3 - languageName: node - linkType: hard - -"array-back@npm:^3.0.1, array-back@npm:^3.1.0": - version: 3.1.0 - resolution: "array-back@npm:3.1.0" - checksum: 7205004fcd0f9edd926db921af901b083094608d5b265738d0290092f9822f73accb468e677db74c7c94ef432d39e5ed75a7b1786701e182efb25bbba9734209 - languageName: node - linkType: hard - -"array-back@npm:^4.0.1, array-back@npm:^4.0.2": - version: 4.0.2 - resolution: "array-back@npm:4.0.2" - checksum: f30603270771eeb54e5aad5f54604c62b3577a18b6db212a7272b2b6c32049121b49431f656654790ed1469411e45f387e7627c0de8fd0515995cc40df9b9294 - languageName: node - linkType: hard - "array-buffer-byte-length@npm:^1.0.0": version: 1.0.0 resolution: "array-buffer-byte-length@npm:1.0.0" @@ -4175,13 +4010,6 @@ __metadata: languageName: node linkType: hard -"atomic-sleep@npm:^1.0.0": - version: 1.0.0 - resolution: "atomic-sleep@npm:1.0.0" - checksum: b95275afb2f80732f22f43a60178430c468906a415a7ff18bcd0feeebc8eec3930b51250aeda91a476062a90e07132b43a1794e8d8ffcf9b650e8139be75fa36 - languageName: node - linkType: hard - "available-typed-arrays@npm:^1.0.5": version: 1.0.5 resolution: "available-typed-arrays@npm:1.0.5" @@ -4418,16 +4246,6 @@ __metadata: languageName: node linkType: hard -"bl@npm:^1.2.3": - version: 1.2.3 - resolution: "bl@npm:1.2.3" - dependencies: - readable-stream: ^2.3.5 - safe-buffer: ^5.1.1 - checksum: 123f097989ce2fa9087ce761cd41176aaaec864e28f7dfe5c7dab8ae16d66d9844f849c3ad688eb357e3c5e4f49b573e3c0780bb8bc937206735a3b6f8569a5f - languageName: node - linkType: hard - "bl@npm:^2.2.1": version: 2.2.1 resolution: "bl@npm:2.2.1" @@ -4851,13 +4669,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:5.0.0": - version: 5.0.0 - resolution: "camelcase@npm:5.0.0" - checksum: 8bfe920e0472d79d34f0279da1391f155bcce7fc74c99b49dafae4f787396040a34f4023da837ab0b4372e63224b460f9524b495906863c38876faea9da53705 - languageName: node - linkType: hard - "camelcase@npm:^5.0.0, camelcase@npm:^5.3.1": version: 5.3.1 resolution: "camelcase@npm:5.3.1" @@ -4891,15 +4702,6 @@ __metadata: languageName: node linkType: hard -"cargo-cp-artifact@npm:^0.1.6": - version: 0.1.6 - resolution: "cargo-cp-artifact@npm:0.1.6" - bin: - cargo-cp-artifact: bin/cargo-cp-artifact.js - checksum: 2f5d2f3e73372c9d398746372e8d1f7b171f27c8d4e4e9f7de898ead93b29631d62ea26c1ae352fa2c1542e124c2c77ac8a60acc5634bb433133ee2c7c6f1e09 - languageName: node - linkType: hard - "cbor@npm:^8.0.0": version: 8.1.0 resolution: "cbor@npm:8.1.0" @@ -4954,17 +4756,6 @@ __metadata: languageName: node linkType: hard -"chalk@npm:2.4.2, chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.1.0, chalk@npm:^2.4.2": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: ^3.2.1 - escape-string-regexp: ^1.0.5 - supports-color: ^5.3.0 - checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 - languageName: node - linkType: hard - "chalk@npm:^1.0.0": version: 1.1.3 resolution: "chalk@npm:1.1.3" @@ -4978,6 +4769,17 @@ __metadata: languageName: node linkType: hard +"chalk@npm:^2.0.0, chalk@npm:^2.0.1, chalk@npm:^2.1.0, chalk@npm:^2.4.2": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" + dependencies: + ansi-styles: ^3.2.1 + escape-string-regexp: ^1.0.5 + supports-color: ^5.3.0 + checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 + languageName: node + linkType: hard + "chalk@npm:^3.0.0": version: 3.0.0 resolution: "chalk@npm:3.0.0" @@ -5350,39 +5152,6 @@ __metadata: languageName: node linkType: hard -"command-line-args@npm:^5.1.1": - version: 5.2.1 - resolution: "command-line-args@npm:5.2.1" - dependencies: - array-back: ^3.1.0 - find-replace: ^3.0.0 - lodash.camelcase: ^4.3.0 - typical: ^4.0.0 - checksum: e759519087be3cf2e86af8b9a97d3058b4910cd11ee852495be881a067b72891f6a32718fb685ee6d41531ab76b2b7bfb6602f79f882cd4b7587ff1e827982c7 - languageName: node - linkType: hard - -"command-line-commands@npm:^3.0.1": - version: 3.0.2 - resolution: "command-line-commands@npm:3.0.2" - dependencies: - array-back: ^4.0.1 - checksum: 2cf5409af0910b9ea3c405814d68ef6134d22849b7f41c32153b807e9f52c67c486472ab042ca96f80cf2e5ab19db830a52ef2070ae189513e6188b6692db903 - languageName: node - linkType: hard - -"command-line-usage@npm:^6.1.0": - version: 6.1.3 - resolution: "command-line-usage@npm:6.1.3" - dependencies: - array-back: ^4.0.2 - chalk: ^2.4.2 - table-layout: ^1.0.2 - typical: ^5.2.0 - checksum: 8261d4e5536eb0bcddee0ec5e89c05bb2abd18e5760785c8078ede5020bc1c612cbe28eb6586f5ed4a3660689748e5aaad4a72f21566f4ef39393694e2fa1a0b - languageName: node - linkType: hard - "commander@npm:4.0.1": version: 4.0.1 resolution: "commander@npm:4.0.1" @@ -6037,7 +5806,7 @@ __metadata: languageName: node linkType: hard -"dateformat@npm:^4.5.0, dateformat@npm:^4.5.1": +"dateformat@npm:^4.5.0": version: 4.6.3 resolution: "dateformat@npm:4.6.3" checksum: c3aa0617c0a5b30595122bc8d1bee6276a9221e4d392087b41cbbdf175d9662ae0e50d0d6dcdf45caeac5153c4b5b0844265f8cd2b2245451e3da19e39e3b65d @@ -6151,7 +5920,7 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:^0.6.0, deep-extend@npm:~0.6.0": +"deep-extend@npm:^0.6.0": version: 0.6.0 resolution: "deep-extend@npm:0.6.0" checksum: 7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 @@ -7214,13 +6983,6 @@ __metadata: languageName: node linkType: hard -"fast-decode-uri-component@npm:^1.0.0": - version: 1.0.1 - resolution: "fast-decode-uri-component@npm:1.0.1" - checksum: 427a48fe0907e76f0e9a2c228e253b4d8a8ab21d130ee9e4bb8339c5ba4086235cf9576831f7b20955a752eae4b525a177ff9d5825dd8d416e7726939194fbee - languageName: node - linkType: hard - "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" @@ -7271,20 +7033,6 @@ __metadata: languageName: node linkType: hard -"fast-redact@npm:^3.0.0": - version: 3.0.2 - resolution: "fast-redact@npm:3.0.2" - checksum: f4ffdf48f1647dbe0411884e5dca85ebef0762d1ce1937f6779beaea5c83ef7c35416d800b2bff60f1a252b670d1707f9484c9a5d0ef721e68f3dae94b420fa8 - languageName: node - linkType: hard - -"fast-safe-stringify@npm:^2.0.7, fast-safe-stringify@npm:^2.0.8": - version: 2.1.1 - resolution: "fast-safe-stringify@npm:2.1.1" - checksum: a851cbddc451745662f8f00ddb622d6766f9bd97642dabfd9a405fb0d646d69fc0b9a1243cbf67f5f18a39f40f6fa821737651ff1bceeba06c9992ca2dc5bd3d - languageName: node - linkType: hard - "fastest-levenshtein@npm:^1.0.12, fastest-levenshtein@npm:^1.0.7": version: 1.0.12 resolution: "fastest-levenshtein@npm:1.0.12" @@ -7292,13 +7040,6 @@ __metadata: languageName: node linkType: hard -"fastify-warning@npm:^0.2.0": - version: 0.2.0 - resolution: "fastify-warning@npm:0.2.0" - checksum: c19ebccf54a3122877d2248400772ca98bacbabdf97826211ede29246c640d47431a2eebed1f52f9421139ed5e52e42d3bd4aefc46e27b6f34add3507529fd97 - languageName: node - linkType: hard - "fastq@npm:^1.6.0": version: 1.13.0 resolution: "fastq@npm:1.13.0" @@ -7384,26 +7125,6 @@ __metadata: languageName: node linkType: hard -"find-my-way@npm:^2.2.2": - version: 2.2.5 - resolution: "find-my-way@npm:2.2.5" - dependencies: - fast-decode-uri-component: ^1.0.0 - safe-regex2: ^2.0.0 - semver-store: ^0.3.0 - checksum: 93303495659720c55c92e6cd7c430861c722865ac93454eac8b014954db82cfbcbac20826e74d871cef8883d484b2b8dc15a435b8964696bcdffe76afce5ade1 - languageName: node - linkType: hard - -"find-replace@npm:^3.0.0": - version: 3.0.0 - resolution: "find-replace@npm:3.0.0" - dependencies: - array-back: ^3.0.1 - checksum: 6b04bcfd79027f5b84aa1dfe100e3295da989bdac4b4de6b277f4d063e78f5c9e92ebc8a1fec6dd3b448c924ba404ee051cc759e14a3ee3e825fa1361025df08 - languageName: node - linkType: hard - "find-up@npm:5.0.0, find-up@npm:^5.0.0": version: 5.0.0 resolution: "find-up@npm:5.0.0" @@ -7480,13 +7201,6 @@ __metadata: languageName: node linkType: hard -"flatstr@npm:^1.0.12": - version: 1.0.12 - resolution: "flatstr@npm:1.0.12" - checksum: e1bb562c94b119e958bf37e55738b172b5f8aaae6532b9660ecd877779f8559dbbc89613ba6b29ccc13447e14c59277d41450f785cf75c30df9fce62f459e9a8 - languageName: node - linkType: hard - "flatted@npm:^3.1.0, flatted@npm:^3.2.6": version: 3.2.7 resolution: "flatted@npm:3.2.7" @@ -7794,15 +7508,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"git-config@npm:0.0.7": - version: 0.0.7 - resolution: "git-config@npm:0.0.7" - dependencies: - iniparser: ~1.0.5 - checksum: 99a7e203061fa2bf5a1ca9a888c0b86b2f1d8d104f57ae82cdaf61cf344dc4b67a85250572686d76c70ba0a8e83a7ca4993d2a9efe0a42ea03b5b65ebcaef97d - languageName: node - linkType: hard - "git-raw-commits@npm:^2.0.8": version: 2.0.10 resolution: "git-raw-commits@npm:2.0.10" @@ -8523,34 +8228,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"iniparser@npm:~1.0.5": - version: 1.0.5 - resolution: "iniparser@npm:1.0.5" - checksum: eba0ec2d6856dd1d1cc6c6234c683aee67d923c054c851e3d583f2436bd4fc14b29f9d39f3f94bac9cfa211d8310558c557e1e983fddc82e07ad6a6524cabc2a - languageName: node - linkType: hard - -"inquirer@npm:^7.3.3": - version: 7.3.3 - resolution: "inquirer@npm:7.3.3" - dependencies: - ansi-escapes: ^4.2.1 - chalk: ^4.1.0 - cli-cursor: ^3.1.0 - cli-width: ^3.0.0 - external-editor: ^3.0.3 - figures: ^3.0.0 - lodash: ^4.17.19 - mute-stream: 0.0.8 - run-async: ^2.4.0 - rxjs: ^6.6.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - through: ^2.3.6 - checksum: 4d387fc1eb6126acbd58cbdb9ad99d2887d181df86ab0c2b9abdf734e751093e2d5882c2b6dc7144d9ab16b7ab30a78a1d7f01fb6a2850a44aeb175d1e3f8778 - languageName: node - linkType: hard - "inquirer@npm:^8.0.0": version: 8.2.0 resolution: "inquirer@npm:8.2.0" @@ -9234,20 +8911,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"jmespath@npm:^0.15.0": - version: 0.15.0 - resolution: "jmespath@npm:0.15.0" - checksum: 353bb9e69cc4c1560be0a4df43cb4020abc246e1c60cb5b55dcc76d8c858383f1633faf22ccaf6a5e09568a2077d0f4f1e989e6fcfd496b5cef87964cc8cb9e7 - languageName: node - linkType: hard - -"joycon@npm:^2.2.5": - version: 2.2.5 - resolution: "joycon@npm:2.2.5" - checksum: 930bb748c0ade3b70cca756aa559916a3e0df36b06b0ace629d9c4a6081d235d3d7a93eb7d3094d53ab7a3658bcd5c6a54e4ed235e5f5c03a177597a669081eb - languageName: node - linkType: hard - "js-base64@npm:^2.1.9": version: 2.6.4 resolution: "js-base64@npm:2.6.4" @@ -9689,13 +9352,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"leven@npm:2.1.0": - version: 2.1.0 - resolution: "leven@npm:2.1.0" - checksum: f7b4a01b15c0ee2f92a04c0367ea025d10992b044df6f0d4ee1a845d4a488b343e99799e2f31212d72a2b1dea67124f57c1bb1b4561540df45190e44b5b8b394 - languageName: node - linkType: hard - "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -10110,13 +9766,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"make-promises-safe@npm:^5.1.0": - version: 5.1.0 - resolution: "make-promises-safe@npm:5.1.0" - checksum: 6e59ed8c568b422e4d707d171bf7d9a05ef483bad09749ddbab79e059498572b01e3f58baae7ce49d1e748e693823eb633d3875ae86fa5131242683e71ba73fe - languageName: node - linkType: hard - "map-obj@npm:^1.0.0": version: 1.0.1 resolution: "map-obj@npm:1.0.1" @@ -10587,13 +10236,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"moment@npm:^2.29.4": - version: 2.29.4 - resolution: "moment@npm:2.29.4" - checksum: 0ec3f9c2bcba38dc2451b1daed5daded747f17610b92427bebe1d08d48d8b7bdd8d9197500b072d14e326dd0ccf3e326b9e3d07c5895d3d49e39b6803b76e80e - languageName: node - linkType: hard - "mongodb@npm:^3.3.4": version: 3.7.3 resolution: "mongodb@npm:3.7.3" @@ -10624,13 +10266,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"mri@npm:1.1.4": - version: 1.1.4 - resolution: "mri@npm:1.1.4" - checksum: e65b9aed3b9e423ad4c11f529ab1b9280f65dce8fb476d0da236b5c570ad3322fbbcd2393180855f1474f8b0f982d76ad398766fbd47b8a5ab4069e325d0268e - languageName: node - linkType: hard - "ms@npm:2.0.0": version: 2.0.0 resolution: "ms@npm:2.0.0" @@ -10741,53 +10376,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"neon-cli@npm:^0.10.1": - version: 0.10.1 - resolution: "neon-cli@npm:0.10.1" - dependencies: - chalk: ^4.1.0 - command-line-args: ^5.1.1 - command-line-commands: ^3.0.1 - command-line-usage: ^6.1.0 - git-config: 0.0.7 - handlebars: ^4.7.6 - inquirer: ^7.3.3 - make-promises-safe: ^5.1.0 - rimraf: ^3.0.2 - semver: ^7.3.2 - toml: ^3.0.0 - ts-typed-json: ^0.3.2 - validate-npm-package-license: ^3.0.4 - validate-npm-package-name: ^3.0.0 - bin: - neon: bin/cli.js - checksum: 284e7ec9e3d7e643abc3f521e0969ee73e22297b6f7102e9526770b1c9f5a73c650ceef12497eb51ed9818ac2d3f53448ad8ef77a88108dae70a7bae2e131402 - languageName: node - linkType: hard - -"neon-load-or-build@npm:^2.2.2": - version: 2.2.2 - resolution: "neon-load-or-build@npm:2.2.2" - bin: - neon-load-or-build: ./bin.js - neon-load-or-build-optional: ./optional.js - neon-load-or-build-test: ./build-test.js - checksum: 3cafba0e26ad2d343c9c0bcbaaeef34fd646941da401a02bb7307a99095774c4bbbe4d2e168641e50f7228cb933ac9c5e68db390ec7e52dc9d01be99b5a90258 - languageName: node - linkType: hard - -"neon-tag-prebuild@github:shumkov/neon-tag-prebuild#patch-1": - version: 1.1.0 - resolution: "neon-tag-prebuild@https://github.com/shumkov/neon-tag-prebuild.git#commit=a429834da27432b129eceb737e4d2b3f03fa5496" - dependencies: - mkdirp: ^1.0.4 - node-abi: ^2.19.1 - bin: - neon-tag-prebuild: ./bin.js - checksum: 00a16bf27c06e0fa021be8019942490b4dc4f9cfd09b13eda042fdbc1f3873b7d74438f3b0d327651f77b93d087dd6ca5b9497bfc73457d12870f15cff0f0066 - languageName: node - linkType: hard - "net@npm:^1.0.2": version: 1.0.2 resolution: "net@npm:1.0.2" @@ -10825,15 +10413,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"node-abi@npm:^2.19.1": - version: 2.30.1 - resolution: "node-abi@npm:2.30.1" - dependencies: - semver: ^5.4.1 - checksum: 3f4b0c912ce4befcd7ceab4493ba90b51d60dfcc90f567c93f731d897ef8691add601cb64c181683b800f21d479d68f9a6e15d8ab8acd16a5706333b9e30a881 - languageName: node - linkType: hard - "node-fetch@npm:^2.6.7": version: 2.6.7 resolution: "node-fetch@npm:2.6.7" @@ -11821,61 +11400,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"pino-multi-stream@npm:^5.2.0": - version: 5.3.0 - resolution: "pino-multi-stream@npm:5.3.0" - dependencies: - pino: ^6.0.0 - checksum: 10ddb859836a1d8e4894a408c4bc0c00ca67fe81c2c1aa8ff1534720a5e1ad0261a976239408ec5cdfa5fd7f0444c83d6caa00189efe5cf95b230ed9a32ee6d5 - languageName: node - linkType: hard - -"pino-pretty@npm:^4.0.3": - version: 4.8.0 - resolution: "pino-pretty@npm:4.8.0" - dependencies: - "@hapi/bourne": ^2.0.0 - args: ^5.0.1 - chalk: ^4.0.0 - dateformat: ^4.5.1 - fast-safe-stringify: ^2.0.7 - jmespath: ^0.15.0 - joycon: ^2.2.5 - pump: ^3.0.0 - readable-stream: ^3.6.0 - rfdc: ^1.3.0 - split2: ^3.1.1 - strip-json-comments: ^3.1.1 - bin: - pino-pretty: bin.js - checksum: 8e2e4cdb80c7f8b4df318f30415c98a09f952174a7dd9b0910041f995b8476fc177568e950ea3ce5967303c46356df37d13f822cff99c848e4177c957d3b1dad - languageName: node - linkType: hard - -"pino-std-serializers@npm:^3.1.0": - version: 3.2.0 - resolution: "pino-std-serializers@npm:3.2.0" - checksum: 77e29675b116e42ae9fe6d4ef52ef3a082ffc54922b122d85935f93ddcc20277f0b0c873c5c6c5274a67b0409c672aaae3de6bcea10a2d84699718dda55ba95b - languageName: node - linkType: hard - -"pino@npm:^6.0.0, pino@npm:^6.4.0": - version: 6.13.3 - resolution: "pino@npm:6.13.3" - dependencies: - fast-redact: ^3.0.0 - fast-safe-stringify: ^2.0.8 - fastify-warning: ^0.2.0 - flatstr: ^1.0.12 - pino-std-serializers: ^3.1.0 - quick-format-unescaped: ^4.0.3 - sonic-boom: ^1.0.2 - bin: - pino: bin.js - checksum: a580decd47a1c8b32a846ba1cb478087b523636d697bd4c57833d10b3f2b35c7d06739715ad9a291b41caf002b8d1bbf98674bfb3e99989fd41b7d934cca861c - languageName: node - linkType: hard - "pkg-dir@npm:^2.0.0": version: 2.0.0 resolution: "pkg-dir@npm:2.0.0" @@ -12058,16 +11582,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"protocol-buffers-encodings@npm:^1.1.0": - version: 1.1.1 - resolution: "protocol-buffers-encodings@npm:1.1.1" - dependencies: - signed-varint: ^2.0.1 - varint: 5.0.0 - checksum: 1b22d6d05bbd6249cbfe9a792003945a3a4cb49c2d0e19a4b10ea2a9b543d610fcf244108133f7a5df83479a8e8cded51a33845477c1490361bfbe66a49c64ae - languageName: node - linkType: hard - "prr@npm:~1.0.1": version: 1.0.1 resolution: "prr@npm:1.0.1" @@ -12175,13 +11689,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"quick-format-unescaped@npm:^4.0.3": - version: 4.0.4 - resolution: "quick-format-unescaped@npm:4.0.4" - checksum: 7bc32b99354a1aa46c089d2a82b63489961002bb1d654cee3e6d2d8778197b68c2d854fd23d8422436ee1fdfd0abaddc4d4da120afe700ade68bd357815b26fd - languageName: node - linkType: hard - "quick-lru@npm:^4.0.1": version: 4.0.1 resolution: "quick-lru@npm:4.0.1" @@ -12302,7 +11809,7 @@ fsevents@~2.3.2: languageName: node linkType: hard -"readable-stream@npm:2 || 3, readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": +"readable-stream@npm:3, readable-stream@npm:^3.0.0, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": version: 3.6.0 resolution: "readable-stream@npm:3.6.0" dependencies: @@ -12398,13 +11905,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"reduce-flatten@npm:^2.0.0": - version: 2.0.0 - resolution: "reduce-flatten@npm:2.0.0" - checksum: 64393ef99a16b20692acfd60982d7fdbd7ff8d9f8f185c6023466444c6dd2abb929d67717a83cec7f7f8fb5f46a25d515b3b2bf2238fdbfcdbfd01d2a9e73cb8 - languageName: node - linkType: hard - "regenerate-unicode-properties@npm:^9.0.0": version: 9.0.0 resolution: "regenerate-unicode-properties@npm:9.0.0" @@ -12643,13 +12143,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"ret@npm:~0.2.0": - version: 0.2.2 - resolution: "ret@npm:0.2.2" - checksum: 774964bb413a3525e687bca92d81c1cd75555ec33147c32ecca22f3d06409e35df87952cfe3d57afff7650a0f7e42139cf60cb44e94c29dde390243bc1941f16 - languageName: node - linkType: hard - "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -12719,7 +12212,7 @@ fsevents@~2.3.2: languageName: node linkType: hard -"rxjs@npm:^6.6.0, rxjs@npm:^6.6.7": +"rxjs@npm:^6.6.7": version: 6.6.7 resolution: "rxjs@npm:6.6.7" dependencies: @@ -12762,15 +12255,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"safe-regex2@npm:^2.0.0": - version: 2.0.0 - resolution: "safe-regex2@npm:2.0.0" - dependencies: - ret: ~0.2.0 - checksum: f5e182fca040dedd50ae052ea0eb035d9903b2db71243d5d8b43299735857288ef2ab52546a368d9c6fd1333b2a0d039297925e78ffc14845354f3f6158af7c2 - languageName: node - linkType: hard - "safe-stable-stringify@npm:^1.1.0": version: 1.1.1 resolution: "safe-stable-stringify@npm:1.1.1" @@ -12844,14 +12328,7 @@ fsevents@~2.3.2: languageName: node linkType: hard -"semver-store@npm:^0.3.0": - version: 0.3.0 - resolution: "semver-store@npm:0.3.0" - checksum: b38f747123e850191526a912657c653c7e5963d164a8daf99e52aa30bc8c5bdac176dc6dab714e17a1a8489ac138c18ff7161b1961f1882888bce637990442dd - languageName: node - linkType: hard - -"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.7.1": +"semver@npm:2 || 3 || 4 || 5, semver@npm:^5.5.0, semver@npm:^5.7.1": version: 5.7.1 resolution: "semver@npm:5.7.1" bin: @@ -13073,15 +12550,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"signed-varint@npm:^2.0.1": - version: 2.0.1 - resolution: "signed-varint@npm:2.0.1" - dependencies: - varint: ~5.0.0 - checksum: a9fd2d954d62149d5dcbf7292c028d5665046763bd3e2b68f5603fca9248c808ca727f0b70e8e785d292c40f6a43b7406d56a37c7b06becd3c6ad0972c5d0e94 - languageName: node - linkType: hard - "simple-swizzle@npm:^0.2.2": version: 0.2.2 resolution: "simple-swizzle@npm:0.2.2" @@ -13241,25 +12709,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"sonic-boom@npm:^1.0.2": - version: 1.4.1 - resolution: "sonic-boom@npm:1.4.1" - dependencies: - atomic-sleep: ^1.0.0 - flatstr: ^1.0.12 - checksum: 189fa8fe5c2dc05d3513fc1a4926a2f16f132fa6fa0b511745a436010cdcd9c1d3b3cb6a9d7c05bd32a965dc77673a5ac0eb0992e920bdedd16330d95323124f - languageName: node - linkType: hard - -"sonic-boom@npm:^2.1.0": - version: 2.3.1 - resolution: "sonic-boom@npm:2.3.1" - dependencies: - atomic-sleep: ^1.0.0 - checksum: 4f5022de97483bb6f889415e342f9a451dbdebbe732df454f7d6e417cc80e813c19e2d646ad5ae20a92510a34c311fb9fbc440864bb234b78b3a2100467d851b - languageName: node - linkType: hard - "sort-keys@npm:^4.2.0": version: 4.2.0 resolution: "sort-keys@npm:4.2.0" @@ -13364,7 +12813,7 @@ fsevents@~2.3.2: languageName: node linkType: hard -"split2@npm:^3.0.0, split2@npm:^3.1.1": +"split2@npm:^3.0.0": version: 3.2.2 resolution: "split2@npm:3.2.2" dependencies: @@ -13781,18 +13230,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"table-layout@npm:^1.0.2": - version: 1.0.2 - resolution: "table-layout@npm:1.0.2" - dependencies: - array-back: ^4.0.1 - deep-extend: ~0.6.0 - typical: ^5.2.0 - wordwrapjs: ^4.0.0 - checksum: 8f41b5671f101a5195747ec1727b1d35ea2cd5bf85addda11cc2f4b36892db9696ce3c2c7334b5b8a122505b34d19135fede50e25678df71b0439e0704fd953f - languageName: node - linkType: hard - "table@npm:^5.4.6": version: 5.4.6 resolution: "table@npm:5.4.6" @@ -13983,16 +13420,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"through2@npm:^3.0.1": - version: 3.0.2 - resolution: "through2@npm:3.0.2" - dependencies: - inherits: ^2.0.4 - readable-stream: 2 || 3 - checksum: 47c9586c735e7d9cbbc1029f3ff422108212f7cc42e06d5cc9fff7901e659c948143c790e0d0d41b1b5f89f1d1200bdd200c7b72ad34f42f9edbeb32ea49e8b7 - languageName: node - linkType: hard - "through2@npm:^4.0.0": version: 4.0.2 resolution: "through2@npm:4.0.2" @@ -14071,13 +13498,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"toml@npm:^3.0.0": - version: 3.0.0 - resolution: "toml@npm:3.0.0" - checksum: 5d7f1d8413ad7780e9bdecce8ea4c3f5130dd53b0a4f2e90b93340979a137739879d7b9ce2ce05c938b8cc828897fe9e95085197342a1377dd8850bf5125f15f - languageName: node - linkType: hard - "touch@npm:^3.1.0": version: 3.1.0 resolution: "touch@npm:3.1.0" @@ -14223,13 +13643,6 @@ fsevents@~2.3.2: languageName: node linkType: hard -"ts-typed-json@npm:^0.3.2": - version: 0.3.2 - resolution: "ts-typed-json@npm:0.3.2" - checksum: 141c976da04b290076c7fdb79cc05429315a974a41ecab6cb78cd63fac832062fd9fd8de8166f52955037874f0bf97d51306e723318b05a22f66666ebbc7ca53 - languageName: node - linkType: hard - "tsconfig-paths@npm:^3.11.0, tsconfig-paths@npm:^3.5.0": version: 3.12.0 resolution: "tsconfig-paths@npm:3.12.0" @@ -14407,20 +13820,6 @@ typescript@^3.9.5: languageName: node linkType: hard -"typical@npm:^4.0.0": - version: 4.0.0 - resolution: "typical@npm:4.0.0" - checksum: a242081956825328f535e6195a924240b34daf6e7fdb573a1809a42b9f37fb8114fa99c7ab89a695e0cdb419d4149d067f6723e4b95855ffd39c6c4ca378efb3 - languageName: node - linkType: hard - -"typical@npm:^5.2.0": - version: 5.2.0 - resolution: "typical@npm:5.2.0" - checksum: ccaeb151a9a556291b495571ca44c4660f736fb49c29314bbf773c90fad92e9485d3cc2b074c933866c1595abbbc962f2b8bfc6e0f52a8c6b0cdd205442036ac - languageName: node - linkType: hard - "ua-parser-js@npm:^1.0.33": version: 1.0.33 resolution: "ua-parser-js@npm:1.0.33" @@ -14683,7 +14082,7 @@ typescript@^3.9.5: languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1, validate-npm-package-license@npm:^3.0.4": +"validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4" dependencies: @@ -14709,13 +14108,6 @@ typescript@^3.9.5: languageName: node linkType: hard -"varint@npm:5.0.0": - version: 5.0.0 - resolution: "varint@npm:5.0.0" - checksum: 527c65ad87f1d140c03cf734d5c193430ef75fc21b7ec9d2b72f06ee19dbf686be70e0bee27674db3807cedb73ba13ce36a589427ebe52ac620de11686a74c1c - languageName: node - linkType: hard - "varint@npm:^6.0.0": version: 6.0.0 resolution: "varint@npm:6.0.0" @@ -14723,13 +14115,6 @@ typescript@^3.9.5: languageName: node linkType: hard -"varint@npm:~5.0.0": - version: 5.0.2 - resolution: "varint@npm:5.0.2" - checksum: e1a66bf9a6cea96d1f13259170d4d41b845833acf3a9df990ea1e760d279bd70d5b1f4c002a50197efd2168a2fd43eb0b808444600fd4d23651e8d42fe90eb05 - languageName: node - linkType: hard - "vary@npm:^1": version: 1.1.2 resolution: "vary@npm:1.1.2" @@ -15049,16 +14434,6 @@ typescript@^3.9.5: languageName: node linkType: hard -"wordwrapjs@npm:^4.0.0": - version: 4.0.1 - resolution: "wordwrapjs@npm:4.0.1" - dependencies: - reduce-flatten: ^2.0.0 - typical: ^5.2.0 - checksum: 3d927f3c95d0ad990968da54c0ad8cde2801d8e91006cd7474c26e6b742cc8557250ce495c9732b2f9db1f903601cb74ec282e0f122ee0d02d7abe81e150eea8 - languageName: node - linkType: hard - "workerpool@npm:6.2.0": version: 6.2.0 resolution: "workerpool@npm:6.2.0"