diff --git a/backend/package-lock.json b/backend/package-lock.json index b62274bb5e..b34d7d681e 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -17,8 +17,8 @@ "bip32": "^4.0.0", "bitcoinjs-lib": "~6.1.3", "crypto-js": "~4.2.0", - "express": "~4.21.1", "ecpair": "^2.1.0", + "express": "~4.21.1", "maxmind": "~4.3.11", "mysql2": "~3.11.0", "redis": "^4.7.0", @@ -38,10 +38,12 @@ "@types/ws": "~8.5.10", "@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/parser": "^5.55.0", + "cross-env": "^7.0.3", "eslint": "^8.36.0", "eslint-config-prettier": "^8.8.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "rimraf": "^6.0.1", "ts-jest": "^29.1.1", "ts-node": "^10.9.1" } @@ -665,6 +667,109 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2891,6 +2996,25 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3047,6 +3171,13 @@ "node": ">=6.0.0" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ecpair": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", @@ -3720,6 +3851,23 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", @@ -3745,6 +3893,36 @@ } } }, + "node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -4344,6 +4522,22 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", @@ -6228,6 +6422,16 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/mmdb-lib": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", @@ -6454,6 +6658,13 @@ "node": ">=6" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6525,6 +6736,33 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -6907,15 +7145,70 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, + "license": "ISC", "dependencies": { - "glob": "^7.1.3" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" }, "bin": { - "rimraf": "bin.js" + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -7282,6 +7575,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -7294,6 +7603,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -7803,6 +8126,61 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -8400,6 +8778,71 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -10111,6 +10554,15 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + } + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -10219,6 +10671,12 @@ "esutils": "^2.0.2" } }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "ecpair": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-2.1.0.tgz", @@ -10737,6 +11195,17 @@ "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { @@ -10750,6 +11219,24 @@ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, + "foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } + } + }, "form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -11179,6 +11666,15 @@ "istanbul-lib-report": "^3.0.0" } }, + "jackspeak": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", + "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2" + } + }, "jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", @@ -12577,6 +13073,12 @@ "brace-expansion": "^1.1.7" } }, + "minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true + }, "mmdb-lib": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", @@ -12746,6 +13248,12 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -12796,6 +13304,24 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, + "path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "requires": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "dependencies": { + "lru-cache": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", + "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", + "dev": true + } + } + }, "path-to-regexp": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", @@ -13060,12 +13586,47 @@ "dev": true }, "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", "dev": true, "requires": { - "glob": "^7.1.3" + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", + "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + } + }, + "minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "ripemd160": { @@ -13341,6 +13902,17 @@ "strip-ansi": "^6.0.1" } }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, "strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -13350,6 +13922,15 @@ "ansi-regex": "^5.0.1" } }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, "strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -13717,6 +14298,43 @@ } } }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/backend/package.json b/backend/package.json index 559acb8332..894bb412eb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -21,22 +21,22 @@ ], "main": "index.ts", "scripts": { - "tsc": "./node_modules/typescript/bin/tsc -p tsconfig.build.json", + "tsc": "npx tsc -p tsconfig.build.json", "build": "npm run tsc && npm run create-resources", - "clean": "rm -rf ./dist/ ./node_modules/ ./package/ ./rust-gbt/", - "create-resources": "cp ./src/tasks/price-feeds/mtgox-weekly.json ./dist/tasks && node dist/api/fetch-version.js", - "package": "./npm_package.sh", - "package-rm-build-deps": "./npm_package_rm_build_deps.sh", + "clean": "npx rimraf ./dist/ ./node_modules/ ./package/ ./rust-gbt/", + "create-resources": "node scripts/create-resources.js", + "package": "node scripts/package.js", + "package-rm-build-deps": "node scripts/package-rm-build-deps.js", "preinstall": "cd ../rust/gbt && npm run build-release && npm run to-backend", "start": "node --max-old-space-size=2048 dist/index.js", "start-production": "node --max-old-space-size=16384 dist/index.js", "reindex-updated-pools": "npm run start-production --update-pools", "reindex-all-blocks": "npm run start-production --update-pools --reindex-blocks", - "test": "./node_modules/.bin/jest --coverage", - "test:ci": "CI=true ./node_modules/.bin/jest --coverage", - "lint": "./node_modules/.bin/eslint . --ext .ts", - "lint:fix": "./node_modules/.bin/eslint . --ext .ts --fix", - "prettier": "./node_modules/.bin/prettier --write \"src/**/*.{js,ts}\"" + "test": "npx jest --coverage", + "test:ci": "cross-env CI=true npx jest --coverage", + "lint": "npx eslint . --ext .ts", + "lint:fix": "npx eslint . --ext .ts --fix", + "prettier": "npx prettier --write \"src/**/*.{js,ts}\"" }, "dependencies": { "@babel/core": "^7.25.2", @@ -46,12 +46,12 @@ "bip32": "^4.0.0", "bitcoinjs-lib": "~6.1.3", "crypto-js": "~4.2.0", - "express": "~4.21.1", "ecpair": "^2.1.0", + "express": "~4.21.1", "maxmind": "~4.3.11", "mysql2": "~3.11.0", - "rust-gbt": "file:./rust-gbt", "redis": "^4.7.0", + "rust-gbt": "file:./rust-gbt", "socks-proxy-agent": "~7.0.0", "tiny-secp256k1": "^2.2.3", "typescript": "~4.9.3", @@ -67,10 +67,12 @@ "@types/ws": "~8.5.10", "@typescript-eslint/eslint-plugin": "^5.55.0", "@typescript-eslint/parser": "^5.55.0", + "cross-env": "^7.0.3", "eslint": "^8.36.0", "eslint-config-prettier": "^8.8.0", "jest": "^29.5.0", "prettier": "^3.0.0", + "rimraf": "^6.0.1", "ts-jest": "^29.1.1", "ts-node": "^10.9.1" } diff --git a/backend/scripts/create-resources.js b/backend/scripts/create-resources.js new file mode 100644 index 0000000000..d867166996 --- /dev/null +++ b/backend/scripts/create-resources.js @@ -0,0 +1,21 @@ +const fs = require('fs'); +const path = require('path'); + +try { + // Ensure dist/tasks directory exists + const tasksDir = path.join(__dirname, '..', 'dist', 'tasks'); + fs.mkdirSync(tasksDir, { recursive: true }); + + // Copy mtgox-weekly.json + const sourceFile = path.join(__dirname, '..', 'src', 'tasks', 'price-feeds', 'mtgox-weekly.json'); + const targetFile = path.join(tasksDir, 'mtgox-weekly.json'); + fs.copyFileSync(sourceFile, targetFile); + + // Run fetch-version.js + require('../dist/api/fetch-version.js'); + + console.log('Resources created successfully'); +} catch (error) { + console.error('Error creating resources:', error); + process.exit(1); +} diff --git a/backend/scripts/final-mysql-setup.sql b/backend/scripts/final-mysql-setup.sql new file mode 100644 index 0000000000..41c53bd5e6 --- /dev/null +++ b/backend/scripts/final-mysql-setup.sql @@ -0,0 +1,95 @@ +-- Drop tables in correct order to avoid foreign key constraints +DROP TABLE IF EXISTS blocks; +DROP TABLE IF EXISTS pools; +DROP TABLE IF EXISTS statistics; +DROP TABLE IF EXISTS elements_pegs; +DROP TABLE IF EXISTS prices; +DROP TABLE IF EXISTS state; + +-- Create state table first +CREATE TABLE state ( + name varchar(25) NOT NULL, + number int NULL, + string varchar(100) NULL, + CONSTRAINT name_unique UNIQUE (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Insert initial state values +INSERT INTO state VALUES('schema_version', 83, NULL); +INSERT INTO state VALUES('last_elements_block', 0, NULL); + +-- Create pools table with all required columns +CREATE TABLE pools ( + id int NOT NULL AUTO_INCREMENT, + unique_id varchar(100) NOT NULL, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses json NOT NULL, + regexes json NOT NULL, + slug varchar(100) NOT NULL, + PRIMARY KEY (id), + UNIQUE KEY unique_id_idx (unique_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Insert default pool with all required fields +INSERT INTO pools (id, unique_id, name, link, addresses, regexes, slug) +VALUES ( + -1, + 'unknown', + 'Unknown', + 'https://learnmeabitcoin.com/technical/coinbase-transaction', + '[]', + '[]', + 'unknown' +); + +-- Create blocks table with updated schema +CREATE TABLE blocks ( + height int unsigned NOT NULL, + hash varchar(65) NOT NULL, + blockTimestamp timestamp NOT NULL, + size int unsigned NOT NULL, + weight int unsigned NOT NULL, + tx_count smallint unsigned NOT NULL, + coinbase_raw text, + difficulty double NOT NULL, + pool_id int DEFAULT -1, + fees double unsigned NOT NULL, + reward double unsigned NOT NULL DEFAULT 0, + fee_span json NOT NULL, + median_fee double unsigned NOT NULL, + PRIMARY KEY (height), + INDEX pool_idx (pool_id), + CONSTRAINT blocks_pool_fk FOREIGN KEY (pool_id) REFERENCES pools(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Create other required tables +CREATE TABLE statistics ( + id int AUTO_INCREMENT PRIMARY KEY, + added datetime NOT NULL, + unconfirmed_transactions int unsigned NOT NULL, + tx_per_second float unsigned NOT NULL, + vbytes_per_second int unsigned NOT NULL, + mempool_byte_weight int unsigned NOT NULL, + fee_data longtext NOT NULL, + total_fee double unsigned NOT NULL, + INDEX added_idx (added) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Create prices table +CREATE TABLE prices ( + id SERIAL PRIMARY KEY, + time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + USD DECIMAL(24,8) NOT NULL DEFAULT 0, + EUR DECIMAL(24,8) NOT NULL DEFAULT 0, + GBP DECIMAL(24,8) NOT NULL DEFAULT 0, + CAD DECIMAL(24,8) NOT NULL DEFAULT 0, + CHF DECIMAL(24,8) NOT NULL DEFAULT 0, + AUD DECIMAL(24,8) NOT NULL DEFAULT 0, + JPY DECIMAL(24,8) NOT NULL DEFAULT 0, + INDEX time_idx (time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Add initial price data +INSERT INTO prices (time, USD, EUR, GBP, CAD, CHF, AUD, JPY) +VALUES (CURRENT_TIMESTAMP, 0, 0, 0, 0, 0, 0, 0); diff --git a/backend/scripts/migrations.sql b/backend/scripts/migrations.sql new file mode 100644 index 0000000000..9de2f3114e --- /dev/null +++ b/backend/scripts/migrations.sql @@ -0,0 +1,87 @@ +-- First drop foreign keys safely +SET @db_name = DATABASE(); +SET @table_name = 'blocks'; + +SELECT CONCAT('ALTER TABLE ', @table_name, ' DROP FOREIGN KEY ', CONSTRAINT_NAME, ';') +INTO @drop_fk_sql +FROM information_schema.REFERENTIAL_CONSTRAINTS +WHERE CONSTRAINT_SCHEMA = @db_name + AND TABLE_NAME = @table_name + AND REFERENCED_TABLE_NAME = 'pools' +LIMIT 1; + +SET @drop_sql = IFNULL(@drop_fk_sql, 'SELECT 1'); +PREPARE stmt FROM @drop_sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Drop and recreate tables +DROP TABLE IF EXISTS blocks; +DROP TABLE IF EXISTS pools; +DROP TABLE IF EXISTS statistics; +DROP TABLE IF EXISTS elements_pegs; +DROP TABLE IF EXISTS prices; +DROP TABLE IF EXISTS state; + +-- Create state table first +CREATE TABLE state ( + name varchar(25) NOT NULL, + number int(11) NULL, + string varchar(100) NULL, + CONSTRAINT name_unique UNIQUE (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Insert initial state +INSERT INTO state VALUES('schema_version', 0, NULL); +INSERT INTO state VALUES('last_elements_block', 0, NULL); + +-- Create pools table +CREATE TABLE pools ( + id int(11) NOT NULL AUTO_INCREMENT, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses text NOT NULL, + regexes text NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Create base blocks table +CREATE TABLE blocks ( + height int(11) unsigned NOT NULL, + hash varchar(65) NOT NULL, + blockTimestamp timestamp NOT NULL, + size int(11) unsigned NOT NULL, + weight int(11) unsigned NOT NULL, + tx_count int(11) unsigned NOT NULL, + coinbase_raw text, + difficulty bigint(20) unsigned NOT NULL, + pool_id int(11) DEFAULT -1, + fees double unsigned NOT NULL, + fee_span json NOT NULL, + median_fee double unsigned NOT NULL, + reward double unsigned NOT NULL DEFAULT 0, + PRIMARY KEY (height), + INDEX (pool_id), + FOREIGN KEY (pool_id) REFERENCES pools (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Create statistics table +CREATE TABLE statistics ( + id int(11) NOT NULL AUTO_INCREMENT, + added datetime NOT NULL, + unconfirmed_transactions int(11) UNSIGNED NOT NULL, + tx_per_second float UNSIGNED NOT NULL, + vbytes_per_second int(10) UNSIGNED NOT NULL, + mempool_byte_weight int(10) UNSIGNED NOT NULL, + fee_data longtext NOT NULL, + total_fee double UNSIGNED NOT NULL, + PRIMARY KEY (id), + INDEX added_idx (added) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Insert default pool +INSERT INTO pools (id, name, link, addresses, regexes) +VALUES (-1, 'Unknown', '', '', ''); + +-- Set schema version to skip migrations +UPDATE state SET number = 83 WHERE name = 'schema_version'; diff --git a/backend/scripts/mysql8-migrations.sql b/backend/scripts/mysql8-migrations.sql new file mode 100644 index 0000000000..773ca342a2 --- /dev/null +++ b/backend/scripts/mysql8-migrations.sql @@ -0,0 +1,84 @@ +-- Drop foreign keys safely using information_schema +SET @table_name = 'blocks'; +SET @constraints = ( + SELECT GROUP_CONCAT(CONSTRAINT_NAME) + FROM information_schema.TABLE_CONSTRAINTS + WHERE TABLE_NAME = @table_name + AND CONSTRAINT_TYPE = 'FOREIGN KEY' + AND TABLE_SCHEMA = DATABASE() +); + +SET @drop_fk_stmt = IF(@constraints IS NOT NULL, + CONCAT('ALTER TABLE ', @table_name, ' DROP FOREIGN KEY ', @constraints), + 'SELECT 1'); + +PREPARE stmt FROM @drop_fk_stmt; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Drop and recreate tables with proper MySQL 8 syntax +DROP TABLE IF EXISTS blocks; +DROP TABLE IF EXISTS pools; +DROP TABLE IF EXISTS statistics; +DROP TABLE IF EXISTS elements_pegs; +DROP TABLE IF EXISTS state; + +-- Create state table +CREATE TABLE state ( + name varchar(25) NOT NULL, + number int NULL, + string varchar(100) NULL, + CONSTRAINT name_unique UNIQUE (name) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Create pools table +CREATE TABLE pools ( + id int NOT NULL AUTO_INCREMENT, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses text NOT NULL, + regexes text NOT NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Create blocks table +CREATE TABLE blocks ( + height int unsigned NOT NULL DEFAULT 0, + hash varchar(65) NOT NULL, + blockTimestamp timestamp NOT NULL, + size int unsigned NOT NULL DEFAULT 0, + weight int unsigned NOT NULL DEFAULT 0, + tx_count smallint unsigned NOT NULL DEFAULT 0, + coinbase_raw text, + difficulty double NOT NULL DEFAULT 0, + pool_id int DEFAULT -1, + fees double unsigned NOT NULL DEFAULT 0, + reward double unsigned NOT NULL DEFAULT 0, + fee_span json NOT NULL, + median_fee double unsigned NOT NULL DEFAULT 0, + INDEX height_idx (height), + INDEX pool_idx (pool_id), + CONSTRAINT blocks_pool_fk FOREIGN KEY (pool_id) REFERENCES pools(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Create prices table +CREATE TABLE prices ( + id SERIAL PRIMARY KEY, + time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + USD DECIMAL(24,8) NOT NULL DEFAULT 0, + EUR DECIMAL(24,8) NOT NULL DEFAULT 0, + GBP DECIMAL(24,8) NOT NULL DEFAULT 0, + CAD DECIMAL(24,8) NOT NULL DEFAULT 0, + CHF DECIMAL(24,8) NOT NULL DEFAULT 0, + AUD DECIMAL(24,8) NOT NULL DEFAULT 0, + JPY DECIMAL(24,8) NOT NULL DEFAULT 0, + INDEX time_index (time) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Add initial price data to prevent query errors +INSERT INTO prices (time, USD, EUR, GBP, CAD, CHF, AUD, JPY) +VALUES (CURRENT_TIMESTAMP, 0, 0, 0, 0, 0, 0, 0); + +-- Initialize state +INSERT INTO state VALUES('schema_version', 83, NULL); +INSERT INTO state VALUES('last_elements_block', 0, NULL); diff --git a/backend/scripts/safe-init-db.sql b/backend/scripts/safe-init-db.sql new file mode 100644 index 0000000000..378ee6924e --- /dev/null +++ b/backend/scripts/safe-init-db.sql @@ -0,0 +1,68 @@ +-- Safely drop foreign key constraints +SELECT DISTINCT CONSTRAINT_NAME INTO @fk_name +FROM information_schema.KEY_COLUMN_USAGE +WHERE TABLE_NAME = 'blocks' +AND REFERENCED_TABLE_NAME = 'pools'; + +SET @drop_fk = CONCAT('ALTER TABLE blocks DROP FOREIGN KEY ', @fk_name); + +-- Only execute if foreign key exists +SET @sql = IFNULL(@drop_fk, 'SELECT "No foreign key exists"'); +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; + +-- Drop all tables in correct order +DROP TABLE IF EXISTS blocks; +DROP TABLE IF EXISTS pools; +DROP TABLE IF EXISTS statistics; +DROP TABLE IF EXISTS elements_pegs; +DROP TABLE IF EXISTS prices; +DROP TABLE IF EXISTS state; + +-- Create tables from scratch +-- Create state table with schema version 83 +CREATE TABLE state ( + name varchar(25) NOT NULL, + number int NULL, + string varchar(100) NULL, + CONSTRAINT name_unique UNIQUE (name) +) ENGINE=InnoDB; + +INSERT INTO state VALUES('schema_version', 83, NULL); +INSERT INTO state VALUES('last_elements_block', 0, NULL); + +-- Create pools table first (referenced by blocks) +CREATE TABLE pools ( + id int NOT NULL AUTO_INCREMENT PRIMARY KEY, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses text NOT NULL, + regexes text NOT NULL +) ENGINE=InnoDB; + +-- Insert default pool +INSERT INTO pools (id, name, link, addresses, regexes) VALUES (-1, 'Unknown', '', '', ''); + +-- Create blocks table with explicit foreign key name +CREATE TABLE blocks ( + height int unsigned NOT NULL, + hash varchar(65) NOT NULL, + blockTimestamp timestamp NOT NULL, + size int unsigned NOT NULL, + weight int unsigned NOT NULL, + tx_count smallint unsigned NOT NULL, + coinbase_raw text, + difficulty double NOT NULL, + pool_id int DEFAULT -1, + fees double unsigned NOT NULL, + reward double unsigned NOT NULL DEFAULT 0, + fee_span json NOT NULL, + median_fee double unsigned NOT NULL, + PRIMARY KEY (height), + INDEX pool_idx (pool_id), + CONSTRAINT blocks_pool_fk FOREIGN KEY (pool_id) REFERENCES pools(id) +) ENGINE=InnoDB; + +-- Create statistics and prices tables +-- ...rest of table creation code... diff --git a/backend/scripts/setup-db.ps1 b/backend/scripts/setup-db.ps1 new file mode 100644 index 0000000000..0f7bfe9c8f --- /dev/null +++ b/backend/scripts/setup-db.ps1 @@ -0,0 +1,28 @@ +$password = "root" + +# Drop and create database +Write-Host "Resetting database..." +$dropCreate = @" +DROP DATABASE IF EXISTS mempool; +CREATE DATABASE mempool; +"@ +echo $dropCreate | mysql -u root "-p$password" + +# Read SQL file content +Write-Host "Reading initialization script..." +$sqlContent = Get-Content -Path "scripts/final-mysql-setup.sql" -Raw + +# Execute initialization script +Write-Host "Initializing database..." +echo $sqlContent | mysql -u root "-p$password" mempool + +# Verify setup +Write-Host "`nVerifying setup..." +$verify = @" +USE mempool; +SHOW TABLES; +SELECT number FROM state WHERE name='schema_version'; +"@ +echo $verify | mysql -u root "-p$password" + +Write-Host "`nSetup complete!" diff --git a/rust/gbt/check-cargo-version.js b/rust/gbt/check-cargo-version.js new file mode 100644 index 0000000000..c437e933bb --- /dev/null +++ b/rust/gbt/check-cargo-version.js @@ -0,0 +1,15 @@ +const fs = require('fs'); +const { execSync } = require('child_process'); + +try { + const rustToolchain = fs.readFileSync('./rust-toolchain', 'utf8').trim(); + const cargoVersion = execSync('cargo --version', { encoding: 'utf8' }); + + if (!cargoVersion.includes(`cargo ${rustToolchain}`)) { + console.warn(`\x1b[1;35m[[[[WARNING]]]]: cargo version mismatch with ./rust-toolchain version (${rustToolchain})!!!\x1b[0m`); + } +} catch (error) { + console.warn('Failed to check cargo version:', error); + // Exit with success code to not break the build + process.exit(0); +} diff --git a/rust/gbt/package.json b/rust/gbt/package.json index 77ca25da62..8a0e0882ba 100644 --- a/rust/gbt/package.json +++ b/rust/gbt/package.json @@ -9,9 +9,9 @@ "build": "npm install --no-save @napi-rs/cli@2.18.0 && npm run check-cargo-version && napi build --platform", "build-debug": "npm run build", "build-release": "npm run build -- --release --strip", - "check-cargo-version": "VER=$(cat rust-toolchain) ; if ! cargo version | grep \"cargo $VER\" >/dev/null ; then echo -e \"\\033[1;35m[[[[WARNING]]]]: cargo version mismatch with ./rust-toolchain version ($VER)!!!\\033[0m\" >&2; fi", + "check-cargo-version": "node check-cargo-version.js", "clean": "rm -rf ./target/ ./node_modules/ *.node package-lock.json", - "to-backend": "FD=${FD:-../../backend/rust-gbt/} ; rm -rf $FD && mkdir $FD && cp index.js index.d.ts package.json *.node $FD", + "to-backend": "node to-backend.js", "prepublishOnly": "napi prepublish -t npm", "test": "cargo test" }, diff --git a/rust/gbt/to-backend.js b/rust/gbt/to-backend.js new file mode 100644 index 0000000000..ea69cbb12d --- /dev/null +++ b/rust/gbt/to-backend.js @@ -0,0 +1,39 @@ +const fs = require('fs'); +const path = require('path'); + +// Default target directory relative to gbt folder +const defaultTargetDir = '../../backend/rust-gbt/'; +const targetDir = process.env.FD || defaultTargetDir; +const fullTargetPath = path.resolve(__dirname, targetDir); + +try { + // Remove existing directory if it exists + if (fs.existsSync(fullTargetPath)) { + fs.rmSync(fullTargetPath, { recursive: true, force: true }); + } + + // Create the target directory + fs.mkdirSync(fullTargetPath, { recursive: true }); + + // Files to copy + const filesToCopy = ['index.js', 'index.d.ts', 'package.json']; + + // Copy the specified files + filesToCopy.forEach(file => { + if (fs.existsSync(file)) { + fs.copyFileSync(file, path.join(fullTargetPath, file)); + } + }); + + // Copy .node files + fs.readdirSync(__dirname) + .filter(file => file.endsWith('.node')) + .forEach(file => { + fs.copyFileSync(file, path.join(fullTargetPath, file)); + }); + + console.log('Files successfully copied to', fullTargetPath); +} catch (error) { + console.error('Error copying files:', error); + process.exit(1); +}