diff --git a/barretenberg/acir_tests/browser-test-app/package.json b/barretenberg/acir_tests/browser-test-app/package.json index 857d7be57509..a118807386d7 100644 --- a/barretenberg/acir_tests/browser-test-app/package.json +++ b/barretenberg/acir_tests/browser-test-app/package.json @@ -15,7 +15,7 @@ "pako": "^2.1.0", "pino": "^9.5.0", "process": "^0.11.10", - "serve": "^14.2.1", + "serve": "^14.2.6", "ts-loader": "^9.5.1", "typescript": "^5.4.2", "webpack": "^5.99.6", diff --git a/barretenberg/acir_tests/package.json b/barretenberg/acir_tests/package.json index 5e443a93352f..82bcae9dd162 100644 --- a/barretenberg/acir_tests/package.json +++ b/barretenberg/acir_tests/package.json @@ -12,6 +12,9 @@ "pino": "^9.5.0" }, "resolutions": { - "ws": "^8.17.1" + "ws": "^8.17.1", + "basic-ftp": "^5.2.0", + "node-forge": "^1.3.2", + "serialize-javascript": "^7.0.3" } } diff --git a/barretenberg/acir_tests/yarn.lock b/barretenberg/acir_tests/yarn.lock index 3e4b08f0ac21..23cba15e717f 100644 --- a/barretenberg/acir_tests/yarn.lock +++ b/barretenberg/acir_tests/yarn.lock @@ -902,7 +902,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:~1.3.4, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -969,15 +969,15 @@ __metadata: languageName: node linkType: hard -"ajv@npm:8.12.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" +"ajv@npm:8.18.0": + version: 8.18.0 + resolution: "ajv@npm:8.18.0" dependencies: - fast-deep-equal: "npm:^3.1.1" + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" - uri-js: "npm:^4.2.2" - checksum: 10c0/ac4f72adf727ee425e049bc9d8b31d4a57e1c90da8d28bcd23d60781b12fcd6fc3d68db5df16994c57b78b94eed7988f5a6b482fd376dc5b084125e20a0a622e + checksum: 10c0/e7517c426173513a07391be951879932bdf3348feaebd2199f5b901c20f99d60db8cd1591502d4d551dc82f594e82a05c4fe1c70139b15b8937f7afeaed9532f languageName: node linkType: hard @@ -1167,10 +1167,10 @@ __metadata: languageName: node linkType: hard -"basic-ftp@npm:^5.0.2": - version: 5.0.5 - resolution: "basic-ftp@npm:5.0.5" - checksum: 10c0/be983a3997749856da87b839ffce6b8ed6c7dbf91ea991d5c980d8add275f9f2926c19f80217ac3e7f353815be879371d636407ca72b038cea8cab30e53928a6 +"basic-ftp@npm:^5.2.0": + version: 5.2.0 + resolution: "basic-ftp@npm:5.2.0" + checksum: 10c0/a0f85c01deae0723021f9bf4a7be29378186fa8bba41e74ea11832fe74c187ce90c3599c3cc5ec936581cfd150020e79f4a9ed0ee9fb20b2308e69b045f3a059 languageName: node linkType: hard @@ -1261,12 +1261,12 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" +"brace-expansion@npm:^2.0.2": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" dependencies: balanced-match: "npm:^1.0.0" - checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf languageName: node linkType: hard @@ -1289,7 +1289,7 @@ __metadata: pako: "npm:^2.1.0" pino: "npm:^9.5.0" process: "npm:^0.11.10" - serve: "npm:^14.2.1" + serve: "npm:^14.2.6" ts-loader: "npm:^9.5.1" typescript: "npm:^5.4.2" webpack: "npm:^5.99.6" @@ -1605,7 +1605,7 @@ __metadata: languageName: node linkType: hard -"compressible@npm:~2.0.16, compressible@npm:~2.0.18": +"compressible@npm:~2.0.18": version: 2.0.18 resolution: "compressible@npm:2.0.18" dependencies: @@ -1614,18 +1614,18 @@ __metadata: languageName: node linkType: hard -"compression@npm:1.7.4": - version: 1.7.4 - resolution: "compression@npm:1.7.4" +"compression@npm:1.8.1": + version: 1.8.1 + resolution: "compression@npm:1.8.1" dependencies: - accepts: "npm:~1.3.5" - bytes: "npm:3.0.0" - compressible: "npm:~2.0.16" + bytes: "npm:3.1.2" + compressible: "npm:~2.0.18" debug: "npm:2.6.9" - on-headers: "npm:~1.0.2" - safe-buffer: "npm:5.1.2" + negotiator: "npm:~0.6.4" + on-headers: "npm:~1.1.0" + safe-buffer: "npm:5.2.1" vary: "npm:~1.1.2" - checksum: 10c0/138db836202a406d8a14156a5564fb1700632a76b6e7d1546939472895a5304f2b23c80d7a22bf44c767e87a26e070dbc342ea63bb45ee9c863354fa5556bbbc + checksum: 10c0/85114b0b91c16594dc8c671cd9b05ef5e465066a60e5a4ed8b4551661303559a896ed17bb72c4234c04064e078f6ca86a34b8690349499a43f6fc4b844475da4 languageName: node linkType: hard @@ -2297,7 +2297,7 @@ __metadata: languageName: node linkType: hard -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": +"fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 @@ -3377,21 +3377,21 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:3.1.5": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 languageName: node linkType: hard "minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 languageName: node linkType: hard @@ -3609,10 +3609,10 @@ __metadata: languageName: node linkType: hard -"node-forge@npm:^1": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 10c0/e882819b251a4321f9fc1d67c85d1501d3004b4ee889af822fd07f64de3d1a8e272ff00b689570af0465d65d6bf5074df9c76e900e0aff23e60b847f2a46fbe8 +"node-forge@npm:^1.3.2": + version: 1.3.3 + resolution: "node-forge@npm:1.3.3" + checksum: 10c0/9c6f53b0ebb34865872cf62a35b0aef8fb337e2efc766626c2e3a0040f4c02933bf29a62ba999eb44a2aca73bd512c4eda22705a47b94654b9fb8ed53db9a1db languageName: node linkType: hard @@ -3729,6 +3729,13 @@ __metadata: languageName: node linkType: hard +"on-headers@npm:~1.1.0": + version: 1.1.0 + resolution: "on-headers@npm:1.1.0" + checksum: 10c0/2c3b6b0d68ec9adbd561dc2d61c9b14da8ac03d8a2f0fd9e97bdf0600c887d5d97f664ff3be6876cf40cda6e3c587d73a4745e10b426ac50c7664fc5a0dfc0a1 + languageName: node + linkType: hard + "once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -4138,13 +4145,6 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - "puppeteer-core@npm:24.22.3": version: 24.22.3 resolution: "puppeteer-core@npm:24.22.3" @@ -4192,15 +4192,6 @@ __metadata: languageName: node linkType: hard -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 - languageName: node - linkType: hard - "range-parser@npm:1.2.0": version: 1.2.0 resolution: "range-parser@npm:1.2.0" @@ -4433,20 +4424,20 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 - languageName: node - linkType: hard - -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 languageName: node linkType: hard +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + "safe-stable-stringify@npm:^2.3.1": version: 2.5.0 resolution: "safe-stable-stringify@npm:2.5.0" @@ -4529,27 +4520,25 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.2": - version: 6.0.2 - resolution: "serialize-javascript@npm:6.0.2" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 +"serialize-javascript@npm:^7.0.3": + version: 7.0.4 + resolution: "serialize-javascript@npm:7.0.4" + checksum: 10c0/f3da6f994c41306fbfabb55eefe280a46da05592939a84b0d95c84e296c92ba9e6a3d86cf7bbd71e7a59e1cfcd8481745910af109bedbd3ed853b444d32f9ee9 languageName: node linkType: hard -"serve-handler@npm:6.1.6": - version: 6.1.6 - resolution: "serve-handler@npm:6.1.6" +"serve-handler@npm:6.1.7": + version: 6.1.7 + resolution: "serve-handler@npm:6.1.7" dependencies: bytes: "npm:3.0.0" content-disposition: "npm:0.5.2" mime-types: "npm:2.1.18" - minimatch: "npm:3.1.2" + minimatch: "npm:3.1.5" path-is-inside: "npm:1.0.2" path-to-regexp: "npm:3.3.0" range-parser: "npm:1.2.0" - checksum: 10c0/1e1cb6bbc51ee32bc1505f2e0605bdc2e96605c522277c977b67f83be9d66bd1eec8604388714a4d728e036d86b629bc9aec02120ea030d3d2c3899d44696503 + checksum: 10c0/35afb68d81afd3c38d15792a5bc2451915b739bef2898a47ebd190db6a4e29846530ac00292b8008fe7297a819257c3948be2deaf4ffd32c96689e8947cf0ae9 languageName: node linkType: hard @@ -4580,24 +4569,24 @@ __metadata: languageName: node linkType: hard -"serve@npm:^14.2.1": - version: 14.2.4 - resolution: "serve@npm:14.2.4" +"serve@npm:^14.2.6": + version: 14.2.6 + resolution: "serve@npm:14.2.6" dependencies: "@zeit/schemas": "npm:2.36.0" - ajv: "npm:8.12.0" + ajv: "npm:8.18.0" arg: "npm:5.0.2" boxen: "npm:7.0.0" chalk: "npm:5.0.1" chalk-template: "npm:0.4.0" clipboardy: "npm:3.0.0" - compression: "npm:1.7.4" + compression: "npm:1.8.1" is-port-reachable: "npm:4.0.0" - serve-handler: "npm:6.1.6" + serve-handler: "npm:6.1.7" update-check: "npm:1.5.4" bin: serve: build/main.js - checksum: 10c0/93abecd6214228d529065040f7c0cbe541c1cc321c6a94b8a968f45a519bd9c46a9fd5e45a9b24a1f5736c5b547b8fa60d5414ebc78f870e29431b64165c1d06 + checksum: 10c0/7e1668e0d187719dbe4f3de967012ce2263c967f6135d9c630f803b0f173334e1442ab326fcc4c8e6cd4e293d8bd8c773aebab2746ecaa0fb1ab29a36079763b languageName: node linkType: hard @@ -5310,15 +5299,6 @@ __metadata: languageName: node linkType: hard -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - "util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" diff --git a/barretenberg/docs/package.json b/barretenberg/docs/package.json index a11671aee17c..04147dbbb2bb 100644 --- a/barretenberg/docs/package.json +++ b/barretenberg/docs/package.json @@ -34,6 +34,7 @@ "react-dom": "^19.0.0", "rehype-katex": "^7.0.1", "remark-math": "^6.0.0", + "serve": "^14.2.6", "tsx": "^4.19.3" }, "devDependencies": { @@ -44,20 +45,24 @@ "@swc/core": "^1.10.0", "@swc/jest": "^0.2.37", "@types/jest": "^30.0.0", + "@typescript/native-preview": "7.0.0-dev.20251126.1", "jest": "^30.0.0", "netlify-cli": "^17.23.0", "nodemon": "^3.1.10", "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "~5.6.2", - "@typescript/native-preview": "7.0.0-dev.20251126.1" + "typescript": "~5.6.2" }, "jest": { "testRegex": "./examples/.*\\.test\\.ts$", "transform": { - "^.+\\.tsx?$": ["@swc/jest"] + "^.+\\.tsx?$": [ + "@swc/jest" + ] }, - "extensionsToTreatAsEsm": [".ts"], + "extensionsToTreatAsEsm": [ + ".ts" + ], "testTimeout": 120000 }, "browserslist": { @@ -77,7 +82,11 @@ }, "resolutions": { "tar-fs": "^3.1.1", - "@docusaurus/mdx-loader/image-size": "1.2.1" + "@docusaurus/mdx-loader/image-size": "1.2.1", + "h3": "^1.15.5", + "node-forge": "^1.3.2", + "serve-handler": "^6.1.7", + "serialize-javascript": "^7.0.3" }, "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/barretenberg/docs/yarn.lock b/barretenberg/docs/yarn.lock index d4306cb115eb..4dd0ec62576a 100644 --- a/barretenberg/docs/yarn.lock +++ b/barretenberg/docs/yarn.lock @@ -6371,6 +6371,11 @@ resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== +"@zeit/schemas@2.36.0": + version "2.36.0" + resolved "https://registry.yarnpkg.com/@zeit/schemas/-/schemas-2.36.0.tgz#7a1b53f4091e18d0b404873ea3e3c83589c765f2" + integrity sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -6492,6 +6497,16 @@ ajv-keywords@^5.1.0: dependencies: fast-deep-equal "^3.1.3" +ajv@8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.18.0.tgz#8864186b6738d003eb3a933172bb3833e10cefbc" + integrity sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -6669,6 +6684,11 @@ anymatch@^3.1.3, anymatch@~3.1.2: resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.1.0.tgz#75500a190313d95c64e871e7e4284c6ac219f0b1" integrity sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew== +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + archiver-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2" @@ -6748,16 +6768,16 @@ are-we-there-yet@^2.0.0: delegates "^1.0.0" readable-stream "^3.6.0" +arg@5.0.2, arg@^5.0.0: + version "5.0.2" + resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" + integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== + arg@^4.1.0: version "4.1.3" resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -arg@^5.0.0: - version "5.0.2" - resolved "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz" - integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg== - argparse@^1.0.7: version "1.0.10" resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" @@ -7136,6 +7156,20 @@ boolbase@^1.0.0: resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== +boxen@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/boxen/-/boxen-7.0.0.tgz#9e5f8c26e716793fc96edcf7cf754cdf5e3fbf32" + integrity sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg== + dependencies: + ansi-align "^3.0.1" + camelcase "^7.0.0" + chalk "^5.0.1" + cli-boxes "^3.0.0" + string-width "^5.1.2" + type-fest "^2.13.0" + widest-line "^4.0.1" + wrap-ansi "^8.0.1" + boxen@7.1.1, boxen@^7.0.0: version "7.1.1" resolved "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz" @@ -7186,7 +7220,7 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -brace-expansion@^2.0.1: +brace-expansion@^2.0.1, brace-expansion@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== @@ -7364,7 +7398,7 @@ camelcase@^6.2.0, camelcase@^6.3.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -camelcase@^7.0.1: +camelcase@^7.0.0, camelcase@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz" integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== @@ -7394,6 +7428,18 @@ ccount@^2.0.0: resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== +chalk-template@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/chalk-template/-/chalk-template-0.4.0.tgz#692c034d0ed62436b9062c1707fadcd0f753204b" + integrity sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg== + dependencies: + chalk "^4.1.2" + +chalk@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6" + integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w== + chalk@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" @@ -7645,6 +7691,15 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +clipboardy@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-3.0.0.tgz#f3876247404d334c9ed01b6f269c11d09a5e3092" + integrity sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg== + dependencies: + arch "^2.2.0" + execa "^5.1.1" + is-wsl "^2.2.0" + clipboardy@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-4.0.0.tgz#e73ced93a76d19dd379ebf1f297565426dffdca1" @@ -7892,6 +7947,19 @@ compressible@~2.0.18: dependencies: mime-db ">= 1.43.0 < 2" +compression@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.8.1.tgz#4a45d909ac16509195a9a28bd91094889c180d79" + integrity sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w== + dependencies: + bytes "3.1.2" + compressible "~2.0.18" + debug "2.6.9" + negotiator "~0.6.4" + on-headers "~1.1.0" + safe-buffer "5.2.1" + vary "~1.1.2" + compression@^1.7.4: version "1.8.0" resolved "https://registry.npmjs.org/compression/-/compression-1.8.0.tgz" @@ -8180,7 +8248,7 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3, cross-spawn@^7.0.6: shebang-command "^2.0.0" which "^2.0.1" -"crossws@>=0.2.0 <0.4.0", crossws@^0.3.4: +"crossws@>=0.2.0 <0.4.0", crossws@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/crossws/-/crossws-0.3.5.tgz#daad331d44148ea6500098bc858869f3a5ab81a6" integrity sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA== @@ -10713,19 +10781,19 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" -h3@^1.10.0, h3@^1.12.0, h3@^1.15.2: - version "1.15.3" - resolved "https://registry.yarnpkg.com/h3/-/h3-1.15.3.tgz#e242ec6a7692a45caed3e4a73710cede4fb8d863" - integrity sha512-z6GknHqyX0h9aQaTx22VZDf6QyZn+0Nh+Ym8O/u0SGSkyF5cuTJYKlc8MkzW3Nzf9LE1ivcpmYC3FUGpywhuUQ== +h3@^1.10.0, h3@^1.12.0, h3@^1.15.2, h3@^1.15.5: + version "1.15.5" + resolved "https://registry.yarnpkg.com/h3/-/h3-1.15.5.tgz#e2f28d4a66a249973bb050eaddb06b9ab55506f8" + integrity sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg== dependencies: cookie-es "^1.2.2" - crossws "^0.3.4" + crossws "^0.3.5" defu "^6.1.4" destr "^2.0.5" iron-webcrypto "^1.2.1" - node-mock-http "^1.0.0" + node-mock-http "^1.0.4" radix3 "^1.1.2" - ufo "^1.6.1" + ufo "^1.6.3" uncrypto "^0.1.3" handle-thing@^2.0.0: @@ -11717,6 +11785,11 @@ is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-port-reachable@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-4.0.0.tgz#dac044091ef15319c8ab2f34604d8794181f8c2d" + integrity sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig== + is-regexp@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz" @@ -13765,26 +13838,26 @@ minimalistic-assert@^1.0.0: resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +minimatch@3.1.5, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== dependencies: brace-expansion "^1.1.7" minimatch@^5.0.1, minimatch@^5.1.0: - version "5.1.6" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" - integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + version "5.1.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.9.tgz#1293ef15db0098b394540e8f9f744f9fda8dee4b" + integrity sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw== dependencies: brace-expansion "^2.0.1" minimatch@^9.0.0, minimatch@^9.0.4: - version "9.0.5" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + version "9.0.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e" + integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^2.0.2" minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" @@ -14316,10 +14389,10 @@ node-fetch@^2.6.7: dependencies: whatwg-url "^5.0.0" -node-forge@^1, node-forge@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== +node-forge@^1, node-forge@^1.3.1, node-forge@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.3.tgz#0ad80f6333b3a0045e827ac20b7f735f93716751" + integrity sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg== node-gyp-build-optional-packages@5.2.2: version "5.2.2" @@ -14338,10 +14411,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-mock-http@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.1.tgz#29b4e0b08d786acadda450e8c159d3e652b3cbfd" - integrity sha512-0gJJgENizp4ghds/Ywu2FCmcRsgBTmRQzYPZm61wy+Em2sBarSka0OhQS5huLBg6od1zkNpnWMCZloQDFVvOMQ== +node-mock-http@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/node-mock-http/-/node-mock-http-1.0.4.tgz#21f2ab4ce2fe4fbe8a660d7c5195a1db85e042a4" + integrity sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ== node-releases@^2.0.19: version "2.0.19" @@ -14574,6 +14647,11 @@ on-headers@^1.0.0, on-headers@~1.0.2: resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== +on-headers@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.1.0.tgz#59da4f91c45f5f989c6e4bcedc5a3b0aed70ff65" + integrity sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A== + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" @@ -16095,13 +16173,6 @@ random-bytes@~1.0.0: resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" integrity sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ== -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - range-parser@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz" @@ -16132,7 +16203,7 @@ raw-body@3.0.0: iconv-lite "0.6.3" unpipe "1.0.0" -rc@1.2.8, rc@^1.2.7: +rc@1.2.8, rc@^1.0.1, rc@^1.1.6, rc@^1.2.7: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== @@ -16482,6 +16553,14 @@ regexpu-core@^6.2.0: unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.1.0" +registry-auth-token@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.3.2.tgz#851fd49038eecb586911115af845260eec983f20" + integrity sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ== + dependencies: + rc "^1.1.6" + safe-buffer "^5.0.1" + registry-auth-token@^5.0.1, registry-auth-token@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz" @@ -16489,6 +16568,13 @@ registry-auth-token@^5.0.1, registry-auth-token@^5.0.2: dependencies: "@pnpm/npm-conf" "^2.1.0" +registry-url@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" + integrity sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA== + dependencies: + rc "^1.0.1" + registry-url@^6.0.0, registry-url@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz" @@ -16837,7 +16923,7 @@ rxjs@^7.5.5: dependencies: tslib "^2.1.0" -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -16986,22 +17072,20 @@ send@0.19.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz" - integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== - dependencies: - randombytes "^2.1.0" +serialize-javascript@^6.0.0, serialize-javascript@^6.0.1, serialize-javascript@^6.0.2, serialize-javascript@^7.0.3: + version "7.0.4" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-7.0.4.tgz#c517735bd5b7631dd1fc191ee19cbb713ff8e05c" + integrity sha512-DuGdB+Po43Q5Jxwpzt1lhyFSYKryqoNjQSA9M92tyw0lyHIOur+XCalOUe0KTJpyqzT8+fQ5A0Jf7vCx/NKmIg== -serve-handler@^6.1.6: - version "6.1.6" - resolved "https://registry.npmjs.org/serve-handler/-/serve-handler-6.1.6.tgz" - integrity sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ== +serve-handler@6.1.7, serve-handler@^6.1.6, serve-handler@^6.1.7: + version "6.1.7" + resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.7.tgz#e9bb864e87ee71e8dab874cde44d146b77e3fb78" + integrity sha512-CinAq1xWb0vR3twAv9evEU8cNWkXCb9kd5ePAHUKJBkOsUpR1wt/CvGdeca7vqumL1U5cSaeVQ6zZMxiJ3yWsg== dependencies: bytes "3.0.0" content-disposition "0.5.2" mime-types "2.1.18" - minimatch "3.1.2" + minimatch "3.1.5" path-is-inside "1.0.2" path-to-regexp "3.3.0" range-parser "1.2.0" @@ -17029,6 +17113,23 @@ serve-static@1.16.2: parseurl "~1.3.3" send "0.19.0" +serve@^14.2.6: + version "14.2.6" + resolved "https://registry.yarnpkg.com/serve/-/serve-14.2.6.tgz#b5e520dfda9b1ed3b824a8e8d4fd6f69e4c6944c" + integrity sha512-QEjUSA+sD4Rotm1znR8s50YqA3kYpRGPmtd5GlFxbaL9n/FdUNbqMhxClqdditSk0LlZyA/dhud6XNRTOC9x2Q== + dependencies: + "@zeit/schemas" "2.36.0" + ajv "8.18.0" + arg "5.0.2" + boxen "7.0.0" + chalk "5.0.1" + chalk-template "0.4.0" + clipboardy "3.0.0" + compression "1.8.1" + is-port-reachable "4.0.0" + serve-handler "6.1.7" + update-check "1.5.4" + set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -18208,6 +18309,11 @@ ufo@^1.3.2, ufo@^1.5.4, ufo@^1.6.1: resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== +ufo@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.3.tgz#799666e4e88c122a9659805e30b9dc071c3aed4f" + integrity sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q== + uid-safe@2.1.5: version "2.1.5" resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.5.tgz#2b3d5c7240e8fc2e58f8aa269e5ee49c0857bd3a" @@ -18470,6 +18576,14 @@ update-browserslist-db@^1.1.3: escalade "^3.2.0" picocolors "^1.1.1" +update-check@1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/update-check/-/update-check-1.5.4.tgz#5b508e259558f1ad7dbc8b4b0457d4c9d28c8743" + integrity sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ== + dependencies: + registry-auth-token "3.3.2" + registry-url "3.1.0" + update-notifier@7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-7.3.1.tgz#49af1ad6acfa0ea01c0d0f3c04047c154ead7096" diff --git a/boxes/boxes/react/package.json b/boxes/boxes/react/package.json index 02c2cdfcb03f..b74ac2c68439 100644 --- a/boxes/boxes/react/package.json +++ b/boxes/boxes/react/package.json @@ -38,7 +38,7 @@ "formik": "^2.4.3", "react": "^18.2.0", "react-dom": "^18.2.0", - "serve": "^14.2.1", + "serve": "^14.2.6", "yup": "^1.2.0" }, "devDependencies": { diff --git a/boxes/package.json b/boxes/package.json index fa22079088b0..03e4c87b41d1 100644 --- a/boxes/package.json +++ b/boxes/package.json @@ -49,13 +49,16 @@ "@aztec/sequencer-client": "link:../yarn-project/sequencer-client", "@aztec/p2p": "link:../yarn-project/p2p", "@aztec/wallets": "link:../yarn-project/wallets", - "@aztec/wallet-sdk": "link:../yarn-project/wallet-sdk" + "@aztec/wallet-sdk": "link:../yarn-project/wallet-sdk", + "rollup": "^4.59.0", + "node-forge": "^1.3.2", + "serialize-javascript": "^7.0.3" }, "dependencies": { "@inquirer/confirm": "^3.0.0", "@inquirer/input": "^2.0.0", "@inquirer/select": "^2.0.0", - "axios": "^1.12.0", + "axios": "^1.13.5", "commander": "^12.1.0", "ora": "^8.0.1", "pino": "^9.5.0", diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 828a41beba7b..fb0e88f1b274 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -46,7 +46,7 @@ __metadata: "@inquirer/confirm": "npm:^3.0.0" "@inquirer/input": "npm:^2.0.0" "@inquirer/select": "npm:^2.0.0" - axios: "npm:^1.12.0" + axios: "npm:^1.13.5" commander: "npm:^12.1.0" ora: "npm:^8.0.1" pino: "npm:^9.5.0" @@ -1698,142 +1698,177 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.41.1" +"@rollup/rollup-android-arm-eabi@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-android-arm64@npm:4.41.1" +"@rollup/rollup-android-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm64@npm:4.59.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-darwin-arm64@npm:4.41.1" +"@rollup/rollup-darwin-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-darwin-x64@npm:4.41.1" +"@rollup/rollup-darwin-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.59.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.41.1" +"@rollup/rollup-freebsd-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-freebsd-x64@npm:4.41.1" +"@rollup/rollup-freebsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.41.1" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.41.1" +"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.41.1" +"@rollup/rollup-linux-arm64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.41.1" +"@rollup/rollup-linux-arm64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.41.1" +"@rollup/rollup-linux-loong64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-powerpc64le-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-powerpc64le-gnu@npm:4.41.1" +"@rollup/rollup-linux-loong64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.41.1" +"@rollup/rollup-linux-ppc64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.41.1" +"@rollup/rollup-linux-riscv64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.41.1" +"@rollup/rollup-linux-s390x-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.41.1" +"@rollup/rollup-linux-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.41.1" +"@rollup/rollup-linux-x64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.41.1" +"@rollup/rollup-openbsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0" + conditions: os=openharmony & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.41.1" +"@rollup/rollup-win32-ia32-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.41.1": - version: 4.41.1 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.41.1" +"@rollup/rollup-win32-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -2138,13 +2173,20 @@ __metadata: languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:1.0.7, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": +"@types/estree@npm:*, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6": version: 1.0.7 resolution: "@types/estree@npm:1.0.7" checksum: 10c0/be815254316882f7c40847336cd484c3bc1c3e34f710d197160d455dc9d6d050ffbf4c3bc76585dba86f737f020ab20bdb137ebe0e9116b0c86c7c0342221b8c languageName: node linkType: hard +"@types/estree@npm:1.0.8": + version: 1.0.8 + resolution: "@types/estree@npm:1.0.8" + checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^5.0.0": version: 5.0.6 resolution: "@types/express-serve-static-core@npm:5.0.6" @@ -3342,7 +3384,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:~1.3.4, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -3420,15 +3462,15 @@ __metadata: languageName: node linkType: hard -"ajv@npm:8.12.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" +"ajv@npm:8.18.0": + version: 8.18.0 + resolution: "ajv@npm:8.18.0" dependencies: - fast-deep-equal: "npm:^3.1.1" + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" - uri-js: "npm:^4.2.2" - checksum: 10c0/ac4f72adf727ee425e049bc9d8b31d4a57e1c90da8d28bcd23d60781b12fcd6fc3d68db5df16994c57b78b94eed7988f5a6b482fd376dc5b084125e20a0a622e + checksum: 10c0/e7517c426173513a07391be951879932bdf3348feaebd2199f5b901c20f99d60db8cd1591502d4d551dc82f594e82a05c4fe1c70139b15b8937f7afeaed9532f languageName: node linkType: hard @@ -3752,14 +3794,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.12.0": - version: 1.12.2 - resolution: "axios@npm:1.12.2" +"axios@npm:^1.13.5": + version: 1.13.6 + resolution: "axios@npm:1.13.6" dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.4" + follow-redirects: "npm:^1.15.11" + form-data: "npm:^4.0.5" proxy-from-env: "npm:^1.1.0" - checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed + checksum: 10c0/51fb5af055c3b85662fa97df17d986ae2c37d13bf86d50b6bb36b6b3a2dec6966a1d3a14ab3774b71707b155ae3597ed9b7babdf1a1a863d1a31840cb8e7ec71 languageName: node linkType: hard @@ -3798,7 +3840,7 @@ __metadata: react-dom: "npm:^18.2.0" react-toastify: "npm:^10.0.4" resolve-typescript-plugin: "npm:^2.0.1" - serve: "npm:^14.2.1" + serve: "npm:^14.2.6" stream-browserify: "npm:^3.0.0" style-loader: "npm:^3.3.3" ts-jest: "npm:^29.4.0" @@ -4065,6 +4107,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^2.0.2": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -4649,7 +4700,7 @@ __metadata: languageName: node linkType: hard -"compressible@npm:~2.0.16, compressible@npm:~2.0.18": +"compressible@npm:~2.0.18": version: 2.0.18 resolution: "compressible@npm:2.0.18" dependencies: @@ -4658,18 +4709,18 @@ __metadata: languageName: node linkType: hard -"compression@npm:1.7.4": - version: 1.7.4 - resolution: "compression@npm:1.7.4" +"compression@npm:1.8.1": + version: 1.8.1 + resolution: "compression@npm:1.8.1" dependencies: - accepts: "npm:~1.3.5" - bytes: "npm:3.0.0" - compressible: "npm:~2.0.16" + bytes: "npm:3.1.2" + compressible: "npm:~2.0.18" debug: "npm:2.6.9" - on-headers: "npm:~1.0.2" - safe-buffer: "npm:5.1.2" + negotiator: "npm:~0.6.4" + on-headers: "npm:~1.1.0" + safe-buffer: "npm:5.2.1" vary: "npm:~1.1.2" - checksum: 10c0/138db836202a406d8a14156a5564fb1700632a76b6e7d1546939472895a5304f2b23c80d7a22bf44c767e87a26e070dbc342ea63bb45ee9c863354fa5556bbbc + checksum: 10c0/85114b0b91c16594dc8c671cd9b05ef5e465066a60e5a4ed8b4551661303559a896ed17bb72c4234c04064e078f6ca86a34b8690349499a43f6fc4b844475da4 languageName: node linkType: hard @@ -6400,7 +6451,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.6": +"follow-redirects@npm:^1.0.0": version: 1.15.9 resolution: "follow-redirects@npm:1.15.9" peerDependenciesMeta: @@ -6410,6 +6461,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.11": + version: 1.15.11 + resolution: "follow-redirects@npm:1.15.11" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343 + languageName: node + linkType: hard + "for-each@npm:^0.3.3, for-each@npm:^0.3.5": version: 0.3.5 resolution: "for-each@npm:0.3.5" @@ -6429,16 +6490,16 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.4": - version: 4.0.4 - resolution: "form-data@npm:4.0.4" +"form-data@npm:^4.0.5": + version: 4.0.5 + resolution: "form-data@npm:4.0.5" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" es-set-tostringtag: "npm:^2.1.0" hasown: "npm:^2.0.2" mime-types: "npm:^2.1.12" - checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695 + checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b languageName: node linkType: hard @@ -8754,12 +8815,12 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:3.1.5, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 languageName: node linkType: hard @@ -8773,20 +8834,20 @@ __metadata: linkType: hard "minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 + checksum: 10c0/4202718683815a7288b13e470160a4f9560cf392adef4f453927505817e01ef6b3476ecde13cfcaed17e7326dd3b69ad44eb2daeb19a217c5500f9277893f1d6 languageName: node linkType: hard "minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 languageName: node linkType: hard @@ -9011,10 +9072,10 @@ __metadata: languageName: node linkType: hard -"node-forge@npm:^1": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 10c0/e882819b251a4321f9fc1d67c85d1501d3004b4ee889af822fd07f64de3d1a8e272ff00b689570af0465d65d6bf5074df9c76e900e0aff23e60b847f2a46fbe8 +"node-forge@npm:^1.3.2": + version: 1.3.3 + resolution: "node-forge@npm:1.3.3" + checksum: 10c0/9c6f53b0ebb34865872cf62a35b0aef8fb337e2efc766626c2e3a0040f4c02933bf29a62ba999eb44a2aca73bd512c4eda22705a47b94654b9fb8ed53db9a1db languageName: node linkType: hard @@ -9233,6 +9294,13 @@ __metadata: languageName: node linkType: hard +"on-headers@npm:~1.1.0": + version: 1.1.0 + resolution: "on-headers@npm:1.1.0" + checksum: 10c0/2c3b6b0d68ec9adbd561dc2d61c9b14da8ac03d8a2f0fd9e97bdf0600c887d5d97f664ff3be6876cf40cda6e3c587d73a4745e10b426ac50c7664fc5a0dfc0a1 + languageName: node + linkType: hard + "once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" @@ -10381,31 +10449,36 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.20.0, rollup@npm:^4.34.9": - version: 4.41.1 - resolution: "rollup@npm:4.41.1" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.41.1" - "@rollup/rollup-android-arm64": "npm:4.41.1" - "@rollup/rollup-darwin-arm64": "npm:4.41.1" - "@rollup/rollup-darwin-x64": "npm:4.41.1" - "@rollup/rollup-freebsd-arm64": "npm:4.41.1" - "@rollup/rollup-freebsd-x64": "npm:4.41.1" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.41.1" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.41.1" - "@rollup/rollup-linux-arm64-gnu": "npm:4.41.1" - "@rollup/rollup-linux-arm64-musl": "npm:4.41.1" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.41.1" - "@rollup/rollup-linux-powerpc64le-gnu": "npm:4.41.1" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.41.1" - "@rollup/rollup-linux-riscv64-musl": "npm:4.41.1" - "@rollup/rollup-linux-s390x-gnu": "npm:4.41.1" - "@rollup/rollup-linux-x64-gnu": "npm:4.41.1" - "@rollup/rollup-linux-x64-musl": "npm:4.41.1" - "@rollup/rollup-win32-arm64-msvc": "npm:4.41.1" - "@rollup/rollup-win32-ia32-msvc": "npm:4.41.1" - "@rollup/rollup-win32-x64-msvc": "npm:4.41.1" - "@types/estree": "npm:1.0.7" +"rollup@npm:^4.59.0": + version: 4.59.0 + resolution: "rollup@npm:4.59.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.59.0" + "@rollup/rollup-android-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-x64": "npm:4.59.0" + "@rollup/rollup-freebsd-arm64": "npm:4.59.0" + "@rollup/rollup-freebsd-x64": "npm:4.59.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.59.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-loong64-musl": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-musl": "npm:4.59.0" + "@rollup/rollup-openbsd-x64": "npm:4.59.0" + "@rollup/rollup-openharmony-arm64": "npm:4.59.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.59.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.59.0" + "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: "@rollup/rollup-android-arm-eabi": @@ -10428,9 +10501,13 @@ __metadata: optional: true "@rollup/rollup-linux-arm64-musl": optional: true - "@rollup/rollup-linux-loongarch64-gnu": + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": optional: true - "@rollup/rollup-linux-powerpc64le-gnu": + "@rollup/rollup-linux-ppc64-gnu": + optional: true + "@rollup/rollup-linux-ppc64-musl": optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true @@ -10442,17 +10519,23 @@ __metadata: optional: true "@rollup/rollup-linux-x64-musl": optional: true + "@rollup/rollup-openbsd-x64": + optional: true + "@rollup/rollup-openharmony-arm64": + optional: true "@rollup/rollup-win32-arm64-msvc": optional: true "@rollup/rollup-win32-ia32-msvc": optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true "@rollup/rollup-win32-x64-msvc": optional: true fsevents: optional: true bin: rollup: dist/bin/rollup - checksum: 10c0/c4d5f2257320b50dc0e035e31d8d2f78d36b7015aef2f87cc984c0a1c97ffebf14337dddeb488b4b11ae798fea6486189b77e7cf677617dcf611d97db41ebfda + checksum: 10c0/f38742da34cfee5e899302615fa157aa77cb6a2a1495e5e3ce4cc9c540d3262e235bbe60caa31562bbfe492b01fdb3e7a8c43c39d842d3293bcf843123b766fc languageName: node linkType: hard @@ -10485,13 +10568,6 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 - languageName: node - linkType: hard - "safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" @@ -10499,6 +10575,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21 + languageName: node + linkType: hard + "safe-push-apply@npm:^1.0.0": version: 1.0.0 resolution: "safe-push-apply@npm:1.0.0" @@ -10618,27 +10701,25 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.2": - version: 6.0.2 - resolution: "serialize-javascript@npm:6.0.2" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 +"serialize-javascript@npm:^7.0.3": + version: 7.0.4 + resolution: "serialize-javascript@npm:7.0.4" + checksum: 10c0/f3da6f994c41306fbfabb55eefe280a46da05592939a84b0d95c84e296c92ba9e6a3d86cf7bbd71e7a59e1cfcd8481745910af109bedbd3ed853b444d32f9ee9 languageName: node linkType: hard -"serve-handler@npm:6.1.6": - version: 6.1.6 - resolution: "serve-handler@npm:6.1.6" +"serve-handler@npm:6.1.7": + version: 6.1.7 + resolution: "serve-handler@npm:6.1.7" dependencies: bytes: "npm:3.0.0" content-disposition: "npm:0.5.2" mime-types: "npm:2.1.18" - minimatch: "npm:3.1.2" + minimatch: "npm:3.1.5" path-is-inside: "npm:1.0.2" path-to-regexp: "npm:3.3.0" range-parser: "npm:1.2.0" - checksum: 10c0/1e1cb6bbc51ee32bc1505f2e0605bdc2e96605c522277c977b67f83be9d66bd1eec8604388714a4d728e036d86b629bc9aec02120ea030d3d2c3899d44696503 + checksum: 10c0/35afb68d81afd3c38d15792a5bc2451915b739bef2898a47ebd190db6a4e29846530ac00292b8008fe7297a819257c3948be2deaf4ffd32c96689e8947cf0ae9 languageName: node linkType: hard @@ -10669,24 +10750,24 @@ __metadata: languageName: node linkType: hard -"serve@npm:^14.2.1": - version: 14.2.4 - resolution: "serve@npm:14.2.4" +"serve@npm:^14.2.6": + version: 14.2.6 + resolution: "serve@npm:14.2.6" dependencies: "@zeit/schemas": "npm:2.36.0" - ajv: "npm:8.12.0" + ajv: "npm:8.18.0" arg: "npm:5.0.2" boxen: "npm:7.0.0" chalk: "npm:5.0.1" chalk-template: "npm:0.4.0" clipboardy: "npm:3.0.0" - compression: "npm:1.7.4" + compression: "npm:1.8.1" is-port-reachable: "npm:4.0.0" - serve-handler: "npm:6.1.6" + serve-handler: "npm:6.1.7" update-check: "npm:1.5.4" bin: serve: build/main.js - checksum: 10c0/93abecd6214228d529065040f7c0cbe541c1cc321c6a94b8a968f45a519bd9c46a9fd5e45a9b24a1f5736c5b547b8fa60d5414ebc78f870e29431b64165c1d06 + checksum: 10c0/7e1668e0d187719dbe4f3de967012ce2263c967f6135d9c630f803b0f173334e1442ab326fcc4c8e6cd4e293d8bd8c773aebab2746ecaa0fb1ab29a36079763b languageName: node linkType: hard diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index e38996d04e99..6d599bccc6b1 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -9,6 +9,21 @@ Aztec is in active development. Each version may introduce breaking changes that ## TBD +### [Aztec.js] `getPublicEvents` now returns an object instead of an array + +`getPublicEvents` now returns a `GetPublicEventsResult` object with `events` and `maxLogsHit` fields instead of a plain array. This enables pagination through large result sets using the new `afterLog` filter option. + +```diff +- const events = await getPublicEvents(node, MyContract.events.MyEvent, filter); ++ const { events } = await getPublicEvents(node, MyContract.events.MyEvent, filter); +``` + +The `maxLogsHit` flag indicates whether the log limit was reached, meaning more results may be available. You can use `afterLog` in the filter to fetch the next page. + +### [Aztec.nr] Removed `get_random_bytes` + +The `get_random_bytes` unconstrained function has been removed from `aztec::utils::random`. If you were using it, you can replace it with direct calls to the `random` oracle from `aztec::oracle::random` and convert to bytes yourself. + ### [Aztec.js] `simulate()`, `send()`, and deploy return types changed to always return objects All SDK interaction methods now return structured objects that include offchain output alongside the primary result. This affects `.simulate()`, `.send()`, deploy `.send()`, and `Wallet.sendTx()`. diff --git a/docs/examples/ts/aztecjs_advanced/index.ts b/docs/examples/ts/aztecjs_advanced/index.ts index bd138a88ff79..ec42567d43a0 100644 --- a/docs/examples/ts/aztecjs_advanced/index.ts +++ b/docs/examples/ts/aztecjs_advanced/index.ts @@ -278,7 +278,7 @@ async function pollForTransferEvents() { const currentBlock = await node.getBlockNumber(); if (currentBlock > lastProcessedBlock) { - const events = await getPublicEvents( + const { events } = await getPublicEvents( node, TokenContract.events.Transfer, { diff --git a/docs/package.json b/docs/package.json index 405e44c4837d..07ee97420804 100644 --- a/docs/package.json +++ b/docs/package.json @@ -91,7 +91,12 @@ "resolutions": { "tar-fs": "^3.1.1", "ws@npm:8.13.0": "npm:8.17.1", - "path-to-regexp@npm:^1.7.0": "npm:1.9.0" + "path-to-regexp@npm:^1.7.0": "npm:1.9.0", + "h3": "^1.15.5", + "node-forge": "^1.3.2", + "serve-handler": "^6.1.7", + "serialize-javascript": "^7.0.3", + "axios": "^1.13.5" }, "packageManager": "yarn@4.5.2" } diff --git a/docs/yarn.lock b/docs/yarn.lock index ed4abf35cf76..cadc2c58e266 100644 --- a/docs/yarn.lock +++ b/docs/yarn.lock @@ -9576,14 +9576,14 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.6.0, axios@npm:^1.6.8": - version: 1.12.2 - resolution: "axios@npm:1.12.2" +"axios@npm:^1.13.5": + version: 1.13.6 + resolution: "axios@npm:1.13.6" dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.4" + follow-redirects: "npm:^1.15.11" + form-data: "npm:^4.0.5" proxy-from-env: "npm:^1.1.0" - checksum: 10c0/80b063e318cf05cd33a4d991cea0162f3573481946f9129efb7766f38fde4c061c34f41a93a9f9521f02b7c9565ccbc197c099b0186543ac84a24580017adfed + checksum: 10c0/51fb5af055c3b85662fa97df17d986ae2c37d13bf86d50b6bb36b6b3a2dec6966a1d3a14ab3774b71707b155ae3597ed9b7babdf1a1a863d1a31840cb8e7ec71 languageName: node linkType: hard @@ -9980,6 +9980,15 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^2.0.2": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -14010,7 +14019,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.12.1, follow-redirects@npm:^1.15.6": +"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.12.1": version: 1.15.6 resolution: "follow-redirects@npm:1.15.6" peerDependenciesMeta: @@ -14020,6 +14029,16 @@ __metadata: languageName: node linkType: hard +"follow-redirects@npm:^1.15.11": + version: 1.15.11 + resolution: "follow-redirects@npm:1.15.11" + peerDependenciesMeta: + debug: + optional: true + checksum: 10c0/d301f430542520a54058d4aeeb453233c564aaccac835d29d15e050beb33f339ad67d9bddbce01739c5dc46a6716dbe3d9d0d5134b1ca203effa11a7ef092343 + languageName: node + linkType: hard + "foreground-child@npm:^3.1.0": version: 3.1.1 resolution: "foreground-child@npm:3.1.1" @@ -14037,16 +14056,16 @@ __metadata: languageName: node linkType: hard -"form-data@npm:^4.0.4": - version: 4.0.4 - resolution: "form-data@npm:4.0.4" +"form-data@npm:^4.0.5": + version: 4.0.5 + resolution: "form-data@npm:4.0.5" dependencies: asynckit: "npm:^0.4.0" combined-stream: "npm:^1.0.8" es-set-tostringtag: "npm:^2.1.0" hasown: "npm:^2.0.2" mime-types: "npm:^2.1.12" - checksum: 10c0/373525a9a034b9d57073e55eab79e501a714ffac02e7a9b01be1c820780652b16e4101819785e1e18f8d98f0aee866cc654d660a435c378e16a72f2e7cac9695 + checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b languageName: node linkType: hard @@ -14594,20 +14613,20 @@ __metadata: languageName: node linkType: hard -"h3@npm:^1.12.0, h3@npm:^1.15.3, h3@npm:^1.15.4": - version: 1.15.4 - resolution: "h3@npm:1.15.4" +"h3@npm:^1.15.5": + version: 1.15.5 + resolution: "h3@npm:1.15.5" dependencies: cookie-es: "npm:^1.2.2" crossws: "npm:^0.3.5" defu: "npm:^6.1.4" destr: "npm:^2.0.5" iron-webcrypto: "npm:^1.2.1" - node-mock-http: "npm:^1.0.2" + node-mock-http: "npm:^1.0.4" radix3: "npm:^1.1.2" - ufo: "npm:^1.6.1" + ufo: "npm:^1.6.3" uncrypto: "npm:^0.1.3" - checksum: 10c0/5182a722d01fe18af5cb62441aaa872b630f4e1ac2cf1782e1f442e65fdfddb85eb6723bf73a96184c2dc1f1e3771d713ef47c456a9a4e92c640b025ba91044c + checksum: 10c0/d36c05176555109aa0b42c520dc03350d5baa9fff5067075f0919920a80f966a53eff2785051203a4630f8472bec118e5e0187b186a3105eba3106087cb0ddb9 languageName: node linkType: hard @@ -18120,30 +18139,30 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:3.1.5, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 languageName: node linkType: hard "minimatch@npm:^5.1.0": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 10c0/3defdfd230914f22a8da203747c42ee3c405c39d4d37ffda284dac5e45b7e1f6c49aa8be606509002898e73091ff2a3bbfc59c2c6c71d4660609f63aa92f98e3 + checksum: 10c0/4202718683815a7288b13e470160a4f9560cf392adef4f453927505817e01ef6b3476ecde13cfcaed17e7326dd3b69ad44eb2daeb19a217c5500f9277893f1d6 languageName: node linkType: hard "minimatch@npm:^9.0.0, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 languageName: node linkType: hard @@ -18618,10 +18637,10 @@ __metadata: languageName: node linkType: hard -"node-forge@npm:^1, node-forge@npm:^1.3.1": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 10c0/e882819b251a4321f9fc1d67c85d1501d3004b4ee889af822fd07f64de3d1a8e272ff00b689570af0465d65d6bf5074df9c76e900e0aff23e60b847f2a46fbe8 +"node-forge@npm:^1.3.2": + version: 1.3.3 + resolution: "node-forge@npm:1.3.3" + checksum: 10c0/9c6f53b0ebb34865872cf62a35b0aef8fb337e2efc766626c2e3a0040f4c02933bf29a62ba999eb44a2aca73bd512c4eda22705a47b94654b9fb8ed53db9a1db languageName: node linkType: hard @@ -18656,10 +18675,10 @@ __metadata: languageName: node linkType: hard -"node-mock-http@npm:^1.0.2": - version: 1.0.3 - resolution: "node-mock-http@npm:1.0.3" - checksum: 10c0/663f2a13518fc89b0dc69f96ba4442b5d1ecbbf20a833283725c8d2d92286af1b634803822432985be5999317fd5f23edbf2a62335fe6dd38d6b19dd7b107559 +"node-mock-http@npm:^1.0.4": + version: 1.0.4 + resolution: "node-mock-http@npm:1.0.4" + checksum: 10c0/86e3f7453cf07ad6b8bd17cf89ff91d45f486a861cf6d891618cf29647d559cbcde1d1f90c9cc02e014ff9f7900b2fb21c96b03ea4b4a415dbe2d65badadceba languageName: node linkType: hard @@ -20869,15 +20888,6 @@ __metadata: languageName: node linkType: hard -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 - languageName: node - linkType: hard - "range-parser@npm:1.2.0": version: 1.2.0 resolution: "range-parser@npm:1.2.0" @@ -21956,7 +21966,7 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": +"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 @@ -22154,27 +22164,25 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.0, serialize-javascript@npm:^6.0.1": - version: 6.0.2 - resolution: "serialize-javascript@npm:6.0.2" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 +"serialize-javascript@npm:^7.0.3": + version: 7.0.4 + resolution: "serialize-javascript@npm:7.0.4" + checksum: 10c0/f3da6f994c41306fbfabb55eefe280a46da05592939a84b0d95c84e296c92ba9e6a3d86cf7bbd71e7a59e1cfcd8481745910af109bedbd3ed853b444d32f9ee9 languageName: node linkType: hard -"serve-handler@npm:^6.1.6": - version: 6.1.6 - resolution: "serve-handler@npm:6.1.6" +"serve-handler@npm:^6.1.7": + version: 6.1.7 + resolution: "serve-handler@npm:6.1.7" dependencies: bytes: "npm:3.0.0" content-disposition: "npm:0.5.2" mime-types: "npm:2.1.18" - minimatch: "npm:3.1.2" + minimatch: "npm:3.1.5" path-is-inside: "npm:1.0.2" path-to-regexp: "npm:3.3.0" range-parser: "npm:1.2.0" - checksum: 10c0/1e1cb6bbc51ee32bc1505f2e0605bdc2e96605c522277c977b67f83be9d66bd1eec8604388714a4d728e036d86b629bc9aec02120ea030d3d2c3899d44696503 + checksum: 10c0/35afb68d81afd3c38d15792a5bc2451915b739bef2898a47ebd190db6a4e29846530ac00292b8008fe7297a819257c3948be2deaf4ffd32c96689e8947cf0ae9 languageName: node linkType: hard @@ -23788,6 +23796,13 @@ __metadata: languageName: node linkType: hard +"ufo@npm:^1.6.3": + version: 1.6.3 + resolution: "ufo@npm:1.6.3" + checksum: 10c0/bf0e4ebff99e54da1b9c7182ac2f40475988b41faa881d579bc97bc2a0509672107b0a0e94c4b8d31a0ab8c4bf07f4aa0b469ac6da8536d56bda5b085ea2e953 + languageName: node + linkType: hard + "uid-safe@npm:2.1.5": version: 2.1.5 resolution: "uid-safe@npm:2.1.5" diff --git a/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr b/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr index b73fcb96e135..fa37326877f2 100644 --- a/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr +++ b/noir-projects/aztec-nr/aztec/src/messages/encryption/aes128.nr @@ -1,6 +1,6 @@ use crate::protocol::{ address::AztecAddress, - constants::{DOM_SEP__SYMMETRIC_KEY, DOM_SEP__SYMMETRIC_KEY_2}, + constants::{DOM_SEP__CIPHERTEXT_FIELD_MASK, DOM_SEP__SYMMETRIC_KEY, DOM_SEP__SYMMETRIC_KEY_2}, hash::poseidon2_hash_with_separator, point::Point, public_keys::AddressPoint, @@ -26,7 +26,6 @@ use crate::{ fields_to_bytes::{fields_from_bytes, fields_to_bytes}, }, point::point_from_x_coord_and_sign, - random::get_random_bytes, }, }; @@ -156,8 +155,9 @@ impl MessageEncryption for AES128 { /// ## Overview /// /// The plaintext is an array of up to `MESSAGE_PLAINTEXT_LEN` (12) fields. The output is always exactly - /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. Unused trailing fields are filled with - /// random data so that all encrypted messages are indistinguishable by size. + /// `MESSAGE_CIPHERTEXT_LEN` (15) fields, regardless of plaintext size. All output fields except the + /// ephemeral public key are uniformly random `Field` values to any observer without knowledge of the + /// shared secret, making all encrypted messages indistinguishable by size or content. /// /// ## PKCS#7 Padding /// @@ -204,27 +204,31 @@ impl MessageEncryption for AES128 { /// Messages are transmitted as fields, not bytes. A field is ~254 bits and can safely store 31 whole bytes, so /// we need to pack our byte data into 31-byte chunks. This packing drives the wire format. /// - /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with random bytes to a + /// **Step 1 -- Assemble bytes.** The ciphertexts are laid out in a byte array, padded with zero bytes to a /// multiple of 31 so it divides evenly into fields: /// /// ```text /// +------------+-------------------------+---------+ /// | header ct | body ct | byte pad| - /// | 16 B | PlaintextLen*32 + 16 B | (random)| + /// | 16 B | PlaintextLen*32 + 16 B | (zeros) | /// +------------+-------------------------+---------+ /// |<-------- padded to a multiple of 31 B -------->| /// ``` /// - /// **Step 2 -- Pack into fields.** The byte array is split into 31-byte chunks, each stored in one field. The - /// ephemeral public key x-coordinate is prepended as its own field. Any remaining fields (up to 15 total) are - /// filled with random data so that all messages are the same size: + /// **Step 2 -- Pack and mask.** The byte array is split into 31-byte chunks, each stored in one field. A + /// Poseidon2-derived mask (see `derive_field_mask`) is added to each so that the resulting fields appear as + /// uniformly random `Field` values to any observer without knowledge of the shared secret, hiding the fact + /// that the underlying ciphertext consists of 128-bit AES blocks. + /// + /// **Step 3 -- Assemble ciphertext.** The ephemeral public key x-coordinate is prepended and random field padding + /// is appended to fill to 15 fields: /// /// ```text /// +----------+-------------------------+-------------------+ - /// | eph_pk.x | message-byte fields | random field pad | - /// | | (packed 31 B per field) | (fills to 15) | + /// | eph_pk.x | masked message fields | random field pad | + /// | | (packed 31 B per field) | (fills to 15) | /// +----------+-------------------------+-------------------+ - /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields ------->| + /// |<---------- MESSAGE_CIPHERTEXT_LEN = 15 fields -------->| /// ``` /// /// ## Key Derivation @@ -304,11 +308,7 @@ impl MessageEncryption for AES128 { // Assemble the message byte array: // [header_ct (16B)] [body_ct] [padding to mult of 31] - let mut message_bytes_padding_to_mult_31 = - get_arr_of_size__message_bytes_padding__from_PT::(); - // Safety: this randomness won't be constrained to be random. It's in the interest of the executor of this fn - // to encrypt with random bytes. - message_bytes_padding_to_mult_31 = unsafe { get_random_bytes() }; + let message_bytes_padding_to_mult_31 = get_arr_of_size__message_bytes_padding__from_PT::(); let mut message_bytes = get_arr_of_size__message_bytes__from_PT::(); @@ -346,30 +346,26 @@ impl MessageEncryption for AES128 { assert(offset == message_bytes.len(), "unexpected encrypted message length"); // Pack message bytes into fields (31 bytes per field) and prepend eph_pk.x. - // TODO(#12749): As Mike pointed out, we need to make messages produced by different encryption schemes - // indistinguishable from each other and for this reason the output here and in the last for-loop of this - // function should cover a full field. let message_bytes_as_fields = bytes_to_fields(message_bytes); let mut ciphertext: [Field; MESSAGE_CIPHERTEXT_LEN] = [0; MESSAGE_CIPHERTEXT_LEN]; ciphertext[0] = eph_pk.x; + // Mask each content field with a Poseidon2-derived value, so that they appear as uniformly random `Field` + // values let mut offset = 1; for i in 0..message_bytes_as_fields.len() { - ciphertext[offset + i] = message_bytes_as_fields[i]; + let mask = derive_field_mask(ciphertext_shared_secret, i as u32); + ciphertext[offset + i] = message_bytes_as_fields[i] + mask; } offset += message_bytes_as_fields.len(); + // Pad with random fields so that padding is indistinguishable from masked data fields. for i in offset..MESSAGE_CIPHERTEXT_LEN { - // We need to get a random value that fits in 31 bytes to not leak information about the size of the - // message (all the "real" message fields contain at most 31 bytes because of the way we convert the bytes - // to fields). TODO(#12749): Long term, this is not a good solution. - // Safety: we assume that the sender wants for the message to be private - a malicious one could simply // reveal its contents publicly. It is therefore fine to trust the sender to provide random padding. - let field_bytes = unsafe { get_random_bytes::<31>() }; - ciphertext[i] = Field::from_be_bytes::<31>(field_bytes); + ciphertext[i] = unsafe { random() }; } ciphertext @@ -381,14 +377,11 @@ impl MessageEncryption for AES128 { ) -> Option> { let eph_pk_x = ciphertext.get(0); - let ciphertext_without_eph_pk_x_fields = array::subbvec::( + let masked_fields = array::subbvec::( ciphertext, EPH_PK_X_SIZE_IN_FIELDS, ); - // Convert the ciphertext represented as fields to a byte representation (its original format) - let ciphertext_without_eph_pk_x = bytes_from_fields(ciphertext_without_eph_pk_x_fields); - // With the x-coordinate of the ephemeral public key we can reconstruct the point as we know that the // y-coordinate must be positive. This may fail however, as not all x-coordinates are on the curve. In that // case, we simply return `Option::none`. @@ -396,6 +389,14 @@ impl MessageEncryption for AES128 { // Derive shared secret let ciphertext_shared_secret = get_shared_secret(recipient, eph_pk); + let unmasked_fields = masked_fields.mapi(|i, field| { + let unmasked = unmask_field(ciphertext_shared_secret, i, field); + // If we failed to unmask the field, we are dealing with the random padding. We'll ignore it later, + // so we can simply set it to 0 + unmasked.unwrap_or(0) + }); + let ciphertext_without_eph_pk_x = bytes_from_fields(unmasked_fields); + // Derive symmetric keys: let pairs = derive_aes_symmetric_key_and_iv_from_ecdh_shared_secret_using_poseidon2_unsafe::<2>( ciphertext_shared_secret, @@ -436,6 +437,30 @@ impl MessageEncryption for AES128 { } } +/// 2^248: upper bound for values that fit in 31 bytes +global TWO_POW_248: Field = 2.pow_32(248); + +/// Removes the Poseidon2-derived mask from a ciphertext field. Returns the unmasked value if it fits in 31 bytes +/// (a content field), or `None` if it doesn't (random padding). Unconstrained to prevent accidental use in +/// constrained context. +unconstrained fn unmask_field(shared_secret: Point, index: u32, masked: Field) -> Option { + let unmasked = masked - derive_field_mask(shared_secret, index); + if unmasked.lt(TWO_POW_248) { + Option::some(unmasked) + } else { + Option::none() + } +} + +/// Derives a field mask from an ECDH shared secret and field index. Applied only to data fields (those carrying +/// packed message bytes). Padding fields use `random()` instead. +fn derive_field_mask(shared_secret: Point, index: u32) -> Field { + poseidon2_hash_with_separator( + [shared_secret.x, shared_secret.y], + DOM_SEP__CIPHERTEXT_FIELD_MASK + index, + ) +} + /// Produces a random valid address point, i.e. one that is on the curve. This is equivalent to calling /// [`AztecAddress::to_address_point`] on a random valid address. unconstrained fn random_address_point() -> AddressPoint { diff --git a/noir-projects/aztec-nr/aztec/src/utils/mod.nr b/noir-projects/aztec-nr/aztec/src/utils/mod.nr index 0e1b8653a442..f708bd7ad09c 100644 --- a/noir-projects/aztec-nr/aztec/src/utils/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/utils/mod.nr @@ -4,7 +4,6 @@ pub mod array; pub mod comparison; pub mod conversion; pub mod point; -pub mod random; mod with_hash; pub use with_hash::WithHash; pub mod remove_constraints; diff --git a/noir-projects/aztec-nr/aztec/src/utils/random.nr b/noir-projects/aztec-nr/aztec/src/utils/random.nr deleted file mode 100644 index 6cb65f361058..000000000000 --- a/noir-projects/aztec-nr/aztec/src/utils/random.nr +++ /dev/null @@ -1,17 +0,0 @@ -use crate::oracle::random::random; - -/// Returns as many random bytes as specified through N. -pub unconstrained fn get_random_bytes() -> [u8; N] { - let mut bytes = [0; N]; - let mut idx = 32; - let mut randomness = [0; 32]; - for i in 0..N { - if idx == 32 { - randomness = random().to_be_bytes(); - idx = 1; // Skip the first byte as it's always 0. - } - bytes[i] = randomness[idx]; - idx += 1; - } - bytes -} diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 43817825a1a2..7b7c76bf8bad 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -51,6 +51,7 @@ members = [ "contracts/test/note_getter_contract", "contracts/test/offchain_effect_contract", "contracts/test/only_self_contract", + "contracts/test/option_param_contract", "contracts/test/oracle_version_check_contract", "contracts/test/parent_contract", "contracts/test/pending_note_hashes_contract", diff --git a/noir-projects/noir-contracts/contracts/test/option_param_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/test/option_param_contract/Nargo.toml new file mode 100644 index 000000000000..7f4a4e434f0d --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/option_param_contract/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "option_param_contract" +authors = [""] +compiler_version = ">=0.25.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts/contracts/test/option_param_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test/option_param_contract/src/main.nr new file mode 100644 index 000000000000..a30e26bbed67 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/option_param_contract/src/main.nr @@ -0,0 +1,33 @@ +mod test; + +use aztec::macros::aztec; + +#[aztec] +pub contract OptionParam { + use aztec::{macros::functions::external, protocol::traits::{Deserialize, Serialize}}; + + #[derive(Serialize, Deserialize, Eq)] + pub struct SomeStruct { + pub w: Field, + pub x: bool, + pub y: u64, + pub z: i64, + } + + #[external("public")] + fn return_public_optional_struct(value: Option) -> Option { + value + } + + #[external("private")] + fn return_private_optional_struct(value: Option) -> Option { + value + } + + #[external("utility")] + unconstrained fn return_utility_optional_struct( + value: Option, + ) -> Option { + value + } +} diff --git a/noir-projects/noir-contracts/contracts/test/option_param_contract/src/test.nr b/noir-projects/noir-contracts/contracts/test/option_param_contract/src/test.nr new file mode 100644 index 000000000000..816f461b1448 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/test/option_param_contract/src/test.nr @@ -0,0 +1,77 @@ +use crate::OptionParam; +use crate::OptionParam::SomeStruct; +use aztec::{protocol::constants::MAX_FIELD_VALUE, test::helpers::test_environment::TestEnvironment}; + +global U64_MAX: u64 = (2.pow_32(64) - 1) as u64; +global I64_MAX: i64 = (2.pow_32(63) - 1) as i64; + +#[test] +unconstrained fn passes_public_optional_struct_parameter() { + let mut env = TestEnvironment::new(); + let sender = env.create_light_account(); + + let option_param = OptionParam::at(env.deploy("OptionParam").without_initializer()); + + let none_value = + env.call_public(sender, option_param.return_public_optional_struct(Option::none())); + assert_eq(none_value, Option::none()); + + let some_value = env.call_public( + sender, + option_param.return_public_optional_struct(Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + )), + ); + assert_eq( + some_value, + Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + ), + ); +} + +#[test] +unconstrained fn passes_utility_optional_struct_parameter() { + let mut env = TestEnvironment::new(); + + let option_param = OptionParam::at(env.deploy("OptionParam").without_initializer()); + + let none_value = + env.execute_utility(option_param.return_utility_optional_struct(Option::none())); + assert_eq(none_value, Option::none()); + + let some_value = env.execute_utility(option_param.return_utility_optional_struct(Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + ))); + assert_eq( + some_value, + Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + ), + ); +} + +#[test] +unconstrained fn passes_private_optional_struct_parameter() { + let mut env = TestEnvironment::new(); + let sender = env.create_light_account(); + + let option_param = OptionParam::at(env.deploy("OptionParam").without_initializer()); + + let none_value = + env.call_private(sender, option_param.return_private_optional_struct(Option::none())); + assert_eq(none_value, Option::none()); + + let some_value = env.call_private( + sender, + option_param.return_private_optional_struct(Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + )), + ); + assert_eq( + some_value, + Option::some( + SomeStruct { w: MAX_FIELD_VALUE, x: true, y: U64_MAX, z: I64_MAX }, + ), + ); +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 33eebf46284e..6100302d21ee 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -705,6 +705,7 @@ pub global DOM_SEP__AUTHWIT_NULLIFIER: u32 = 1239150694; pub global DOM_SEP__SYMMETRIC_KEY: u32 = 3882206064; pub global DOM_SEP__SYMMETRIC_KEY_2: u32 = 4129434989; +pub global DOM_SEP__CIPHERTEXT_FIELD_MASK: u32 = 1870492847; pub global DOM_SEP__PARTIAL_NOTE_VALIDITY_COMMITMENT: u32 = 623934423; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants_tests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants_tests.nr index 699edf5b8b84..6f7c9dee1cc1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants_tests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants_tests.nr @@ -7,19 +7,19 @@ use crate::{ CONTRACT_CLASS_REGISTRY_UTILITY_FUNCTION_BROADCASTED_MAGIC_VALUE, CONTRACT_INSTANCE_PUBLISHED_MAGIC_VALUE, CONTRACT_INSTANCE_UPDATED_MAGIC_VALUE, DOM_SEP__AUTHWIT_INNER, DOM_SEP__AUTHWIT_NULLIFIER, DOM_SEP__AUTHWIT_OUTER, - DOM_SEP__BLOCK_HEADER_HASH, DOM_SEP__CONTRACT_ADDRESS_V1, DOM_SEP__CONTRACT_CLASS_ID, - DOM_SEP__EVENT_COMMITMENT, DOM_SEP__FUNCTION_ARGS, DOM_SEP__INITIALIZATION_NULLIFIER, - DOM_SEP__INITIALIZER, DOM_SEP__IVSK_M, DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__NHK_M, - DOM_SEP__NOTE_HASH, DOM_SEP__NOTE_HASH_NONCE, DOM_SEP__NOTE_NULLIFIER, DOM_SEP__OVSK_M, - DOM_SEP__PARTIAL_ADDRESS, DOM_SEP__PARTIAL_NOTE_VALIDITY_COMMITMENT, - DOM_SEP__PRIVATE_FUNCTION_LEAF, DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__PRIVATE_TX_HASH, - DOM_SEP__PROTOCOL_CONTRACTS, DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA, - DOM_SEP__PUBLIC_KEYS_HASH, DOM_SEP__PUBLIC_LEAF_SLOT, DOM_SEP__PUBLIC_STORAGE_MAP_SLOT, - DOM_SEP__PUBLIC_TX_HASH, DOM_SEP__SECRET_HASH, DOM_SEP__SIGNATURE_PAYLOAD, - DOM_SEP__SILOED_NOTE_HASH, DOM_SEP__SILOED_NULLIFIER, DOM_SEP__SYMMETRIC_KEY, - DOM_SEP__SYMMETRIC_KEY_2, DOM_SEP__TSK_M, DOM_SEP__TX_NULLIFIER, DOM_SEP__TX_REQUEST, - DOM_SEP__UNIQUE_NOTE_HASH, NULL_MSG_SENDER_CONTRACT_ADDRESS, SIDE_EFFECT_MASKING_ADDRESS, - TX_START_PREFIX, + DOM_SEP__BLOCK_HEADER_HASH, DOM_SEP__CIPHERTEXT_FIELD_MASK, DOM_SEP__CONTRACT_ADDRESS_V1, + DOM_SEP__CONTRACT_CLASS_ID, DOM_SEP__EVENT_COMMITMENT, DOM_SEP__FUNCTION_ARGS, + DOM_SEP__INITIALIZATION_NULLIFIER, DOM_SEP__INITIALIZER, DOM_SEP__IVSK_M, + DOM_SEP__MESSAGE_NULLIFIER, DOM_SEP__NHK_M, DOM_SEP__NOTE_HASH, DOM_SEP__NOTE_HASH_NONCE, + DOM_SEP__NOTE_NULLIFIER, DOM_SEP__OVSK_M, DOM_SEP__PARTIAL_ADDRESS, + DOM_SEP__PARTIAL_NOTE_VALIDITY_COMMITMENT, DOM_SEP__PRIVATE_FUNCTION_LEAF, + DOM_SEP__PRIVATE_LOG_FIRST_FIELD, DOM_SEP__PRIVATE_TX_HASH, DOM_SEP__PROTOCOL_CONTRACTS, + DOM_SEP__PUBLIC_BYTECODE, DOM_SEP__PUBLIC_CALLDATA, DOM_SEP__PUBLIC_KEYS_HASH, + DOM_SEP__PUBLIC_LEAF_SLOT, DOM_SEP__PUBLIC_STORAGE_MAP_SLOT, DOM_SEP__PUBLIC_TX_HASH, + DOM_SEP__SECRET_HASH, DOM_SEP__SIGNATURE_PAYLOAD, DOM_SEP__SILOED_NOTE_HASH, + DOM_SEP__SILOED_NULLIFIER, DOM_SEP__SYMMETRIC_KEY, DOM_SEP__SYMMETRIC_KEY_2, DOM_SEP__TSK_M, + DOM_SEP__TX_NULLIFIER, DOM_SEP__TX_REQUEST, DOM_SEP__UNIQUE_NOTE_HASH, + NULL_MSG_SENDER_CONTRACT_ADDRESS, SIDE_EFFECT_MASKING_ADDRESS, TX_START_PREFIX, }, hash::poseidon2_hash_bytes, traits::{FromField, ToField}, @@ -129,7 +129,7 @@ impl HashedValueTester::new(); + let mut tester = HashedValueTester::<50, 43>::new(); // ----------------- // Domain separators @@ -174,6 +174,7 @@ fn hashed_values_match_derived() { tester.assert_dom_sep_matches_derived(DOM_SEP__AUTHWIT_NULLIFIER, "authwit_nullifier"); tester.assert_dom_sep_matches_derived(DOM_SEP__SYMMETRIC_KEY, "symmetric_key"); tester.assert_dom_sep_matches_derived(DOM_SEP__SYMMETRIC_KEY_2, "symmetric_key_2"); + tester.assert_dom_sep_matches_derived(DOM_SEP__CIPHERTEXT_FIELD_MASK, "ciphertext_field_mask"); tester.assert_dom_sep_matches_derived( DOM_SEP__PARTIAL_NOTE_VALIDITY_COMMITMENT, "partial_note_validity_commitment", diff --git a/playground/package.json b/playground/package.json index 0cda90a8c0b0..6dbf4f3fa98a 100644 --- a/playground/package.json +++ b/playground/package.json @@ -60,5 +60,8 @@ "vite": "^7.1.4", "vite-plugin-node-polyfills": "^0.24.0", "vite-plugin-static-copy": "^3.1.2" + }, + "resolutions": { + "rollup": "^4.59.0" } } diff --git a/playground/yarn.lock b/playground/yarn.lock index 49f5556b80b9..b35c390cd3df 100644 --- a/playground/yarn.lock +++ b/playground/yarn.lock @@ -1202,149 +1202,177 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.50.1" +"@rollup/rollup-android-arm-eabi@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-android-arm64@npm:4.50.1" +"@rollup/rollup-android-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm64@npm:4.59.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-darwin-arm64@npm:4.50.1" +"@rollup/rollup-darwin-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-darwin-x64@npm:4.50.1" +"@rollup/rollup-darwin-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.59.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.50.1" +"@rollup/rollup-freebsd-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-freebsd-x64@npm:4.50.1" +"@rollup/rollup-freebsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.50.1" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.50.1" +"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.50.1" +"@rollup/rollup-linux-arm64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.50.1" +"@rollup/rollup-linux-arm64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loongarch64-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-loongarch64-gnu@npm:4.50.1" +"@rollup/rollup-linux-loong64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.50.1" +"@rollup/rollup-linux-loong64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.50.1" +"@rollup/rollup-linux-ppc64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.50.1" +"@rollup/rollup-linux-riscv64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.50.1" +"@rollup/rollup-linux-s390x-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.50.1" +"@rollup/rollup-linux-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.50.1" +"@rollup/rollup-linux-x64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.50.1" +"@rollup/rollup-openbsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.50.1" +"@rollup/rollup-win32-arm64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.50.1" +"@rollup/rollup-win32-ia32-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.50.1": - version: 4.50.1 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.50.1" +"@rollup/rollup-win32-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0" + conditions: os=win32 & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -2106,12 +2134,12 @@ __metadata: languageName: node linkType: hard -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" +"brace-expansion@npm:^2.0.2": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" dependencies: balanced-match: "npm:^1.0.0" - checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f + checksum: 10c0/6d117a4c793488af86b83172deb6af143e94c17bc53b0b3cec259733923b4ca84679d506ac261f4ba3c7ed37c46018e2ff442f9ce453af8643ecd64f4a54e6cf languageName: node linkType: hard @@ -4408,20 +4436,20 @@ __metadata: linkType: hard "minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 + checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70 languageName: node linkType: hard "minimatch@npm:^9.0.4": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10c0/de96cf5e35bdf0eab3e2c853522f98ffbe9a36c37797778d2665231ec1f20a9447a7e567cb640901f89e4daaa95ae5d70c65a9e8aa2bb0019b6facbc3c0575ed + brace-expansion: "npm:^2.0.2" + checksum: 10c0/0b6a58530dbb00361745aa6c8cffaba4c90f551afe7c734830bd95fd88ebf469dd7355a027824ea1d09e37181cfeb0a797fb17df60c15ac174303ac110eb7e86 languageName: node linkType: hard @@ -5341,31 +5369,35 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.43.0": - version: 4.50.1 - resolution: "rollup@npm:4.50.1" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.50.1" - "@rollup/rollup-android-arm64": "npm:4.50.1" - "@rollup/rollup-darwin-arm64": "npm:4.50.1" - "@rollup/rollup-darwin-x64": "npm:4.50.1" - "@rollup/rollup-freebsd-arm64": "npm:4.50.1" - "@rollup/rollup-freebsd-x64": "npm:4.50.1" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.50.1" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.50.1" - "@rollup/rollup-linux-arm64-gnu": "npm:4.50.1" - "@rollup/rollup-linux-arm64-musl": "npm:4.50.1" - "@rollup/rollup-linux-loongarch64-gnu": "npm:4.50.1" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.50.1" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.50.1" - "@rollup/rollup-linux-riscv64-musl": "npm:4.50.1" - "@rollup/rollup-linux-s390x-gnu": "npm:4.50.1" - "@rollup/rollup-linux-x64-gnu": "npm:4.50.1" - "@rollup/rollup-linux-x64-musl": "npm:4.50.1" - "@rollup/rollup-openharmony-arm64": "npm:4.50.1" - "@rollup/rollup-win32-arm64-msvc": "npm:4.50.1" - "@rollup/rollup-win32-ia32-msvc": "npm:4.50.1" - "@rollup/rollup-win32-x64-msvc": "npm:4.50.1" +"rollup@npm:^4.59.0": + version: 4.59.0 + resolution: "rollup@npm:4.59.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.59.0" + "@rollup/rollup-android-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-x64": "npm:4.59.0" + "@rollup/rollup-freebsd-arm64": "npm:4.59.0" + "@rollup/rollup-freebsd-x64": "npm:4.59.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.59.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-loong64-musl": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-musl": "npm:4.59.0" + "@rollup/rollup-openbsd-x64": "npm:4.59.0" + "@rollup/rollup-openharmony-arm64": "npm:4.59.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.59.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.59.0" "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -5389,10 +5421,14 @@ __metadata: optional: true "@rollup/rollup-linux-arm64-musl": optional: true - "@rollup/rollup-linux-loongarch64-gnu": + "@rollup/rollup-linux-loong64-gnu": + optional: true + "@rollup/rollup-linux-loong64-musl": optional: true "@rollup/rollup-linux-ppc64-gnu": optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true "@rollup/rollup-linux-riscv64-musl": @@ -5403,19 +5439,23 @@ __metadata: optional: true "@rollup/rollup-linux-x64-musl": optional: true + "@rollup/rollup-openbsd-x64": + optional: true "@rollup/rollup-openharmony-arm64": optional: true "@rollup/rollup-win32-arm64-msvc": optional: true "@rollup/rollup-win32-ia32-msvc": optional: true + "@rollup/rollup-win32-x64-gnu": + optional: true "@rollup/rollup-win32-x64-msvc": optional: true fsevents: optional: true bin: rollup: dist/bin/rollup - checksum: 10c0/2029282826d5fb4e308be261b2c28329a4d2bd34304cc3960da69fd21d5acccd0267d6770b1656ffc8f166203ef7e865b4583d5f842a519c8ef059ac71854205 + checksum: 10c0/f38742da34cfee5e899302615fa157aa77cb6a2a1495e5e3ce4cc9c540d3262e235bbe60caa31562bbfe492b01fdb3e7a8c43c39d842d3293bcf843123b766fc languageName: node linkType: hard diff --git a/spartan/.gitignore b/spartan/.gitignore index 792fa0ebb8b7..6fbca9faac92 100644 --- a/spartan/.gitignore +++ b/spartan/.gitignore @@ -29,4 +29,5 @@ environments/* !environments/tps-scenario.env !environments/kind-minimal.env !environments/kind-provers.env +!environments/alpha-net.env *.tfvars diff --git a/spartan/environments/alpha-net.env b/spartan/environments/alpha-net.env new file mode 100644 index 000000000000..2426e3292db3 --- /dev/null +++ b/spartan/environments/alpha-net.env @@ -0,0 +1,90 @@ +NAMESPACE=${NAMESPACE:-alpha-net} +CLUSTER=aztec-gke-private +GCP_REGION=us-west1-a +DESTROY_NAMESPACE=true +DESTROY_ETH_DEVNET=true +CREATE_ETH_DEVNET=${CREATE_ETH_DEVNET:-true} +AZTEC_EPOCH_DURATION=8 +AZTEC_SLOT_DURATION=72 +AZTEC_PROOF_SUBMISSION_EPOCHS=2 +ETHEREUM_CHAIN_ID=1337 +LABS_INFRA_MNEMONIC="test test test test test test test test test test test junk" +FUNDING_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" +# CREATE_CHAOS_MESH=true + +# Install chaos mesh peer isolation after Aztec infra deploys. Validators, +# RPC nodes, and prover nodes can only peer with full-nodes, not each other. +# Requires P2P_PUBLIC_IP=false so P2P uses pod IPs that iptables rules can match. +P2P_PUBLIC_IP=false +CHAOS_MESH_SCENARIOS_FILE=network-requirements.yaml + +AZTEC_MANA_TARGET=2147483647 + +P2P_TX_POOL_DELETE_TXS_AFTER_REORG=true + +# For mbps +SEQ_BUILD_CHECKPOINT_IF_EMPTY=true +SEQ_BLOCK_DURATION_MS=6000 +SEQ_SKIP_CHECKPOINT_PUBLISH_PERCENT=5 + +CREATE_ROLLUP_CONTRACTS=true +REDEPLOY_ROLLUP_CONTRACTS=true +VERIFY_CONTRACTS=false +DESTROY_AZTEC_INFRA=true + +AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 +AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 + +OTEL_COLLECTOR_ENDPOINT=REPLACE_WITH_GCP_SECRET + +VALIDATOR_REPLICAS=12 +VALIDATORS_PER_NODE=4 +PUBLISHERS_PER_VALIDATOR_KEY=2 +VALIDATOR_PUBLISHER_MNEMONIC_START_INDEX=5000 +VALIDATOR_RESOURCE_PROFILE="2-core-dedicated" + +REAL_VERIFIER=false + +RPC_REPLICAS=12 +RPC_INGRESS_ENABLED=false + +FULL_NODE_REPLICAS=500 +FULL_NODE_RESOURCE_PROFILE="2-core-spot" + +PUBLISHERS_PER_PROVER=2 +PROVER_PUBLISHER_MNEMONIC_START_INDEX=8000 +PROVER_REPLICAS=128 +PROVER_RESOURCE_PROFILE="hi-tps" +PROVER_AGENT_POLL_INTERVAL_MS=10000 + +RUN_TESTS=false + +PROVER_TEST_DELAY_TYPE=fixed + +AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS=1 +AZTEC_SLASHING_QUORUM=5 +AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS=0 +AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 +AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 +SPONSORED_FPC=true + +SEQ_MAX_TX_PER_CHECKPOINT=72 +SEQ_MIN_TX_PER_BLOCK=0 + +# Override L1 tx utils bump percentages for scenario tests +VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 +VALIDATOR_L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE=0 +PROVER_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 +PROVER_L1_PRIORITY_FEE_RETRY_BUMP_PERCENTAGE=0 + +# Enable latency mesaruement for p2p messages +DEBUG_P2P_INSTRUMENT_MESSAGES=true + +# Inject artificial delay of proof verification for all nodes +PROVER_TEST_VERIFICATION_DELAY_MS=250 + +# Reduce the amount of metrics produced by prover agents and full nodes +PROVER_AGENT_INCLUDE_METRICS="aztec.circuit" +FULL_NODE_INCLUDE_METRICS="aztec.p2p.gossip.agg_" +LOG_LEVEL=info + diff --git a/spartan/environments/devnet.env b/spartan/environments/devnet.env index 07479bd312b9..a1a1020ea41c 100644 --- a/spartan/environments/devnet.env +++ b/spartan/environments/devnet.env @@ -54,7 +54,7 @@ VALIDATOR_MNEMONIC_START_INDEX=$((1 + MNEMONIC_INDEX_OFFSET)) VALIDATOR_INDICES=$(seq -s ',' $VALIDATOR_MNEMONIC_START_INDEX $((VALIDATOR_MNEMONIC_START_INDEX + TOTAL_VALIDATORS - 1))) VALIDATOR_PUBLISHER_MNEMONIC_START_INDEX=$((5000 + MNEMONIC_INDEX_OFFSET)) PUBLISHERS_PER_VALIDATOR_KEY=1 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 SEQ_MAX_TX_PER_BLOCK=32 PROVER_PUBLISHER_MNEMONIC_START_INDEX=$((8000 + MNEMONIC_INDEX_OFFSET)) diff --git a/spartan/environments/five-tps-long-epoch.env b/spartan/environments/five-tps-long-epoch.env index b5944eb481af..470d2c0c9478 100644 --- a/spartan/environments/five-tps-long-epoch.env +++ b/spartan/environments/five-tps-long-epoch.env @@ -56,7 +56,7 @@ AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 SEQ_MAX_TX_PER_CHECKPOINT=180 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 # Override L1 tx utils bump percentages for scenario tests VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 diff --git a/spartan/environments/five-tps-short-epoch.env b/spartan/environments/five-tps-short-epoch.env index 503f4d1b0856..36cdaa7a6cfd 100644 --- a/spartan/environments/five-tps-short-epoch.env +++ b/spartan/environments/five-tps-short-epoch.env @@ -56,7 +56,7 @@ AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 SEQ_MAX_TX_PER_CHECKPOINT=180 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 # Override L1 tx utils bump percentages for scenario tests VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 diff --git a/spartan/environments/network-defaults.yml b/spartan/environments/network-defaults.yml index 6f14c3a02b9c..ffaa61ab4f97 100644 --- a/spartan/environments/network-defaults.yml +++ b/spartan/environments/network-defaults.yml @@ -170,7 +170,7 @@ _prodlike: &prodlike # Sequencer Configuration #--------------------------------------------------------------------------- # Minimum transactions to include in a block. - SEQ_MIN_TX_PER_BLOCK: 0 + SEQ_MIN_TX_PER_BLOCK: 1 # Maximum transactions to include in a block # Build checkpoint even if block is empty. SEQ_BUILD_CHECKPOINT_IF_EMPTY: true @@ -272,7 +272,7 @@ networks: L1_CHAIN_ID: 11155111 # Sepolia # Genesis state TEST_ACCOUNTS: false - SPONSORED_FPC: true + SPONSORED_FPC: false TRANSACTIONS_DISABLED: false # Sequencer SEQ_MAX_TX_PER_CHECKPOINT: 72 # 1 TPS diff --git a/spartan/environments/next-net.env b/spartan/environments/next-net.env index 214785578995..98a8c1941d4b 100644 --- a/spartan/environments/next-net.env +++ b/spartan/environments/next-net.env @@ -28,7 +28,7 @@ L1_TX_FAILED_STORE=gs://aztec-develop/next-net/failed-l1-txs TEST_ACCOUNTS=true SPONSORED_FPC=true -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 SEQ_MAX_TX_PER_CHECKPOINT=7 diff --git a/spartan/environments/next-scenario.env b/spartan/environments/next-scenario.env index 4001068b19b6..22f042386566 100644 --- a/spartan/environments/next-scenario.env +++ b/spartan/environments/next-scenario.env @@ -13,8 +13,8 @@ DESTROY_AZTEC_INFRA=true VERIFY_CONTRACTS=false USE_LOAD_BALANCERS=true -AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=2 -AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=2 +AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 +AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 OTEL_COLLECTOR_ENDPOINT=REPLACE_WITH_GCP_SECRET @@ -36,6 +36,7 @@ AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS=1 AZTEC_SLASHING_QUORUM=17 AZTEC_SLASHING_OFFSET_IN_ROUNDS=2 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 +SPONSORED_FPC=true AZTEC_GOVERNANCE_PROPOSER_QUORUM=11 AZTEC_GOVERNANCE_PROPOSER_ROUND_SIZE=20 diff --git a/spartan/environments/prove-n-tps-fake.env b/spartan/environments/prove-n-tps-fake.env index 89cdcce263a2..773a500db927 100644 --- a/spartan/environments/prove-n-tps-fake.env +++ b/spartan/environments/prove-n-tps-fake.env @@ -7,6 +7,8 @@ AZTEC_SLOT_DURATION=72 AZTEC_PROOF_SUBMISSION_EPOCHS=1 AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 +AZTEC_MANA_TARGET=1000000000 # 1B mana +SPONSORED_FPC=true CREATE_ETH_DEVNET=true DESTROY_NAMESPACE=true @@ -30,7 +32,7 @@ REAL_VERIFIER=false RPC_REPLICAS=1 RPC_INGRESS_ENABLED=false -PROVER_REPLICAS=200 +PROVER_REPLICAS=10 PROVER_RESOURCE_PROFILE="hi-tps" PROVER_PUBLISHER_MNEMONIC_START_INDEX=8000 PROVER_AGENT_POLL_INTERVAL_MS=10000 @@ -40,7 +42,10 @@ PROVER_TEST_DELAY_TYPE=realistic PROVER_TEST_VERIFICATION_DELAY_MS=250 SEQ_MAX_TX_PER_CHECKPOINT=80 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_BLOCK_DURATION_MS=6000 +SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT=36 +SEQ_BUILD_CHECKPOINT_IF_EMPTY=true +SEQ_MIN_TX_PER_BLOCK=1 P2P_MAX_TX_POOL_SIZE=1000000000 DEBUG_P2P_INSTRUMENT_MESSAGES=true diff --git a/spartan/environments/prove-n-tps-real.env b/spartan/environments/prove-n-tps-real.env index 962def7f71a8..57dcdbf6a057 100644 --- a/spartan/environments/prove-n-tps-real.env +++ b/spartan/environments/prove-n-tps-real.env @@ -8,6 +8,7 @@ AZTEC_PROOF_SUBMISSION_EPOCHS=1 AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 AZTEC_MANA_TARGET=1000000000 # 1B mana +SPONSORED_FPC=true CREATE_ETH_DEVNET=true DESTROY_NAMESPACE=true @@ -38,7 +39,7 @@ PROVER_AGENT_POLL_INTERVAL_MS=10000 PUBLISHERS_PER_PROVER=1 SEQ_MAX_TX_PER_CHECKPOINT=72 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 SEQ_BLOCK_DURATION_MS=6000 SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT=36 SEQ_BUILD_CHECKPOINT_IF_EMPTY=true diff --git a/spartan/environments/scenario.local.env b/spartan/environments/scenario.local.env index 90402965d516..8fcc338a7183 100644 --- a/spartan/environments/scenario.local.env +++ b/spartan/environments/scenario.local.env @@ -20,6 +20,7 @@ AZTEC_SLASH_AMOUNT_MEDIUM=10000000000000000000 AZTEC_SLASH_AMOUNT_LARGE=15000000000000000000 AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=2 AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=2 +SPONSORED_FPC=true R2_ACCESS_KEY_ID="" R2_SECRET_ACCESS_KEY="" diff --git a/spartan/environments/staging-public.env b/spartan/environments/staging-public.env index 9bbdd78887b6..fd3c5b52df47 100644 --- a/spartan/environments/staging-public.env +++ b/spartan/environments/staging-public.env @@ -25,7 +25,7 @@ R2_SECRET_ACCESS_KEY=REPLACE_WITH_GCP_SECRET TEST_ACCOUNTS=false SPONSORED_FPC=true -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 SEQ_MAX_TX_PER_CHECKPOINT=7 # 0.1 TPS # Build checkpoint even if block is empty. diff --git a/spartan/environments/ten-tps-long-epoch.env b/spartan/environments/ten-tps-long-epoch.env index 8b8b4679c489..c2e9526e3812 100644 --- a/spartan/environments/ten-tps-long-epoch.env +++ b/spartan/environments/ten-tps-long-epoch.env @@ -21,6 +21,7 @@ DESTROY_AZTEC_INFRA=true AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 +SPONSORED_FPC=true OTEL_COLLECTOR_ENDPOINT=REPLACE_WITH_GCP_SECRET @@ -56,7 +57,7 @@ AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 SEQ_MAX_TX_PER_CHECKPOINT=360 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 # Override L1 tx utils bump percentages for scenario tests VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 diff --git a/spartan/environments/ten-tps-short-epoch.env b/spartan/environments/ten-tps-short-epoch.env index 86585811d876..8b2cae135c58 100644 --- a/spartan/environments/ten-tps-short-epoch.env +++ b/spartan/environments/ten-tps-short-epoch.env @@ -21,6 +21,7 @@ DESTROY_AZTEC_INFRA=true AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET=1 AZTEC_LAG_IN_EPOCHS_FOR_RANDAO=1 +SPONSORED_FPC=true OTEL_COLLECTOR_ENDPOINT=REPLACE_WITH_GCP_SECRET @@ -56,7 +57,7 @@ AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 SEQ_MAX_TX_PER_CHECKPOINT=360 -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 # Override L1 tx utils bump percentages for scenario tests VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 diff --git a/spartan/environments/tps-scenario.env b/spartan/environments/tps-scenario.env index a9b025f7f4e1..2708bc78ce82 100644 --- a/spartan/environments/tps-scenario.env +++ b/spartan/environments/tps-scenario.env @@ -6,6 +6,7 @@ AZTEC_EPOCH_DURATION=8 AZTEC_SLOT_DURATION=72 AZTEC_PROOF_SUBMISSION_EPOCHS=2 AZTEC_LAG_IN_EPOCHS=1 +SPONSORED_FPC=true CREATE_ETH_DEVNET=false L1_NETWORK=sepolia @@ -68,7 +69,7 @@ AZTEC_SLASHING_OFFSET_IN_ROUNDS=1 AZTEC_LOCAL_EJECTION_THRESHOLD=90000000000000000000 SEQ_MAX_TX_PER_CHECKPOINT=15 # approx 0.2 TPS -SEQ_MIN_TX_PER_BLOCK=0 +SEQ_MIN_TX_PER_BLOCK=1 # Override L1 tx utils bump percentages for scenario tests VALIDATOR_L1_PRIORITY_FEE_BUMP_PERCENTAGE=0 diff --git a/spartan/eth-devnet/create_genesis.sh b/spartan/eth-devnet/create_genesis.sh index 11944384d1be..73948a9031e4 100755 --- a/spartan/eth-devnet/create_genesis.sh +++ b/spartan/eth-devnet/create_genesis.sh @@ -135,7 +135,7 @@ function create_beacon_genesis { docker run --rm \ -v "$tmp_dir:/tmp" \ -v "$beacon_genesis_path:/out" \ - maddiaa/eth-beacon-genesis devnet \ + ethpandaops/eth-beacon-genesis:master-f57c0fb devnet \ --config="/tmp/config.yaml" \ --eth1-config="/tmp/genesis.json" \ --mnemonics="/tmp/mnemonics.yaml" \ diff --git a/spartan/eth-devnet/entrypoints/eth-beacon.sh b/spartan/eth-devnet/entrypoints/eth-beacon.sh index ae3678bad4ba..3b50cda3b238 100755 --- a/spartan/eth-devnet/entrypoints/eth-beacon.sh +++ b/spartan/eth-devnet/entrypoints/eth-beacon.sh @@ -21,6 +21,7 @@ lighthouse bn \ --disable-enr-auto-update \ --staking \ --http \ + --supernode \ --http-address=0.0.0.0 \ --http-port=${BEACON_HTTP_PORT} \ --validator-monitor-auto \ diff --git a/spartan/eth-devnet/values.yaml b/spartan/eth-devnet/values.yaml index a4263fa49ba5..f5becc5d99af 100644 --- a/spartan/eth-devnet/values.yaml +++ b/spartan/eth-devnet/values.yaml @@ -12,7 +12,7 @@ images: image: nethermind/nethermind:1.32.2 pullPolicy: IfNotPresent lighthouse: - image: sigp/lighthouse:v7.1.0 + image: sigp/lighthouse:v8.0.1 pullPolicy: IfNotPresent ethereum: diff --git a/spartan/scripts/deploy_network.sh b/spartan/scripts/deploy_network.sh index 223cef36b8f7..5524f8040573 100755 --- a/spartan/scripts/deploy_network.sh +++ b/spartan/scripts/deploy_network.sh @@ -67,9 +67,8 @@ LABS_INFRA_INDICES=${LABS_INFRA_INDICES:-0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,1 ######################## # ROLLUP VARIABLES ######################## -REDEPLOY_ROLLUP_CONTRACTS=${REDEPLOY_ROLLUP_CONTRACTS:-false} CREATE_ROLLUP_CONTRACTS=${CREATE_ROLLUP_CONTRACTS:-true} -SPONSORED_FPC=${SPONSORED_FPC:-true} +SPONSORED_FPC=${SPONSORED_FPC:-false} TEST_ACCOUNTS=${TEST_ACCOUNTS:-false} REAL_VERIFIER=${REAL_VERIFIER:-true} @@ -105,9 +104,10 @@ else fi PROVER_FAILED_PROOF_STORE=${PROVER_FAILED_PROOF_STORE:-} -SEQ_MIN_TX_PER_BLOCK=${SEQ_MIN_TX_PER_BLOCK:-0} +SEQ_MIN_TX_PER_BLOCK=${SEQ_MIN_TX_PER_BLOCK:-1} SEQ_MAX_TX_PER_BLOCK=${SEQ_MAX_TX_PER_BLOCK:-null} SEQ_MAX_TX_PER_CHECKPOINT=${SEQ_MAX_TX_PER_CHECKPOINT:-8} +SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER=${SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER:-2} SEQ_BLOCK_DURATION_MS=${SEQ_BLOCK_DURATION_MS:-} SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT=${SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT:-} SEQ_BUILD_CHECKPOINT_IF_EMPTY=${SEQ_BUILD_CHECKPOINT_IF_EMPTY:-} @@ -200,6 +200,12 @@ P2P_GOSSIPSUB_DHI=${P2P_GOSSIPSUB_DHI:-12} P2P_DROP_TX=${P2P_DROP_TX:-false} P2P_DROP_TX_CHANCE=${P2P_DROP_TX_CHANCE:-0} +# Chaos mesh scenarios values file (e.g., "network-requirements.yaml") +# If set, the experiment is installed after Aztec infra, rules are injected, +# then all pods are restarted so they come up clean with partition rules active. +# Requires the chaos mesh operator to already be running (see deploy_chaos_mesh.sh). +CHAOS_MESH_SCENARIOS_FILE=${CHAOS_MESH_SCENARIOS_FILE:-} + # Compute validator addresses (skip if no validators) if [[ $VALIDATOR_REPLICAS -gt 0 ]]; then VALIDATOR_ADDRESSES=$(echo "$VALIDATOR_INDICES" | tr ',' '\n' | xargs -I{} cast wallet address --mnemonic "$LABS_INFRA_MNEMONIC" --mnemonic-index {} | tr '\n' ',' | sed 's/,$//') @@ -515,6 +521,7 @@ VALIDATOR_HA_REPLICAS = ${VALIDATOR_HA_REPLICAS} SEQ_MIN_TX_PER_BLOCK = ${SEQ_MIN_TX_PER_BLOCK} SEQ_MAX_TX_PER_BLOCK = ${SEQ_MAX_TX_PER_BLOCK} SEQ_MAX_TX_PER_CHECKPOINT = ${SEQ_MAX_TX_PER_CHECKPOINT} +SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER = ${SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER} SEQ_BLOCK_DURATION_MS = ${SEQ_BLOCK_DURATION_MS:-null} SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT = ${SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT:-null} SEQ_BUILD_CHECKPOINT_IF_EMPTY = ${SEQ_BUILD_CHECKPOINT_IF_EMPTY:-null} @@ -623,6 +630,47 @@ k8s_denoise "tf_run "${DEPLOY_AZTEC_INFRA_DIR}" "${DESTROY_AZTEC_INFRA}" "${CREA STAGE_TIMINGS[aztec_infra]=$(($(date +%s) - AZTEC_INFRA_START)) log "Deployed aztec infra" +# ------------------------------------------------------- +# Optionally install chaos mesh scenarios after Aztec infra +# ------------------------------------------------------- +# Chaos Mesh resolves pod selectors at experiment creation time, so the target +# pods must already exist. The chaos-daemon injects iptables DROP rules into +# each matched pod's network namespace. For partition experiments, this +# immediately blocks packets between the partitioned pods, causing existing +# TCP connections to timeout and preventing new ones from forming. +# +# IMPORTANT: Do NOT restart pods after chaos injection. Chaos Mesh does not +# automatically re-inject rules into recreated pods, leaving them unpartitioned. +if [[ -n "${CHAOS_MESH_SCENARIOS_FILE}" ]]; then + CHAOS_SCENARIOS_DIR="${SCRIPT_DIR}/../aztec-chaos-scenarios" + log "Installing chaos mesh scenarios from ${CHAOS_MESH_SCENARIOS_FILE}" + helm upgrade --install network-shaping "${CHAOS_SCENARIOS_DIR}" \ + --namespace "${NAMESPACE}" \ + --values "${CHAOS_SCENARIOS_DIR}/values/${CHAOS_MESH_SCENARIOS_FILE}" \ + --set "global.targetNamespace=${NAMESPACE}" \ + --wait --timeout=5m + log "Chaos mesh scenarios installed, waiting for rules to be injected..." + + # Wait for all NetworkChaos experiments to have their rules injected. + # The AllInjected condition confirms iptables rules are active on every matched pod. + CHAOS_WAIT_TIMEOUT=120 + CHAOS_WAITED=0 + while true; do + NOT_INJECTED=$(kubectl get networkchaos -n "${NAMESPACE}" -o jsonpath='{range .items[*]}{.status.conditions[?(@.type=="AllInjected")].status}{"\n"}{end}' 2>/dev/null | grep -c "False" || true) + if [[ "${NOT_INJECTED}" -eq 0 ]]; then + log "All chaos mesh rules injected" + break + fi + if [[ "${CHAOS_WAITED}" -ge "${CHAOS_WAIT_TIMEOUT}" ]]; then + log "WARNING: Timed out waiting for chaos mesh injection after ${CHAOS_WAIT_TIMEOUT}s (${NOT_INJECTED} experiments not yet injected)" + break + fi + sleep 5 + CHAOS_WAITED=$((CHAOS_WAITED + 5)) + done + log "Chaos mesh partition active — existing connections will break as packets are dropped" +fi + # Calculate total deployment time DEPLOY_END_TIME=$(date +%s) TOTAL_DEPLOY_TIME=$((DEPLOY_END_TIME - DEPLOY_START_TIME)) diff --git a/spartan/terraform/deploy-aztec-infra/main.tf b/spartan/terraform/deploy-aztec-infra/main.tf index 9b06ef870bed..ef06a6a7245c 100644 --- a/spartan/terraform/deploy-aztec-infra/main.tf +++ b/spartan/terraform/deploy-aztec-infra/main.tf @@ -213,6 +213,7 @@ locals { "validator.node.env.SEQ_MIN_TX_PER_BLOCK" = var.SEQ_MIN_TX_PER_BLOCK "validator.node.env.SEQ_MAX_TX_PER_BLOCK" = var.SEQ_MAX_TX_PER_BLOCK "validator.node.env.SEQ_MAX_TX_PER_CHECKPOINT" = var.SEQ_MAX_TX_PER_CHECKPOINT + "validator.node.env.SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER" = var.SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER "validator.node.env.SEQ_BLOCK_DURATION_MS" = var.SEQ_BLOCK_DURATION_MS "validator.node.env.SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT" = var.SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT "validator.node.env.SEQ_BUILD_CHECKPOINT_IF_EMPTY" = var.SEQ_BUILD_CHECKPOINT_IF_EMPTY diff --git a/spartan/terraform/deploy-aztec-infra/variables.tf b/spartan/terraform/deploy-aztec-infra/variables.tf index ecf14df0976b..274704d12356 100644 --- a/spartan/terraform/deploy-aztec-infra/variables.tf +++ b/spartan/terraform/deploy-aztec-infra/variables.tf @@ -334,7 +334,7 @@ variable "TEST_ACCOUNTS" { variable "SEQ_MIN_TX_PER_BLOCK" { description = "Minimum number of sequencer transactions per block" type = string - default = "0" + default = "1" } variable "SEQ_MAX_TX_PER_BLOCK" { @@ -383,6 +383,12 @@ variable "SEQ_BUILD_CHECKPOINT_IF_EMPTY" { default = null } +variable "SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER" { + description = "Per-block gas budget multiplier for both L2 and DA gas." + type = string + default = null +} + variable "SENTINEL_ENABLED" { description = "Whether to enable sentinel" type = string @@ -765,7 +771,7 @@ variable "FISHERMAN_MODE" { variable "P2P_GOSSIPSUB_D" { description = "The P2P Gossipsub D parameter" type = string - default = "6" + default = "8" } variable "P2P_GOSSIPSUB_DLO" { diff --git a/spartan/terraform/deploy-eth-devnet/values/eth-devnet.yaml b/spartan/terraform/deploy-eth-devnet/values/eth-devnet.yaml index 92cde8c823d6..f22a57775f5e 100644 --- a/spartan/terraform/deploy-eth-devnet/values/eth-devnet.yaml +++ b/spartan/terraform/deploy-eth-devnet/values/eth-devnet.yaml @@ -12,7 +12,7 @@ images: image: nethermind/nethermind:1.32.2 pullPolicy: IfNotPresent lighthouse: - image: sigp/lighthouse:v7.1.0 + image: sigp/lighthouse:v8.0.1 pullPolicy: IfNotPresent ethereum: diff --git a/yarn-project/archiver/src/archiver-misc.test.ts b/yarn-project/archiver/src/archiver-misc.test.ts new file mode 100644 index 000000000000..1ee82651487f --- /dev/null +++ b/yarn-project/archiver/src/archiver-misc.test.ts @@ -0,0 +1,193 @@ +import type { BlobClientInterface } from '@aztec/blob-client/client'; +import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants'; +import type { EpochCache, EpochCommitteeInfo } from '@aztec/epoch-cache'; +import { DefaultL1ContractsConfig } from '@aztec/ethereum/config'; +import type { RollupContract } from '@aztec/ethereum/contracts'; +import type { ViemPublicClient } from '@aztec/ethereum/types'; +import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types'; +import { Buffer32 } from '@aztec/foundation/buffer'; +import { Fr } from '@aztec/foundation/curves/bn254'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { openTmpStore } from '@aztec/kv-store/lmdb-v2'; +import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers'; +import { getTelemetryClient } from '@aztec/telemetry-client'; + +import { EventEmitter } from 'events'; +import { type MockProxy, mock } from 'jest-mock-extended'; + +import { Archiver, type ArchiverEmitter } from './archiver.js'; +import type { ArchiverInstrumentation } from './modules/instrumentation.js'; +import { ArchiverL1Synchronizer } from './modules/l1_synchronizer.js'; +import { KVArchiverDataStore } from './store/kv_archiver_store.js'; +import { L2TipsCache } from './store/l2_tips_cache.js'; + +describe('Archiver misc', () => { + let archiver: Archiver; + let synchronizer: MockProxy; + let l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr }; + + const L1_GENESIS_TIME = 1000n; + const SLOT_DURATION = 24; + const ETH_SLOT_DURATION = DefaultL1ContractsConfig.ethereumSlotDuration; + const EPOCH_DURATION = 4; + + beforeEach(async () => { + l1Constants = { + l1GenesisTime: L1_GENESIS_TIME, + l1StartBlock: 0n, + l1StartBlockHash: Buffer32.random(), + epochDuration: EPOCH_DURATION, + slotDuration: SLOT_DURATION, + ethereumSlotDuration: ETH_SLOT_DURATION, + proofSubmissionEpochs: 1, + targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, + genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT), + }; + + synchronizer = mock(); + + const publicClient = mock(); + const blobClient = mock(); + const rollupContract = mock(); + const epochCache = mock(); + epochCache.getCommitteeForEpoch.mockResolvedValue({ committee: [] as EthAddress[] } as EpochCommitteeInfo); + + const tracer = getTelemetryClient().getTracer(''); + const instrumentation = mock({ isEnabled: () => true, tracer }); + const archiverStore = new KVArchiverDataStore(await openTmpStore('archiver_misc_test'), 1000, { + epochDuration: EPOCH_DURATION, + }); + const events = new EventEmitter() as ArchiverEmitter; + const l2TipsCache = new L2TipsCache(archiverStore.blockStore); + + archiver = new Archiver( + publicClient, + publicClient, + rollupContract, + { + registryAddress: EthAddress.random(), + governanceProposerAddress: EthAddress.random(), + slashFactoryAddress: EthAddress.random(), + slashingProposerAddress: EthAddress.random(), + }, + archiverStore, + { pollingIntervalMs: 1000, batchSize: 1000, maxAllowedEthClientDriftSeconds: 300 }, + blobClient, + instrumentation, + l1Constants, + synchronizer, + events, + l2TipsCache, + ); + }); + + afterEach(async () => { + await archiver?.stop(); + }); + + /** Returns the L1 timestamp at the start of an L2 slot. */ + function slotStart(slot: number): bigint { + return L1_GENESIS_TIME + BigInt(slot) * BigInt(SLOT_DURATION); + } + + /** Returns the L1 timestamp at the last L1 block of an L2 slot. */ + function slotLastL1Block(slot: number): bigint { + // The last L1 block in an L2 slot is the one where the next L1 block falls in the next L2 slot. + // Start of next slot minus ethereumSlotDuration gives us the last L1 block still in this slot. + return slotStart(slot + 1) - BigInt(ETH_SLOT_DURATION); + } + + describe('getSyncedL2SlotNumber', () => { + it('returns undefined before any sync', async () => { + synchronizer.getL1Timestamp.mockReturnValue(undefined); + expect(await archiver.getSyncedL2SlotNumber()).toBeUndefined(); + }); + + it('returns undefined when L1 timestamp is before genesis', async () => { + synchronizer.getL1Timestamp.mockReturnValue(L1_GENESIS_TIME - 100n); + expect(await archiver.getSyncedL2SlotNumber()).toBeUndefined(); + }); + + it('returns undefined at very start of slot 0 (next L1 block still in slot 0)', async () => { + // At genesis, next L1 block at genesis+12 is still in slot 0 (slot 0 covers [0, 24)). + synchronizer.getL1Timestamp.mockReturnValue(L1_GENESIS_TIME); + expect(await archiver.getSyncedL2SlotNumber()).toBeUndefined(); + }); + + it('returns slot 0 when last L1 block of slot 0 has been synced', async () => { + // Last L1 block in slot 0: next L1 block (at ts+12) lands in slot 1. + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(0)); + expect(await archiver.getSyncedL2SlotNumber()).toEqual(SlotNumber(0)); + }); + + it('returns slot 0 at the start of slot 1', async () => { + synchronizer.getL1Timestamp.mockReturnValue(slotStart(1)); + expect(await archiver.getSyncedL2SlotNumber()).toEqual(SlotNumber(0)); + }); + + it('returns slot 4 when last L1 block of slot 4 has been synced', async () => { + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(4)); + expect(await archiver.getSyncedL2SlotNumber()).toEqual(SlotNumber(4)); + }); + + it('returns slot N-1 when L1 timestamp is mid-slot N', async () => { + // Mid slot 3: next L1 block (ts+12) still in slot 3, so slot 2 is last fully synced. + const midSlot3 = slotStart(3) + BigInt(ETH_SLOT_DURATION); + synchronizer.getL1Timestamp.mockReturnValue(midSlot3); + // next L1 block = midSlot3 + 12 = genesis + 3*24 + 24 = genesis + 96 + // slot at genesis+96 = 96/24 = 4, so synced = 4-1 = 3 + // Actually midSlot3 = genesis + 3*24 + 12 = genesis + 84 + // next = genesis + 84 + 12 = genesis + 96, slot = 96/24 = 4, synced = 3 + expect(await archiver.getSyncedL2SlotNumber()).toEqual(SlotNumber(3)); + }); + }); + + describe('getSyncedL2EpochNumber', () => { + // With epochDuration=4: epoch 0 = slots 0-3, epoch 1 = slots 4-7, epoch 2 = slots 8-11 + + it('returns undefined before any sync', async () => { + synchronizer.getL1Timestamp.mockReturnValue(undefined); + expect(await archiver.getSyncedL2EpochNumber()).toBeUndefined(); + }); + + it('returns undefined when only part of epoch 0 is synced', async () => { + // Synced slot 0 => epoch 0 not fully synced, no previous epoch. + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(0)); + expect(await archiver.getSyncedL2EpochNumber()).toBeUndefined(); + }); + + it('returns undefined when synced to slot 2 (mid epoch 0)', async () => { + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(2)); + expect(await archiver.getSyncedL2EpochNumber()).toBeUndefined(); + }); + + it('returns epoch 0 when synced through last slot of epoch 0', async () => { + // Epoch 0 last slot = 3 + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(3)); + expect(await archiver.getSyncedL2EpochNumber()).toEqual(EpochNumber(0)); + }); + + it('returns epoch 0 when synced to first slot of epoch 1', async () => { + // Synced slot 4 = first slot of epoch 1, so only epoch 0 is fully synced. + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(4)); + expect(await archiver.getSyncedL2EpochNumber()).toEqual(EpochNumber(0)); + }); + + it('returns epoch 0 when synced to slot 6 (mid epoch 1)', async () => { + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(6)); + expect(await archiver.getSyncedL2EpochNumber()).toEqual(EpochNumber(0)); + }); + + it('returns epoch 1 when synced through last slot of epoch 1', async () => { + // Epoch 1 last slot = 7 + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(7)); + expect(await archiver.getSyncedL2EpochNumber()).toEqual(EpochNumber(1)); + }); + + it('returns epoch 1 when synced to mid epoch 2', async () => { + synchronizer.getL1Timestamp.mockReturnValue(slotLastL1Block(9)); + expect(await archiver.getSyncedL2EpochNumber()).toEqual(EpochNumber(1)); + }); + }); +}); diff --git a/yarn-project/archiver/src/archiver-store.test.ts b/yarn-project/archiver/src/archiver-store.test.ts index 950b90008ea8..084c4dd89573 100644 --- a/yarn-project/archiver/src/archiver-store.test.ts +++ b/yarn-project/archiver/src/archiver-store.test.ts @@ -72,6 +72,7 @@ describe('Archiver Store', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT), }; diff --git a/yarn-project/archiver/src/archiver-sync.test.ts b/yarn-project/archiver/src/archiver-sync.test.ts index 1779d1362a3e..c95735262b64 100644 --- a/yarn-project/archiver/src/archiver-sync.test.ts +++ b/yarn-project/archiver/src/archiver-sync.test.ts @@ -75,6 +75,7 @@ describe('Archiver Sync', () => { ethereumSlotDuration: DefaultL1ContractsConfig.ethereumSlotDuration, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, genesisArchiveRoot: GENESIS_ROOT, }; diff --git a/yarn-project/archiver/src/archiver.ts b/yarn-project/archiver/src/archiver.ts index 28c0cfa720ab..f27e8cbab3c7 100644 --- a/yarn-project/archiver/src/archiver.ts +++ b/yarn-project/archiver/src/archiver.ts @@ -22,9 +22,8 @@ import { import { PublishedCheckpoint } from '@aztec/stdlib/checkpoint'; import { type L1RollupConstants, - getEpochNumberAtTimestamp, + getEpochAtSlot, getSlotAtNextL1Block, - getSlotAtTimestamp, getSlotRangeForEpoch, getTimestampRangeForEpoch, } from '@aztec/stdlib/epoch-helpers'; @@ -123,7 +122,6 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra protected override readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr; - rollupManaLimit?: number; }, synchronizer: ArchiverL1Synchronizer, events: ArchiverEmitter, @@ -339,16 +337,35 @@ export class Archiver extends ArchiverDataSourceBase implements L2BlockSink, Tra return Promise.resolve(this.synchronizer.getL1Timestamp()); } - public getL2SlotNumber(): Promise { + public getSyncedL2SlotNumber(): Promise { const l1Timestamp = this.synchronizer.getL1Timestamp(); - return Promise.resolve(l1Timestamp === undefined ? undefined : getSlotAtTimestamp(l1Timestamp, this.l1Constants)); + if (l1Timestamp === undefined) { + return Promise.resolve(undefined); + } + // The synced slot is the last L2 slot whose all L1 blocks have been processed. + // If the next L1 block (at l1Timestamp + ethereumSlotDuration) falls in slot N, + // then we've fully synced slot N-1. + const nextL1BlockSlot = getSlotAtNextL1Block(l1Timestamp, this.l1Constants); + if (Number(nextL1BlockSlot) === 0) { + return Promise.resolve(undefined); + } + return Promise.resolve(SlotNumber(nextL1BlockSlot - 1)); } - public getL2EpochNumber(): Promise { - const l1Timestamp = this.synchronizer.getL1Timestamp(); - return Promise.resolve( - l1Timestamp === undefined ? undefined : getEpochNumberAtTimestamp(l1Timestamp, this.l1Constants), - ); + public async getSyncedL2EpochNumber(): Promise { + const syncedSlot = await this.getSyncedL2SlotNumber(); + if (syncedSlot === undefined) { + return undefined; + } + // An epoch is fully synced when all its slots are synced. + // We check if syncedSlot is the last slot of its epoch; if so, that epoch is fully synced. + // Otherwise, only the previous epoch is fully synced. + const epoch = getEpochAtSlot(syncedSlot, this.l1Constants); + const [, endSlot] = getSlotRangeForEpoch(epoch, this.l1Constants); + if (syncedSlot >= endSlot) { + return epoch; + } + return Number(epoch) > 0 ? EpochNumber(Number(epoch) - 1) : undefined; } public async isEpochComplete(epochNumber: EpochNumber): Promise { diff --git a/yarn-project/archiver/src/modules/data_source_base.ts b/yarn-project/archiver/src/modules/data_source_base.ts index 7a8cfc85f238..7bdb3e1faf99 100644 --- a/yarn-project/archiver/src/modules/data_source_base.ts +++ b/yarn-project/archiver/src/modules/data_source_base.ts @@ -46,9 +46,9 @@ export abstract class ArchiverDataSourceBase abstract getL2Tips(): Promise; - abstract getL2SlotNumber(): Promise; + abstract getSyncedL2SlotNumber(): Promise; - abstract getL2EpochNumber(): Promise; + abstract getSyncedL2EpochNumber(): Promise; abstract isEpochComplete(epochNumber: EpochNumber): Promise; diff --git a/yarn-project/archiver/src/modules/data_store_updater.ts b/yarn-project/archiver/src/modules/data_store_updater.ts index 83864240f01d..f1a0ed35fc51 100644 --- a/yarn-project/archiver/src/modules/data_store_updater.ts +++ b/yarn-project/archiver/src/modules/data_store_updater.ts @@ -178,7 +178,7 @@ export class ArchiverDataStoreUpdater { this.log.verbose(`Block number ${blockNumber} already inserted and matches checkpoint`, blockInfos); lastAlreadyInsertedBlockNumber = blockNumber; } else { - this.log.warn(`Conflict detected at block ${blockNumber} between checkpointed and local block`, blockInfos); + this.log.info(`Conflict detected at block ${blockNumber} between checkpointed and local block`, blockInfos); const prunedBlocks = await this.removeBlocksAfter(BlockNumber(blockNumber - 1)); return { prunedBlocks, lastAlreadyInsertedBlockNumber }; } diff --git a/yarn-project/archiver/src/modules/l1_synchronizer.ts b/yarn-project/archiver/src/modules/l1_synchronizer.ts index 5f75863f98db..122d4d2089e4 100644 --- a/yarn-project/archiver/src/modules/l1_synchronizer.ts +++ b/yarn-project/archiver/src/modules/l1_synchronizer.ts @@ -72,7 +72,6 @@ export class ArchiverL1Synchronizer implements Traceable { private readonly l1Constants: L1RollupConstants & { l1StartBlockHash: Buffer32; genesisArchiveRoot: Fr; - rollupManaLimit?: number; }, private readonly events: ArchiverEmitter, tracer: Tracer, @@ -820,7 +819,7 @@ export class ArchiverL1Synchronizer implements Traceable { const prunedCheckpointNumber = result.prunedBlocks[0].checkpointNumber; const prunedSlotNumber = result.prunedBlocks[0].header.globalVariables.slotNumber; - this.log.warn( + this.log.info( `Pruned ${result.prunedBlocks.length} mismatching blocks for checkpoint ${prunedCheckpointNumber}`, { prunedBlocks: result.prunedBlocks.map(b => b.toBlockInfo()), prunedSlotNumber, prunedCheckpointNumber }, ); diff --git a/yarn-project/archiver/src/test/mock_l2_block_source.ts b/yarn-project/archiver/src/test/mock_l2_block_source.ts index da295c09cb96..4491991066cd 100644 --- a/yarn-project/archiver/src/test/mock_l2_block_source.ts +++ b/yarn-project/archiver/src/test/mock_l2_block_source.ts @@ -447,11 +447,11 @@ export class MockL2BlockSource implements L2BlockSource, ContractDataSource { }; } - getL2EpochNumber(): Promise { + getSyncedL2EpochNumber(): Promise { throw new Error('Method not implemented.'); } - getL2SlotNumber(): Promise { + getSyncedL2SlotNumber(): Promise { throw new Error('Method not implemented.'); } diff --git a/yarn-project/archiver/src/test/noop_l1_archiver.ts b/yarn-project/archiver/src/test/noop_l1_archiver.ts index 175253c42c3b..74dd9e604070 100644 --- a/yarn-project/archiver/src/test/noop_l1_archiver.ts +++ b/yarn-project/archiver/src/test/noop_l1_archiver.ts @@ -1,6 +1,7 @@ import type { BlobClientInterface } from '@aztec/blob-client/client'; import type { RollupContract } from '@aztec/ethereum/contracts'; import type { ViemPublicClient, ViemPublicDebugClient } from '@aztec/ethereum/types'; +import { SlotNumber } from '@aztec/foundation/branded-types'; import { Buffer32 } from '@aztec/foundation/buffer'; import { Fr } from '@aztec/foundation/curves/bn254'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -30,7 +31,7 @@ class NoopL1Synchronizer implements FunctionsOf { return 0n; } getL1Timestamp(): bigint | undefined { - return 0n; + return undefined; } testEthereumNodeSynced(): Promise { return Promise.resolve(); @@ -96,6 +97,11 @@ export class NoopL1Archiver extends Archiver { this.runningPromise.start(); return Promise.resolve(); } + + /** Always reports as fully synced since there is no real L1 to sync from. */ + public override getSyncedL2SlotNumber(): Promise { + return Promise.resolve(SlotNumber(Number.MAX_SAFE_INTEGER)); + } } /** Creates an archiver with mocked L1 connectivity for testing. */ diff --git a/yarn-project/aztec-node/src/aztec-node/server.test.ts b/yarn-project/aztec-node/src/aztec-node/server.test.ts index 17d6f3f51928..96119e91cbdc 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.test.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.test.ts @@ -16,7 +16,7 @@ import { computeFeePayerBalanceLeafSlot } from '@aztec/protocol-contracts/fee-ju import type { GlobalVariableBuilder, SequencerClient } from '@aztec/sequencer-client'; import type { SlasherClientInterface } from '@aztec/slasher'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; -import { L2Block, type L2BlockSource } from '@aztec/stdlib/block'; +import { BlockHash, L2Block, type L2BlockSource } from '@aztec/stdlib/block'; import type { ContractDataSource } from '@aztec/stdlib/contract'; import { EmptyL1RollupConstants } from '@aztec/stdlib/epoch-helpers'; import { GasFees } from '@aztec/stdlib/gas'; @@ -136,6 +136,7 @@ describe('aztec node', () => { l2BlockSource = mock(); l2BlockSource.getBlockNumber.mockImplementation(() => Promise.resolve(lastBlockNumber)); + l2BlockSource.getL1Constants.mockResolvedValue(EmptyL1RollupConstants); const l2LogsSource = mock(); @@ -390,6 +391,130 @@ describe('aztec node', () => { expect(l2BlockSource.getL2Block).toHaveBeenCalledWith(3); }); }); + + describe('findLeavesIndexes', () => { + const blockHash1 = Fr.random(); + const blockHash2 = Fr.random(); + + beforeEach(() => { + lastBlockNumber = BlockNumber(2); + }); + + it('returns results for all found leaves', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([10n, 20n]); + merkleTreeOps.getBlockNumbersForLeafIndices.mockResolvedValue([BlockNumber(1), BlockNumber(2)]); + (merkleTreeOps as any).getLeafValue.mockImplementation((_treeId: any, index: bigint) => { + if (index === 1n) { + return Promise.resolve(blockHash1); + } + if (index === 2n) { + return Promise.resolve(blockHash2); + } + return Promise.resolve(undefined); + }); + + const result = await node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [Fr.random(), Fr.random()]); + + expect(result).toEqual([ + { l2BlockNumber: BlockNumber(1), l2BlockHash: new BlockHash(blockHash1), data: 10n }, + { l2BlockNumber: BlockNumber(2), l2BlockHash: new BlockHash(blockHash2), data: 20n }, + ]); + }); + + it('returns undefined for leaves not found', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([undefined, undefined]); + + const result = await node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [Fr.random(), Fr.random()]); + + expect(result).toEqual([undefined, undefined]); + }); + + it('returns correct results when some leaves are not found', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([undefined, 10n, 20n]); + merkleTreeOps.getBlockNumbersForLeafIndices.mockResolvedValue([BlockNumber(1), BlockNumber(2)]); + (merkleTreeOps as any).getLeafValue.mockImplementation((_treeId: any, index: bigint) => { + if (index === 1n) { + return Promise.resolve(blockHash1); + } + if (index === 2n) { + return Promise.resolve(blockHash2); + } + return Promise.resolve(undefined); + }); + + const result = await node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [ + Fr.random(), + Fr.random(), + Fr.random(), + ]); + + expect(result).toEqual([ + undefined, + { l2BlockNumber: BlockNumber(1), l2BlockHash: new BlockHash(blockHash1), data: 10n }, + { l2BlockNumber: BlockNumber(2), l2BlockHash: new BlockHash(blockHash2), data: 20n }, + ]); + // Only defined indices should be passed + expect(merkleTreeOps.getBlockNumbersForLeafIndices).toHaveBeenCalledWith(MerkleTreeId.NOTE_HASH_TREE, [ + 10n, + 20n, + ]); + }); + + it('handles multiple leaves in the same block', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([10n, 20n, 30n]); + merkleTreeOps.getBlockNumbersForLeafIndices.mockResolvedValue([BlockNumber(1), BlockNumber(1), BlockNumber(2)]); + (merkleTreeOps as any).getLeafValue.mockImplementation((_treeId: any, index: bigint) => { + if (index === 1n) { + return Promise.resolve(blockHash1); + } + if (index === 2n) { + return Promise.resolve(blockHash2); + } + return Promise.resolve(undefined); + }); + + const result = await node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [ + Fr.random(), + Fr.random(), + Fr.random(), + ]); + + expect(result).toEqual([ + { l2BlockNumber: BlockNumber(1), l2BlockHash: new BlockHash(blockHash1), data: 10n }, + { l2BlockNumber: BlockNumber(1), l2BlockHash: new BlockHash(blockHash1), data: 20n }, + { l2BlockNumber: BlockNumber(2), l2BlockHash: new BlockHash(blockHash2), data: 30n }, + ]); + // getLeafValue should be called only for unique block numbers + expect(merkleTreeOps.getLeafValue).toHaveBeenCalledTimes(2); + }); + + it('returns empty array for empty input', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([]); + + const result = await node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, []); + + expect(result).toEqual([]); + }); + + it('throws when block number is undefined for a found leaf', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([10n]); + merkleTreeOps.getBlockNumbersForLeafIndices.mockResolvedValue([undefined]); + + await expect(node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [Fr.random()])).rejects.toThrow( + /Block number is undefined/, + ); + }); + + it('throws when block hash is undefined for a found block number', async () => { + merkleTreeOps.findLeafIndices.mockResolvedValue([10n]); + merkleTreeOps.getBlockNumbersForLeafIndices.mockResolvedValue([BlockNumber(1)]); + merkleTreeOps.getLeafValue.mockResolvedValue(undefined); + + await expect(node.findLeavesIndexes('latest', MerkleTreeId.NOTE_HASH_TREE, [Fr.random()])).rejects.toThrow( + /Block hash is undefined/, + ); + }); + }); }); describe('simulatePublicCalls', () => { diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 4ea7c746cb74..242c8204f744 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -866,8 +866,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { } await this.p2pClient!.sendTx(tx); - this.metrics.receivedTx(timer.ms(), true); - this.log.info(`Received tx ${txHash}`, { txHash }); + const duration = timer.ms(); + this.metrics.receivedTx(duration, true); + this.log.info(`Received tx ${txHash} in ${duration}ms`, { txHash }); } public async getTxReceipt(txHash: TxHash): Promise { @@ -970,53 +971,59 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { treeId, leafValues.map(x => x.toBuffer()), ); - // We filter out undefined values - const indices = maybeIndices.filter(x => x !== undefined) as bigint[]; + // Filter out undefined values to query block numbers only for found leaves + const definedIndices = maybeIndices.filter(x => x !== undefined); - // Now we find the block numbers for the indices - const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, indices); + // Now we find the block numbers for the defined indices + const blockNumbers = await committedDb.getBlockNumbersForLeafIndices(treeId, definedIndices); - // If any of the block numbers are undefined, we throw an error. - for (let i = 0; i < indices.length; i++) { - if (blockNumbers[i] === undefined) { - throw new Error(`Block number is undefined for leaf index ${indices[i]} in tree ${MerkleTreeId[treeId]}`); + // Build a map from leaf index to block number + const indexToBlockNumber = new Map(); + for (let i = 0; i < definedIndices.length; i++) { + const blockNumber = blockNumbers[i]; + if (blockNumber === undefined) { + throw new Error( + `Block number is undefined for leaf index ${definedIndices[i]} in tree ${MerkleTreeId[treeId]}`, + ); } + indexToBlockNumber.set(definedIndices[i], blockNumber); } // Get unique block numbers in order to optimize num calls to getLeafValue function. - const uniqueBlockNumbers = [...new Set(blockNumbers.filter(x => x !== undefined))]; + const uniqueBlockNumbers = [...new Set(indexToBlockNumber.values())]; - // Now we obtain the block hashes from the archive tree by calling await `committedDb.getLeafValue(treeId, index)` - // (note that block number corresponds to the leaf index in the archive tree). + // Now we obtain the block hashes from the archive tree (block number = leaf index in archive tree). const blockHashes = await Promise.all( uniqueBlockNumbers.map(blockNumber => { return committedDb.getLeafValue(MerkleTreeId.ARCHIVE, BigInt(blockNumber)); }), ); - // If any of the block hashes are undefined, we throw an error. + // Build a map from block number to block hash + const blockNumberToHash = new Map(); for (let i = 0; i < uniqueBlockNumbers.length; i++) { - if (blockHashes[i] === undefined) { + const blockHash = blockHashes[i]; + if (blockHash === undefined) { throw new Error(`Block hash is undefined for block number ${uniqueBlockNumbers[i]}`); } + blockNumberToHash.set(uniqueBlockNumbers[i], blockHash); } // Create DataInBlock objects by combining indices, blockNumbers and blockHashes and return them. - return maybeIndices.map((index, i) => { + return maybeIndices.map(index => { if (index === undefined) { return undefined; } - const blockNumber = blockNumbers[i]; + const blockNumber = indexToBlockNumber.get(index); if (blockNumber === undefined) { - return undefined; + throw new Error(`Block number not found for leaf index ${index} in tree ${MerkleTreeId[treeId]}`); } - const blockHashIndex = uniqueBlockNumbers.indexOf(blockNumber); - const blockHash = blockHashes[blockHashIndex]; - if (!blockHash) { - return undefined; + const blockHash = blockNumberToHash.get(blockNumber); + if (blockHash === undefined) { + throw new Error(`Block hash not found for block number ${blockNumber}`); } return { - l2BlockNumber: BlockNumber(Number(blockNumber)), + l2BlockNumber: blockNumber, l2BlockHash: new BlockHash(blockHash), data: index, }; @@ -1317,6 +1324,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { // We accept transactions if they are not expired by the next slot (checked based on the ExpirationTimestamp field) const { ts: nextSlotTimestamp } = this.epochCache.getEpochAndSlotInNextL1Slot(); const blockNumber = BlockNumber((await this.blockSource.getBlockNumber()) + 1); + const l1Constants = await this.blockSource.getL1Constants(); const validator = createTxValidatorForAcceptingTxsOverRPC( db, this.contractDataSource, @@ -1333,6 +1341,9 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable { gasFees: await this.getCurrentMinFees(), skipFeeEnforcement, txsPermitted: !this.config.disableTransactions, + rollupManaLimit: l1Constants.rollupManaLimit, + maxBlockL2Gas: this.config.validateMaxL2BlockGas, + maxBlockDAGas: this.config.validateMaxDABlockGas, }, this.log.getBindings(), ); diff --git a/yarn-project/aztec-node/src/sentinel/sentinel.test.ts b/yarn-project/aztec-node/src/sentinel/sentinel.test.ts index b57b619be97d..f3b7e2f5ea3a 100644 --- a/yarn-project/aztec-node/src/sentinel/sentinel.test.ts +++ b/yarn-project/aztec-node/src/sentinel/sentinel.test.ts @@ -76,6 +76,7 @@ describe('sentinel', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; epochCache.getEpochAndSlotNow.mockReturnValue({ epoch, slot, ts, nowMs: ts * 1000n }); diff --git a/yarn-project/aztec-node/src/sentinel/sentinel.ts b/yarn-project/aztec-node/src/sentinel/sentinel.ts index 23f4cb21a613..eed7d863513a 100644 --- a/yarn-project/aztec-node/src/sentinel/sentinel.ts +++ b/yarn-project/aztec-node/src/sentinel/sentinel.ts @@ -309,9 +309,9 @@ export class Sentinel extends (EventEmitter as new () => WatcherEmitter) impleme return false; } - const archiverSlot = await this.archiver.getL2SlotNumber(); - if (archiverSlot === undefined || archiverSlot < targetSlot) { - this.logger.debug(`Waiting for archiver to sync with L2 slot ${targetSlot}`, { archiverSlot, targetSlot }); + const syncedSlot = await this.archiver.getSyncedL2SlotNumber(); + if (syncedSlot === undefined || syncedSlot < targetSlot) { + this.logger.debug(`Waiting for archiver to sync with L2 slot ${targetSlot}`, { syncedSlot, targetSlot }); return false; } diff --git a/yarn-project/aztec.js/src/api/abi.ts b/yarn-project/aztec.js/src/api/abi.ts index abaedaba9b4c..56ff6448708a 100644 --- a/yarn-project/aztec.js/src/api/abi.ts +++ b/yarn-project/aztec.js/src/api/abi.ts @@ -31,6 +31,7 @@ export { type EventSelectorLike, type FieldLike, type FunctionSelectorLike, + type OptionLike, type U128Like, type WrappedFieldLike, } from '../utils/abi_types.js'; diff --git a/yarn-project/aztec.js/src/api/events.ts b/yarn-project/aztec.js/src/api/events.ts index 6b4ea9dd2b0e..a683718a8ee8 100644 --- a/yarn-project/aztec.js/src/api/events.ts +++ b/yarn-project/aztec.js/src/api/events.ts @@ -3,6 +3,14 @@ import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { PublicEvent, PublicEventFilter } from '../wallet/wallet.js'; +/** Result of a paginated public event query. */ +export type GetPublicEventsResult = { + /** The decoded events with metadata. */ + events: PublicEvent[]; + /** Whether the log limit was reached, indicating more results may be available. */ + maxLogsHit: boolean; +}; + /** * Returns decoded public events given search parameters. * @param node - The node to request events from @@ -12,21 +20,23 @@ import type { PublicEvent, PublicEventFilter } from '../wallet/wallet.js'; * - `txHash`: Transaction in which the events were emitted. * - `fromBlock`: The block number from which to start fetching events (inclusive). Defaults to 1. * - `toBlock`: The block number until which to fetch events (not inclusive). Defaults to latest + 1. - * @returns - The decoded events with metadata. + * - `afterLog`: Log id after which to start fetching logs. Used for pagination. + * @returns The decoded events with metadata and a flag indicating if more results are available. */ export async function getPublicEvents( node: AztecNode, eventMetadataDef: EventMetadataDefinition, filter: PublicEventFilter, -): Promise[]> { - const { logs } = await node.getPublicLogs({ +): Promise> { + const { logs, maxLogsHit } = await node.getPublicLogs({ fromBlock: filter.fromBlock ? Number(filter.fromBlock) : undefined, toBlock: filter.toBlock ? Number(filter.toBlock) : undefined, txHash: filter.txHash, contractAddress: filter.contractAddress, + afterLog: filter.afterLog, }); - const decodedEvents: PublicEvent[] = []; + const events: PublicEvent[] = []; for (const log of logs) { const logFields = log.log.getEmittedFields(); @@ -37,7 +47,7 @@ export async function getPublicEvents( continue; } - decodedEvents.push({ + events.push({ event: decodeFromAbi([eventMetadataDef.abiType], log.log.fields) as T, metadata: { l2BlockNumber: log.id.blockNumber, @@ -48,5 +58,5 @@ export async function getPublicEvents( }); } - return decodedEvents; + return { events, maxLogsHit }; } diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 36519b918f7c..50394dc23226 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -110,6 +110,73 @@ describe('Contract Class', () => { debugSymbols: '', errorTypes: {}, }, + { + name: 'optionEcho', + isInitializer: false, + functionType: FunctionType.PRIVATE, + isOnlySelf: false, + isStatic: false, + parameters: [ + { + name: 'value', + type: { + kind: 'struct', + path: 'std::option::Option', + fields: [ + { + name: '_is_some', + type: { + kind: 'boolean', + }, + }, + { + name: '_value', + type: { + kind: 'field', + }, + }, + ], + }, + visibility: 'private', + }, + ], + returnTypes: [], + errorTypes: {}, + bytecode: Buffer.alloc(8, 0xfd), + verificationKey: Buffer.alloc(4064).toString('base64'), + debugSymbols: '', + }, + { + name: 'mixedParams', + isInitializer: false, + functionType: FunctionType.PRIVATE, + isOnlySelf: false, + isStatic: false, + parameters: [ + { + name: 'optValue', + type: { + kind: 'struct', + path: 'std::option::Option', + fields: [ + { name: '_is_some', type: { kind: 'boolean' } }, + { name: '_value', type: { kind: 'field' } }, + ], + }, + visibility: 'private', + }, + { + name: 'aField', + type: { kind: 'field' }, + visibility: 'private', + }, + ], + returnTypes: [], + errorTypes: {}, + bytecode: Buffer.alloc(8, 0xfe), + verificationKey: Buffer.alloc(4064).toString('base64'), + debugSymbols: '', + }, ], nonDispatchPublicFunctions: [], outputs: { @@ -160,4 +227,48 @@ describe('Contract Class', () => { ); expect(result).toBe(42n); }); + + it('allows nullish values for Option parameters', () => { + const fooContract = Contract.at(contractAddress, defaultArtifact, wallet); + + expect(() => fooContract.methods.optionEcho(undefined)).not.toThrow(); + expect(() => fooContract.methods.optionEcho(null)).not.toThrow(); + }); + + it('still rejects nullish values for non-Option parameters', () => { + const fooContract = Contract.at(contractAddress, defaultArtifact, wallet); + + expect(() => fooContract.methods.bar(undefined, 123n)).toThrow( + 'Null or undefined arguments are only allowed for Option parameters in bar(value: Field, value: Field). Received: (undefined, 123n).', + ); + expect(() => fooContract.methods.qux(null)).toThrow( + 'Null or undefined arguments are only allowed for Option parameters in qux(value: Field). Received: (null).', + ); + }); + + it('rejects nullish non-Option param even when Option param is valid', () => { + const fooContract = Contract.at(contractAddress, defaultArtifact, wallet); + + expect(() => fooContract.methods.mixedParams({ w: 1n }, undefined)).toThrow( + 'Null or undefined arguments are only allowed for Option parameters in mixedParams(optValue: Option, aField: Field). Received: ({ w: 1n }, undefined).', + ); + }); + + // Check basic formatting of null/undefined related errors + it.each([ + ['undefined', undefined, 'undefined'], + ['null', null, 'null'], + ['number', 42, '42'], + ['bigint', 123n, '123n'], + ['string', 'hello', 'hello'], + ['boolean', true, 'true'], + ['symbol', Symbol('test'), 'Symbol(test)'], + ['object', { a: 1n, b: 'x' }, '{ a: 1n, b: x }'], + ['array', [1n, 2n], '[1n, 2n]'], + ])('formats %s argument in error message', (_label, value, expectedFormatted) => { + const fooContract = Contract.at(contractAddress, defaultArtifact, wallet); + + // pass the test value first and undefined second to trigger the error whose message we want to test for + expect(() => fooContract.methods.bar(value, undefined)).toThrow(`Received: (${expectedFormatted}, undefined).`); + }); }); diff --git a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts index 30d553d55151..e230aa1cddf8 100644 --- a/yarn-project/aztec.js/src/contract/contract_function_interaction.ts +++ b/yarn-project/aztec.js/src/contract/contract_function_interaction.ts @@ -1,10 +1,14 @@ import { + type ABIParameter, + type AbiType, type FunctionAbi, FunctionCall, FunctionSelector, FunctionType, + canBeMappedFromNullOrUndefined, decodeFromAbi, encodeArguments, + isOptionStruct, } from '@aztec/stdlib/abi'; import type { AuthWitness } from '@aztec/stdlib/auth-witness'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; @@ -40,11 +44,32 @@ export class ContractFunctionInteraction extends BaseContractInteraction { private extraHashedArgs: HashedValues[] = [], ) { super(wallet, authWitnesses, capsules); - if (args.some(arg => arg === undefined || arg === null)) { - throw new Error(`All function interaction arguments must be defined and not null. Received: ${args}`); + // This may feel a bit ad-hoc here, so it warrants a comment. We accept Noir Option parameters, and it's natural + // to map JS's null/undefined to Noir Option's None. One possible way to deal with null/undefined arguments at this + // point in the codebase is to conclude that they are accepted since at least one Noir type (ie: Option) can be + // encoded from them. Then we would let `encode` deal with potential mismatches. I chose not to do that because of + // the pervasiveness of null/undefined in JS, and how easy it is to inadvertently pass it around. Having this check + // here allows us to fail at a point where the boundaries and intent are clear. + if (this.hasInvalidNullOrUndefinedArguments(args)) { + const signature = formatFunctionSignature(this.functionDao.name, this.functionDao.parameters); + const received = args.map(formatArg).join(', '); + throw new Error( + `Null or undefined arguments are only allowed for Option parameters in ${signature}. Received: (${received}).`, + ); } } + private hasInvalidNullOrUndefinedArguments(args: any[]) { + return args.some((arg, index) => { + if (arg !== undefined && arg !== null) { + return false; + } + + const parameterType = this.functionDao.parameters[index]?.type; + return !parameterType || !canBeMappedFromNullOrUndefined(parameterType); + }); + } + /** * Returns the encoded function call wrapped by this interaction * Useful when generating authwits @@ -204,3 +229,62 @@ export class ContractFunctionInteraction extends BaseContractInteraction { ); } } + +/** + * Render an AbiType as a human readable string + * */ +function formatAbiType(abiType: AbiType): string { + switch (abiType.kind) { + case 'field': + return 'Field'; + case 'boolean': + return 'bool'; + case 'integer': + return `${abiType.sign === 'signed' ? 'i' : 'u'}${abiType.width}`; + case 'string': + return `str<${abiType.length}>`; + case 'array': + return `[${formatAbiType(abiType.type)}; ${abiType.length}]`; + case 'struct': { + if (isOptionStruct(abiType)) { + const innerType = abiType.fields.find(f => f.name === '_value')!.type; + return `Option<${formatAbiType(innerType)}>`; + } + return `(${abiType.fields.map(f => `${f.name}: ${formatAbiType(f.type)}`).join(', ')})`; + } + case 'tuple': + return `(${abiType.fields.map(formatAbiType).join(', ')})`; + } +} + +/** + * Pretty print a function signature + */ +function formatFunctionSignature(name: string, parameters: ABIParameter[]): string { + const params = parameters.map(p => `${p.name}: ${formatAbiType(p.type)}`).join(', '); + return `${name}(${params})`; +} + +/** + * Non-exhaustive pretty print of JS args to display in error messages in this module + */ +function formatArg(arg: unknown): string { + if (arg === undefined) { + return 'undefined'; + } + if (arg === null) { + return 'null'; + } + if (typeof arg === 'bigint') { + return `${arg}n`; + } + if (Array.isArray(arg)) { + return `[${arg.map(formatArg).join(', ')}]`; + } + if (typeof arg === 'object') { + const entries = Object.entries(arg).map(([k, v]) => `${k}: ${formatArg(v)}`); + return `{ ${entries.join(', ')} }`; + } + // eslint-disable-next-line @typescript-eslint/no-base-to-string + return String(arg); +} diff --git a/yarn-project/aztec.js/src/utils/abi_types.ts b/yarn-project/aztec.js/src/utils/abi_types.ts index af2b8bfc70df..9c39481d54f6 100644 --- a/yarn-project/aztec.js/src/utils/abi_types.ts +++ b/yarn-project/aztec.js/src/utils/abi_types.ts @@ -23,3 +23,10 @@ export type U128Like = bigint | number; /** Any type that can be converted into a struct with a single `inner` field. */ export type WrappedFieldLike = { /** Wrapped value */ inner: FieldLike } | FieldLike; + +/** Noir `Option` lowered ABI shape, plus ergonomic direct `T | null | undefined` inputs. */ +export type OptionLike = + | T + | null + | undefined + | { /** Whether the option is populated */ _is_some: boolean; /** Wrapped value */ _value: T }; diff --git a/yarn-project/aztec.js/src/wallet/wallet.ts b/yarn-project/aztec.js/src/wallet/wallet.ts index 0e48f2f42726..7f7b61befdcc 100644 --- a/yarn-project/aztec.js/src/wallet/wallet.ts +++ b/yarn-project/aztec.js/src/wallet/wallet.ts @@ -13,6 +13,7 @@ import { AuthWitness } from '@aztec/stdlib/auth-witness'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { type ContractInstanceWithAddress, ContractInstanceWithAddressSchema } from '@aztec/stdlib/contract'; import { Gas } from '@aztec/stdlib/gas'; +import { LogId } from '@aztec/stdlib/logs'; import { AbiDecodedSchema, type ApiSchemaFor, optional, schemas, zodFor } from '@aztec/stdlib/schemas'; import type { ExecutionPayload, InTx } from '@aztec/stdlib/tx'; import { @@ -153,6 +154,8 @@ export type EventFilterBase = { * Optional. If provided, it must be greater than fromBlock. */ toBlock?: BlockNumber; + /** Log id after which to start fetching logs. Used for pagination. */ + afterLog?: LogId; }; /** @@ -340,6 +343,7 @@ const EventFilterBaseSchema = z.object({ txHash: optional(TxHash.schema), fromBlock: optional(BlockNumberPositiveSchema), toBlock: optional(BlockNumberPositiveSchema), + afterLog: optional(LogId.schema), }); export const PrivateEventFilterSchema = EventFilterBaseSchema.extend({ diff --git a/yarn-project/aztec/src/local-network/local-network.ts b/yarn-project/aztec/src/local-network/local-network.ts index 4f62ea214738..5856a93bf8e7 100644 --- a/yarn-project/aztec/src/local-network/local-network.ts +++ b/yarn-project/aztec/src/local-network/local-network.ts @@ -16,15 +16,11 @@ import { SecretValue } from '@aztec/foundation/config'; import { EthAddress } from '@aztec/foundation/eth-address'; import type { LogFn } from '@aztec/foundation/log'; import { DateProvider, TestDateProvider } from '@aztec/foundation/timer'; -import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { getVKTreeRoot } from '@aztec/noir-protocol-circuits-types/vk-tree'; import { protocolContractsHash } from '@aztec/protocol-contracts'; import { SequencerState } from '@aztec/sequencer-client'; -import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi'; -import type { FunctionAbi } from '@aztec/stdlib/abi'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; -import { getContractClassFromArtifact } from '@aztec/stdlib/contract'; -import type { AllowedElement, ProvingJobBroker } from '@aztec/stdlib/interfaces/server'; +import type { ProvingJobBroker } from '@aztec/stdlib/interfaces/server'; import type { PublicDataTreeLeaf } from '@aztec/stdlib/trees'; import { type TelemetryClient, @@ -43,43 +39,12 @@ import { createAccountLogs } from '../cli/util.js'; import { DefaultMnemonic } from '../mnemonic.js'; import { AnvilTestWatcher } from '../testing/anvil_test_watcher.js'; import { EpochTestSettler } from '../testing/epoch_test_settler.js'; +import { getTokenAllowedSetupFunctions } from '../testing/token_allowed_setup.js'; import { getBananaFPCAddress, setupBananaFPC } from './banana_fpc.js'; import { getSponsoredFPCAddress } from './sponsored_fpc.js'; const logger = createLogger('local-network'); -/** - * Returns Token-specific allowlist entries for FPC-based fee payments. - * The local network deploys a banana FPC and Token contracts, so the node must allow Token setup functions. - */ -async function getTokenAllowedSetupFunctions(): Promise { - const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id; - const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat( - TokenContractArtifact.nonDispatchPublicFunctions || [], - ); - const getCalldataLength = (name: string) => { - const fn = allFunctions.find(f => f.name === name)!; - return 1 + countArgumentsSize(fn); - }; - const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'); - const transferInPublicSelector = await FunctionSelector.fromSignature( - 'transfer_in_public((Field),(Field),u128,Field)', - ); - return [ - { - classId: tokenClassId, - selector: increaseBalanceSelector, - calldataLength: getCalldataLength('_increase_public_balance'), - onlySelf: true, - }, - { - classId: tokenClassId, - selector: transferInPublicSelector, - calldataLength: getCalldataLength('transfer_in_public'), - }, - ]; -} - const localAnvil = foundry; /** diff --git a/yarn-project/aztec/src/testing/index.ts b/yarn-project/aztec/src/testing/index.ts index eaf2f836c9a3..97d6da751638 100644 --- a/yarn-project/aztec/src/testing/index.ts +++ b/yarn-project/aztec/src/testing/index.ts @@ -2,3 +2,4 @@ export { AnvilTestWatcher } from './anvil_test_watcher.js'; export { EthCheatCodes, RollupCheatCodes } from '@aztec/ethereum/test'; export { CheatCodes } from './cheat_codes.js'; export { EpochTestSettler } from './epoch_test_settler.js'; +export { getTokenAllowedSetupFunctions } from './token_allowed_setup.js'; diff --git a/yarn-project/aztec/src/testing/token_allowed_setup.ts b/yarn-project/aztec/src/testing/token_allowed_setup.ts new file mode 100644 index 000000000000..539b9521bddf --- /dev/null +++ b/yarn-project/aztec/src/testing/token_allowed_setup.ts @@ -0,0 +1,19 @@ +import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; +import { buildAllowedElement } from '@aztec/p2p/msg_validators'; +import { getContractClassFromArtifact } from '@aztec/stdlib/contract'; +import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; + +/** + * Returns Token-specific allowlist entries needed for FPC-based fee payments. + * These are test-only: FPC-based fee payment with custom tokens won't work on mainnet alpha. + */ +export async function getTokenAllowedSetupFunctions(): Promise { + const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id; + const target = { classId: tokenClassId }; + return Promise.all([ + // Token: needed for private transfers via FPC (transfer_to_public enqueues this) + buildAllowedElement(TokenContractArtifact, target, '_increase_public_balance', { onlySelf: true }), + // Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this) + buildAllowedElement(TokenContractArtifact, target, 'transfer_in_public'), + ]); +} diff --git a/yarn-project/builder/src/contract-interface-gen/typescript.ts b/yarn-project/builder/src/contract-interface-gen/typescript.ts index ff0ec242710d..a8a427ab0d44 100644 --- a/yarn-project/builder/src/contract-interface-gen/typescript.ts +++ b/yarn-project/builder/src/contract-interface-gen/typescript.ts @@ -11,6 +11,7 @@ import { isBoundedVecStruct, isEthAddressStruct, isFunctionSelectorStruct, + isOptionStruct, isPublicKeysStruct, isWrappedFieldStruct, } from '@aztec/stdlib/abi'; @@ -55,6 +56,9 @@ function abiTypeToTypescript(type: ABIParameter['type']): string { // as a BoundedVec in the ArgumentsEncoder. return `${abiTypeToTypescript(type.fields[0].type)}`; } + if (isOptionStruct(type)) { + return `OptionLike<${abiTypeToTypescript(type.fields[1].type)}>`; + } return `{ ${type.fields.map(f => `${f.name}: ${abiTypeToTypescript(f.type)}`).join(', ')} }`; default: throw new Error(`Unknown type ${type.kind}`); @@ -305,7 +309,7 @@ export async function generateTypescriptContractInterface(input: ContractArtifac /* eslint-disable */ import { AztecAddress, CompleteAddress } from '@aztec/aztec.js/addresses'; -import { type AbiType, type AztecAddressLike, type ContractArtifact, EventSelector, decodeFromAbi, type EthAddressLike, type FieldLike, type FunctionSelectorLike, loadContractArtifact, loadContractArtifactForPublic, type NoirCompiledContract, type U128Like, type WrappedFieldLike } from '@aztec/aztec.js/abi'; +import { type AbiType, type AztecAddressLike, type ContractArtifact, EventSelector, decodeFromAbi, type EthAddressLike, type FieldLike, type FunctionSelectorLike, loadContractArtifact, loadContractArtifactForPublic, type NoirCompiledContract, type OptionLike, type U128Like, type WrappedFieldLike } from '@aztec/aztec.js/abi'; import { Contract, ContractBase, ContractFunctionInteraction, type ContractMethod, type ContractStorageLayout, DeployMethod } from '@aztec/aztec.js/contracts'; import { EthAddress } from '@aztec/aztec.js/addresses'; import { Fr, Point } from '@aztec/aztec.js/fields'; diff --git a/yarn-project/constants/src/constants.gen.ts b/yarn-project/constants/src/constants.gen.ts index 6d63cc576b67..6675dfa2cca1 100644 --- a/yarn-project/constants/src/constants.gen.ts +++ b/yarn-project/constants/src/constants.gen.ts @@ -538,6 +538,7 @@ export enum DomainSeparator { AUTHWIT_NULLIFIER = 1239150694, SYMMETRIC_KEY = 3882206064, SYMMETRIC_KEY_2 = 4129434989, + CIPHERTEXT_FIELD_MASK = 1870492847, PARTIAL_NOTE_VALIDITY_COMMITMENT = 623934423, INITIALIZATION_NULLIFIER = 1653084894, SECRET_HASH = 4199652938, diff --git a/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts b/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts index 7b997404b6e1..d0592a8132fb 100644 --- a/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts +++ b/yarn-project/end-to-end/src/bench/client_flows/client_flows_benchmark.ts @@ -4,7 +4,7 @@ import { type FeePaymentMethod, PrivateFeePaymentMethod, SponsoredFeePaymentMeth import { type Logger, createLogger } from '@aztec/aztec.js/log'; import type { AztecNode } from '@aztec/aztec.js/node'; import type { Wallet } from '@aztec/aztec.js/wallet'; -import { CheatCodes } from '@aztec/aztec/testing'; +import { CheatCodes, getTokenAllowedSetupFunctions } from '@aztec/aztec/testing'; import { createExtendedL1Client } from '@aztec/ethereum/client'; import { RollupContract } from '@aztec/ethereum/contracts'; import type { DeployAztecL1ContractsArgs } from '@aztec/ethereum/deploy-aztec-l1-contracts'; @@ -19,16 +19,12 @@ import { AMMContract } from '@aztec/noir-contracts.js/AMM'; import { FPCContract } from '@aztec/noir-contracts.js/FPC'; import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice'; import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; -import { TokenContract as BananaCoin, TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; +import { TokenContract as BananaCoin, TokenContract } from '@aztec/noir-contracts.js/Token'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; import { type PXEConfig, getPXEConfig } from '@aztec/pxe/server'; -import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi'; -import type { FunctionAbi } from '@aztec/stdlib/abi'; -import { getContractClassFromArtifact } from '@aztec/stdlib/contract'; import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract'; import { GasSettings } from '@aztec/stdlib/gas'; -import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; import { deriveSigningKey } from '@aztec/stdlib/keys'; import { MNEMONIC } from '../../fixtures/fixtures.js'; @@ -46,35 +42,6 @@ import { type ClientFlowsConfig, FULL_FLOWS_CONFIG, KEY_FLOWS_CONFIG } from './c const { BENCHMARK_CONFIG } = process.env; -/** Returns Token-specific allowlist entries for FPC-based fee payments (test-only). */ -async function getTokenAllowedSetupFunctions(): Promise { - const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id; - const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat( - TokenContractArtifact.nonDispatchPublicFunctions || [], - ); - const getCalldataLength = (name: string) => { - const fn = allFunctions.find(f => f.name === name)!; - return 1 + countArgumentsSize(fn); - }; - const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'); - const transferInPublicSelector = await FunctionSelector.fromSignature( - 'transfer_in_public((Field),(Field),u128,Field)', - ); - return [ - { - classId: tokenClassId, - selector: increaseBalanceSelector, - calldataLength: getCalldataLength('_increase_public_balance'), - onlySelf: true, - }, - { - classId: tokenClassId, - selector: transferInPublicSelector, - calldataLength: getCalldataLength('transfer_in_public'), - }, - ]; -} - export type AccountType = 'ecdsar1' | 'schnorr'; export type FeePaymentMethodGetter = (wallet: Wallet, sender: AztecAddress) => Promise; export type BenchmarkingFeePaymentMethod = 'bridged_fee_juice' | 'private_fpc' | 'sponsored_fpc' | 'fee_juice'; diff --git a/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts b/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts index a272fc521d94..0068706853bd 100644 --- a/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts +++ b/yarn-project/end-to-end/src/e2e_epochs/epochs_test.ts @@ -181,6 +181,7 @@ export class EpochsTestContext { ethereumSlotDuration, proofSubmissionEpochs: Number(await this.rollup.getProofSubmissionEpochs()), targetCommitteeSize: await this.rollup.getTargetCommitteeSize(), + rollupManaLimit: Number(await this.rollup.getManaLimit()), }; this.logger.info( diff --git a/yarn-project/end-to-end/src/e2e_event_logs.test.ts b/yarn-project/end-to-end/src/e2e_event_logs.test.ts index 64d89526709f..1fde8fe14556 100644 --- a/yarn-project/end-to-end/src/e2e_event_logs.test.ts +++ b/yarn-project/end-to-end/src/e2e_event_logs.test.ts @@ -143,13 +143,13 @@ describe('Logs', () => { toBlock: BlockNumber(lastTx.blockNumber! + 1), }; - const collectedEvent0s = await getPublicEvents( + const { events: collectedEvent0s } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleEvent0, publicEventFilter, ); - const collectedEvent1s = await getPublicEvents( + const { events: collectedEvent1s } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleEvent1, publicEventFilter, @@ -188,7 +188,7 @@ describe('Logs', () => { .emit_nested_event(a, b, c, extra) .send({ from: account1Address }); - const collectedEvents = await getPublicEvents( + const { events: collectedEvents } = await getPublicEvents( aztecNode, TestLogContract.events.ExampleNestedEvent, { diff --git a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts index a4019b3b1c45..fca622ac6bff 100644 --- a/yarn-project/end-to-end/src/e2e_fees/fees_test.ts +++ b/yarn-project/end-to-end/src/e2e_fees/fees_test.ts @@ -1,7 +1,7 @@ import type { AztecAddress } from '@aztec/aztec.js/addresses'; import { type Logger, createLogger } from '@aztec/aztec.js/log'; import type { AztecNode } from '@aztec/aztec.js/node'; -import { CheatCodes } from '@aztec/aztec/testing'; +import { CheatCodes, getTokenAllowedSetupFunctions } from '@aztec/aztec/testing'; import { createExtendedL1Client } from '@aztec/ethereum/client'; import { RollupContract } from '@aztec/ethereum/contracts'; import type { DeployAztecL1ContractsArgs } from '@aztec/ethereum/deploy-aztec-l1-contracts'; @@ -14,16 +14,12 @@ import { AppSubscriptionContract } from '@aztec/noir-contracts.js/AppSubscriptio import { FPCContract } from '@aztec/noir-contracts.js/FPC'; import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice'; import { SponsoredFPCContract } from '@aztec/noir-contracts.js/SponsoredFPC'; -import { TokenContract as BananaCoin, TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; +import { TokenContract as BananaCoin } from '@aztec/noir-contracts.js/Token'; import { CounterContract } from '@aztec/noir-test-contracts.js/Counter'; import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { getCanonicalFeeJuice } from '@aztec/protocol-contracts/fee-juice'; -import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi'; -import type { FunctionAbi } from '@aztec/stdlib/abi'; -import { getContractClassFromArtifact } from '@aztec/stdlib/contract'; import { GasSettings } from '@aztec/stdlib/gas'; import type { AztecNodeAdmin } from '@aztec/stdlib/interfaces/client'; -import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; import { getContract } from 'viem'; @@ -41,46 +37,6 @@ import { type BalancesFn, getBalancesFn, setupSponsoredFPC } from '../fixtures/u import { FeeJuicePortalTestingHarnessFactory, type GasBridgingTestHarness } from '../shared/gas_portal_test_harness.js'; import { TestWallet } from '../test-wallet/test_wallet.js'; -/** Returns the calldata length for a function: 1 (selector) + arguments size. */ -function getCalldataLength(functionName: string): number { - const allFunctions: FunctionAbi[] = (TokenContractArtifact.functions as FunctionAbi[]).concat( - TokenContractArtifact.nonDispatchPublicFunctions || [], - ); - const fn = allFunctions.find(f => f.name === functionName); - if (!fn) { - throw new Error(`Unknown function ${functionName} in Token artifact`); - } - return 1 + countArgumentsSize(fn); -} - -/** - * Returns Token-specific allowlist entries needed for FPC-based fee payments. - * These are test-only — FPC-based fee payment with custom tokens won't work on mainnet alpha. - */ -async function getTokenAllowedSetupFunctions(): Promise { - const tokenClassId = (await getContractClassFromArtifact(TokenContractArtifact)).id; - const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'); - const transferInPublicSelector = await FunctionSelector.fromSignature( - 'transfer_in_public((Field),(Field),u128,Field)', - ); - - return [ - // Token: needed for private transfers via FPC (transfer_to_public enqueues this) - { - classId: tokenClassId, - selector: increaseBalanceSelector, - calldataLength: getCalldataLength('_increase_public_balance'), - onlySelf: true, - }, - // Token: needed for public transfers via FPC (fee_entrypoint_public enqueues this) - { - classId: tokenClassId, - selector: transferInPublicSelector, - calldataLength: getCalldataLength('transfer_in_public'), - }, - ]; -} - /** * Test fixture for testing fees. Provides the following setup steps: * InitialAccounts: Initializes 3 Schnorr account contracts. diff --git a/yarn-project/end-to-end/src/e2e_option_params.test.ts b/yarn-project/end-to-end/src/e2e_option_params.test.ts new file mode 100644 index 000000000000..99c373092636 --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_option_params.test.ts @@ -0,0 +1,92 @@ +import { AztecAddress } from '@aztec/aztec.js/addresses'; +import type { Wallet } from '@aztec/aztec.js/wallet'; +import { MAX_FIELD_VALUE } from '@aztec/constants'; +import { OptionParamContract } from '@aztec/noir-test-contracts.js/OptionParam'; + +import { jest } from '@jest/globals'; + +import { setup } from './fixtures/utils.js'; + +const TIMEOUT = 120_000; + +const U64_MAX = 2n ** 64n - 1n; +const I64_MIN = -(2n ** 63n); + +describe('Option params', () => { + let contract: OptionParamContract; + let wallet: Wallet; + let defaultAccountAddress: AztecAddress; + let teardown: () => Promise; + + const someValue = { + w: MAX_FIELD_VALUE, + x: true, + y: U64_MAX, + z: I64_MIN, + }; + + jest.setTimeout(TIMEOUT); + + beforeAll(async () => { + ({ + teardown, + wallet, + accounts: [defaultAccountAddress], + } = await setup(1)); + + contract = (await OptionParamContract.deploy(wallet).send({ from: defaultAccountAddress })).contract; + }); + + afterAll(() => teardown()); + + it('accepts ergonomic Option params for public functions', async () => { + const { result } = await contract.methods + .return_public_optional_struct(undefined) + .simulate({ from: defaultAccountAddress }); + expect(result).toBeUndefined(); + + const { result: nullResult } = await contract.methods + .return_public_optional_struct(null) + .simulate({ from: defaultAccountAddress }); + expect(nullResult).toBeUndefined(); + + const { result: someResult } = await contract.methods + .return_public_optional_struct(someValue) + .simulate({ from: defaultAccountAddress }); + expect(someResult).toEqual(someValue); + }); + + it('accepts ergonomic Option params for utility functions', async () => { + const { result: undefinedResult } = await contract.methods + .return_utility_optional_struct(undefined) + .simulate({ from: defaultAccountAddress }); + expect(undefinedResult).toBeUndefined(); + + const { result: nullResult } = await contract.methods + .return_utility_optional_struct(null) + .simulate({ from: defaultAccountAddress }); + expect(nullResult).toBeUndefined(); + + const { result: someResult } = await contract.methods + .return_utility_optional_struct(someValue) + .simulate({ from: defaultAccountAddress }); + expect(someResult).toEqual(someValue); + }); + + it('accepts ergonomic Option params for private functions', async () => { + const { result: undefinedResult } = await contract.methods + .return_private_optional_struct(undefined) + .simulate({ from: defaultAccountAddress }); + expect(undefinedResult).toBeUndefined(); + + const { result: nullResult } = await contract.methods + .return_private_optional_struct(null) + .simulate({ from: defaultAccountAddress }); + expect(nullResult).toBeUndefined(); + + const { result: someResult } = await contract.methods + .return_private_optional_struct(someValue) + .simulate({ from: defaultAccountAddress }); + expect(someResult).toEqual(someValue); + }); +}); diff --git a/yarn-project/end-to-end/src/e2e_orderbook.test.ts b/yarn-project/end-to-end/src/e2e_orderbook.test.ts index 22efa02edd17..4f566ca466c8 100644 --- a/yarn-project/end-to-end/src/e2e_orderbook.test.ts +++ b/yarn-project/end-to-end/src/e2e_orderbook.test.ts @@ -81,7 +81,7 @@ describe('Orderbook', () => { .with({ authWitnesses: [makerAuthwit] }) .send({ from: makerAddress }); - const orderCreatedEvents = await getPublicEvents( + const { events: orderCreatedEvents } = await getPublicEvents( aztecNode, OrderbookContract.events.OrderCreated, {}, @@ -137,7 +137,7 @@ describe('Orderbook', () => { .send({ from: takerAddress }); // Verify order was fulfilled by checking events - const orderFulfilledEvents = await getPublicEvents( + const { events: orderFulfilledEvents } = await getPublicEvents( aztecNode, OrderbookContract.events.OrderFulfilled, {}, diff --git a/yarn-project/end-to-end/src/spartan/n_tps.test.ts b/yarn-project/end-to-end/src/spartan/n_tps.test.ts index 5bbdb2a94136..e9dd610fe610 100644 --- a/yarn-project/end-to-end/src/spartan/n_tps.test.ts +++ b/yarn-project/end-to-end/src/spartan/n_tps.test.ts @@ -10,7 +10,7 @@ import { RunningPromise } from '@aztec/foundation/promise'; import { retryUntil } from '@aztec/foundation/retry'; import { sleep } from '@aztec/foundation/sleep'; import { BenchmarkingContract } from '@aztec/noir-test-contracts.js/Benchmarking'; -import { GasFees } from '@aztec/stdlib/gas'; +import { type Gas, GasFees } from '@aztec/stdlib/gas'; import { TopicType } from '@aztec/stdlib/p2p'; import { Tx, TxHash } from '@aztec/stdlib/tx'; @@ -33,6 +33,7 @@ import { getChartDir, getGitProjectRoot, getRPCEndpoint, + hasDeployedHelmRelease, installChaosMeshChart, setupEnvironment, startPortForwardForPrometeheus, @@ -226,6 +227,32 @@ describe('sustained N TPS test', () => { }); const spartanDir = `${getGitProjectRoot()}/spartan`; + // Skip chaos mesh installation if it was already deployed by deploy_network.sh + // (via CHAOS_MESH_SCENARIOS_FILE). Installing before infra ensures partition + // rules are in place when pods start, preventing unwanted peer connections. + const alreadyDeployed = await hasDeployedHelmRelease(CHAOS_MESH_NAME, config.NAMESPACE); + if (alreadyDeployed) { + logger.info('Chaos mesh chart already deployed, skipping installation'); + } else { + logger.info('Installing chaos mesh chart', { + name: CHAOS_MESH_NAME, + namespace: config.NAMESPACE, + valuesFile: 'network-requirements.yaml', + }); + await installChaosMeshChart({ + logger, + targetNamespace: config.NAMESPACE, + instanceName: CHAOS_MESH_NAME, + valuesFile: 'network-requirements.yaml', + helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'), + }); + logger.info('Chaos mesh installation complete'); + + logger.info('Waiting for network to stabilize after chaos mesh installation...'); + await sleep(30 * 1000); + logger.info('Network stabilization wait complete'); + } + const rpcEndpoint = await getRPCEndpoint(config.NAMESPACE); endpoints.push(rpcEndpoint); const rpcUrl = rpcEndpoint.url; @@ -266,7 +293,7 @@ describe('sustained N TPS test', () => { // this function creates n + 1 accounts. We only want one for each wallet const localTestAccounts = await Promise.all( - testWallets.map(lw => deploySponsoredTestAccounts(lw.wallet, aztecNode, logger, 0)), + testWallets.map(lw => deploySponsoredTestAccounts(lw.wallet, aztecNode, logger, 0, { estimateGas: true })), ); lowValueWallets = localTestAccounts.slice(0, lowValueAccounts).map(({ wallet }) => wallet); @@ -279,41 +306,44 @@ describe('sustained N TPS test', () => { logger.info('Deploying benchmark contract...'); const sponsor = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress()); - ({ contract: benchmarkContract } = await BenchmarkingContract.deploy(localTestAccounts[0].wallet).send({ + const deployInteraction = BenchmarkingContract.deploy(localTestAccounts[0].wallet); + const deploySim = await deployInteraction.simulate({ from: localTestAccounts[0].recipientAddress, fee: { paymentMethod: sponsor }, + }); + logger.info('Benchmark contract deploy estimated gas', { gasLimits: deploySim.estimatedGas?.gasLimits }); + ({ contract: benchmarkContract } = await deployInteraction.send({ + from: localTestAccounts[0].recipientAddress, + fee: { paymentMethod: sponsor, gasSettings: deploySim.estimatedGas }, })); logger.info('Benchmark contract deployed', { address: benchmarkContract.address.toString() }); - logger.info('Installing chaos mesh chart', { - name: CHAOS_MESH_NAME, - namespace: config.NAMESPACE, - valuesFile: 'network-requirements.yaml', - }); - await installChaosMeshChart({ - logger, - targetNamespace: config.NAMESPACE, - instanceName: CHAOS_MESH_NAME, - valuesFile: 'network-requirements.yaml', - helmChartDir: getChartDir(spartanDir, 'aztec-chaos-scenarios'), - }); - logger.info('Chaos mesh installation complete'); - - logger.info('Waiting for network to stabilize after chaos mesh installation...'); - await sleep(30 * 1000); - logger.info('Network stabilization wait complete'); - logger.info(`Test setup complete`); }); + let benchmarkGasEstimate: { gasLimits: Gas; teardownGasLimits: Gas } | undefined; + const submitProven = async ( wallet: TestWallet, maxPriorityFeesPerGas: GasFees = GasFees.empty(), ): Promise => { const sponsor = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress()); + + if (!benchmarkGasEstimate) { + const sim = await benchmarkContract.methods.sha256_hash_1024(Array(1024).fill(42)).simulate({ + from: (await benchmarkContract.wallet.getAccounts())[0].item, + fee: { paymentMethod: sponsor, estimateGas: true }, + }); + benchmarkGasEstimate = sim.estimatedGas; + logger.info('Benchmark tx estimated gas', { gasLimits: benchmarkGasEstimate?.gasLimits }); + } + const tx = await proveInteraction(wallet, benchmarkContract.methods.sha256_hash_1024(Array(1024).fill(42)), { from: (await wallet.getAccounts())[0].item, - fee: { paymentMethod: sponsor, gasSettings: { maxPriorityFeesPerGas } }, + fee: { + paymentMethod: sponsor, + gasSettings: { maxPriorityFeesPerGas, ...benchmarkGasEstimate }, + }, }); return tx; @@ -328,7 +358,7 @@ describe('sustained N TPS test', () => { prototypeTxs.set(from.toString(), prototypeTx); } - const tx = await cloneTx(prototypeTx, priorytFee); + const tx = await cloneTx(prototypeTx, priorytFee, logger); return tx; }; @@ -345,15 +375,23 @@ describe('sustained N TPS test', () => { let lowValueTxs = 0; const lowValueSendTx = async (wallet: TestWallet) => { lowValueTxs++; - //const feeAmount = Number(randomBigInt(100n)) + 1; - //const feeAmount = 1; const feeAmount = Math.floor(lowValueTxs / 1000) + 1; const fee = new GasFees(0, feeAmount); - logger.info('Sending low value tx ' + lowValueTxs + ' with fee ' + feeAmount); + const t0 = performance.now(); const tx = await (config.REAL_VERIFIER ? submitProven(wallet, fee) : submitUnproven(wallet, fee)); + const t1 = performance.now(); const txHash = await tx.send({ wait: NO_WAIT }); + const t2 = performance.now(); + + logger.info('Low value tx sent', { + txNum: lowValueTxs, + feeAmount, + cloneMs: Math.round(t1 - t0), + sendMs: Math.round(t2 - t1), + totalMs: Math.round(t2 - t0), + }); return txHash.toString(); }; @@ -362,13 +400,23 @@ describe('sustained N TPS test', () => { highValueTxs++; const feeAmount = Number(randomBigInt(10n)) + 1000; const fee = new GasFees(0, feeAmount); - logger.info('Sending high value tx ' + highValueTxs + ' with fee ' + feeAmount); + const t0 = performance.now(); const tx = await (config.REAL_VERIFIER ? submitProven(wallet, fee) : submitUnproven(wallet, fee)); + const t1 = performance.now(); metrics.recordSentTx(tx, `high_value_${highValueTps}tps`); const txHash = await tx.send({ wait: NO_WAIT }); + const t2 = performance.now(); + + logger.info('High value tx sent', { + txNum: highValueTxs, + feeAmount, + cloneMs: Math.round(t1 - t0), + sendMs: Math.round(t2 - t1), + totalMs: Math.round(t2 - t0), + }); return txHash.toString(); }; @@ -514,9 +562,11 @@ function sendTxsAtTps( return txHashes; } -async function cloneTx(tx: ProvenTx, priorityFee: GasFees): Promise { - // Clone the transaction +async function cloneTx(tx: ProvenTx, priorityFee: GasFees, logger: Logger): Promise { + const t0 = performance.now(); const clonedTxData = Tx.clone(tx, false); + const t1 = performance.now(); + (clonedTxData.data.constants.txContext.gasSettings as any).maxPriorityFeesPerGas = priorityFee; if (clonedTxData.data.forRollup) { @@ -534,7 +584,17 @@ async function cloneTx(tx: ProvenTx, priorityFee: GasFees): Promise { clonedTxData.data.forPublic.nonRevertibleAccumulatedData.nullifiers[i] = Fr.random(); } } + const t2 = performance.now(); + const clonedTx = new ProvenTx((tx as any).node, clonedTxData, tx.offchainEffects, tx.stats); await clonedTx.recomputeHash(); + const t3 = performance.now(); + + logger.debug('cloneTx timing', { + cloneMs: Math.round(t1 - t0), + mutateMs: Math.round(t2 - t1), + rehashMs: Math.round(t3 - t2), + totalMs: Math.round(t3 - t0), + }); return clonedTx; } diff --git a/yarn-project/end-to-end/src/spartan/n_tps_prove.test.ts b/yarn-project/end-to-end/src/spartan/n_tps_prove.test.ts index 59d7d567a208..48986bd06c53 100644 --- a/yarn-project/end-to-end/src/spartan/n_tps_prove.test.ts +++ b/yarn-project/end-to-end/src/spartan/n_tps_prove.test.ts @@ -7,7 +7,7 @@ import { AccountManager } from '@aztec/aztec.js/wallet'; import { RollupCheatCodes } from '@aztec/aztec/testing'; import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants'; import { EthCheatCodesWithState } from '@aztec/ethereum/test'; -import { SlotNumber } from '@aztec/foundation/branded-types'; +import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types'; import { timesParallel } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/curves/bn254'; import { type Logger, createLogger } from '@aztec/foundation/log'; @@ -39,13 +39,14 @@ import { const config = { ...setupEnvironment(process.env) }; -const NUM_WALLETS = config.REAL_VERIFIER ? 10 : 1; const TARGET_TPS = parseFloat(process.env.TPS ?? '1'); if (!Number.isFinite(TARGET_TPS)) { throw new Error('Invalid TPS: ' + process.env.TPS); } +const NUM_WALLETS = config.REAL_VERIFIER ? TARGET_TPS * 11 : 1; // add an extra wallet for each 1TPS in order to be able to maintain target TPS. This is assuming tx creation takes 9-10s const TARGET_PROVER_AGENTS = parseInt(process.env.TARGET_PROVER_AGENTS ?? '200'); +const SLOTS_BUFFER = 1; const epochDurationSlots = config.AZTEC_EPOCH_DURATION; const slotDurationSeconds = config.AZTEC_SLOT_DURATION; @@ -253,14 +254,40 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { const l1ContractAddresses = await aztecNode.getNodeInfo().then(n => n.l1ContractAddresses); rollupCheatCodes = new RollupCheatCodes(ethCheatCodes, l1ContractAddresses); + // Start wallet creation in the background (only needs rpcUrl) + logger.info(`Creating ${NUM_WALLETS} wallet(s) in parallel with block wait...`); + const walletCreationPromise = timesParallel(NUM_WALLETS, i => { + logger.info(`Creating wallet ${i + 1}/${NUM_WALLETS}`); + return createWorkerWalletClient(rpcUrl, config.REAL_VERIFIER, logger); + }); + // Wait for at least one block to be mined + const lagInEpochs = config.AZTEC_LAG_IN_EPOCHS_FOR_VALIDATOR_SET; + const estimatedFirstBlockSlot = (lagInEpochs + 1) * epochDurationSlots; + const currentSlotAtStart = await rollupCheatCodes.getSlot(); + const slotsUntilFirstBlock = Math.max(0, estimatedFirstBlockSlot - Number(currentSlotAtStart)); + const secondsUntilFirstBlock = slotsUntilFirstBlock * slotDurationSeconds; + const estimatedTime = new Date(Date.now() + secondsUntilFirstBlock * 1000); + logger.info( + `Waiting for first block (current slot ${currentSlotAtStart}, estimated first block at slot ${estimatedFirstBlockSlot}, ` + + `~${formatDuration(secondsUntilFirstBlock)} from now, around ${estimatedTime.toISOString()})`, + ); + let lastLoggedSlot: SlotNumber | undefined; await retryUntil( async () => { const blockNumber = await aztecNode.getBlockNumber(); if (blockNumber > INITIAL_L2_BLOCK_NUM) { return true; } - logger.info('Waiting for the first block to mine...'); + const slot = await rollupCheatCodes.getSlot(); + if (slot !== lastLoggedSlot) { + lastLoggedSlot = slot; + const slotsLeft = Math.max(0, estimatedFirstBlockSlot - Number(slot)); + const secondsLeft = slotsLeft * slotDurationSeconds; + logger.info( + `Waiting for the first block to mine (slot ${slot}, ~${formatDuration(secondsLeft)} remaining)...`, + ); + } return false; }, 'get block number', @@ -268,11 +295,9 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { 12, ); - logger.info(`Creating ${NUM_WALLETS} wallet(s)...`); - testWallets = await timesParallel(NUM_WALLETS, i => { - logger.info(`Creating wallet ${i + 1}/${NUM_WALLETS}`); - return createWorkerWalletClient(rpcUrl, config.REAL_VERIFIER, logger); - }); + logger.info(`First block produced. Deploying account contracts`); + + testWallets = await walletCreationPromise; wallets = testWallets.map(tw => tw.wallet); // Register FPC and create/deploy accounts @@ -347,14 +372,14 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { logger.info(`Current slot ${currentSlot} (${slotsIntoEpoch}/${epochDurationSlots})`); - const SLOTS_BUFFER = 1; if (slotsUntilNextEpoch > SLOTS_BUFFER) { const slotsToWait = slotsUntilNextEpoch - SLOTS_BUFFER; const targetSlot = SlotNumber(Number(currentSlot) + slotsToWait); // Use getSecondsUntilSlot to account for how far we are into the current slot const secondsToWait = (await rollupCheatCodes.getSecondsUntilSlot(targetSlot)) + 1; // add a 1s buffer + const endTime = new Date(Date.now() + secondsToWait * 1000); logger.info( - `Waiting ${secondsToWait}s (${slotsToWait} slots) until ${SLOTS_BUFFER} slots before epoch boundary...`, + `Waiting ${formatDuration(secondsToWait)} (${slotsToWait} slots) until ${SLOTS_BUFFER} slot(s) before epoch boundary (until ${endTime.toISOString()})...`, ); await sleep(secondsToWait * 1000); } @@ -372,23 +397,26 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { }); it(`sends ${TARGET_TPS} TPS for a full epoch and waits for proof`, async () => { - const [testEpoch, startSlot, { proven: startProvenBlockNumber, pending: startBlockNumber }] = await Promise.all([ - rollupCheatCodes.getEpoch(), - rollupCheatCodes.getSlot(), - rollupCheatCodes.getTips(), - ]); - logger.info(`Starting test in epoch ${testEpoch}, slot ${startSlot} (real_verifier=${config.REAL_VERIFIER})`); - - const txsToSend = Math.ceil(TARGET_TPS * epochDurationSeconds); + const [testEpoch, startSlot] = await Promise.all([rollupCheatCodes.getEpoch(), rollupCheatCodes.getSlot()]); + const targetEpoch = testEpoch + 1; + logger.info( + `Starting test in epoch ${testEpoch}, slot ${startSlot}, target epoch is ${targetEpoch} (real_verifier=${config.REAL_VERIFIER})`, + ); + const msPerTx = 1000 / TARGET_TPS; - logger.info(`Will send ${txsToSend} transactions at ${TARGET_TPS} TPS over ${epochDurationSeconds} seconds`); + const sendDurationMs = epochDurationSeconds * 1000 + SLOTS_BUFFER * slotDurationSeconds * 1000; // 2 slot buffer + logger.info(`Will send transactions at ${TARGET_TPS} TPS for ${epochDurationSeconds}s (1 epoch)`); - const scaleUpAtTx = Math.max(0, txsToSend - Math.ceil(TARGET_TPS * 8 * slotDurationSeconds)); const sentTxs: TxHash[] = []; const sendStartTime = performance.now(); - - for (let i = 0; i < txsToSend; i++) { - if (i === scaleUpAtTx) { + const sendDeadline = sendStartTime + sendDurationMs; + const scaleUpTime = sendDeadline - 8 * slotDurationSeconds * 1000; + let scaledUp = false; + let i = 0; + + while (performance.now() < sendDeadline) { + if (!scaledUp && performance.now() >= scaleUpTime) { + scaledUp = true; logger.info(`Scaling prover agents to ${TARGET_PROVER_AGENTS} (8 slots before end of tx sending)`); void scaleProverAgents(config.NAMESPACE, TARGET_PROVER_AGENTS, logger).catch(err => logger.error(`Failed to scale prover agents: ${err}`), @@ -409,10 +437,14 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { // consume tx const tx = producer.readyTx; producer.readyTx = null; - await aztecNode.sendTx(tx); - sentTxs.push(tx.getTxHash()); - - logger.info(`Sent tx ${i + 1}/${txsToSend}`); + try { + await aztecNode.sendTx(tx); + sentTxs.push(tx.getTxHash()); + logger.info(`Sent tx ${i + 1}`); + } catch (err) { + logger.warn(`Failed to send tx ${i + 1}: ${err}`); + } + i++; // sleep to maintain target TPS const elapsed = performance.now() - loopStart; @@ -429,6 +461,7 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { logger.info(`Finished sending ${totalSent} txs in ${(sendEndTime - sendStartTime) / 1000}s`); logger.info('Waiting for transactions to be mined...'); + const txsPerBlock = new Map(); const pendingTxs = new Map(); for (const txHash of sentTxs) { pendingTxs.set(txHash.toString(), txHash); @@ -438,8 +471,10 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { let failureCount = 0; const batchSize = 10; - const TX_MINING_TIMEOUT_S = epochDurationSeconds; + const TX_MINING_TIMEOUT_S = 5 * slotDurationSeconds; + const NO_PROGRESS_TIMEOUT_S = 3 * slotDurationSeconds; const miningTimer = new Timer(); + let lastProgressTime = performance.now(); while (pendingTxs.size > 0) { const entries = [...pendingTxs.entries()]; const start = Math.floor(Math.random() * Math.max(1, entries.length - batchSize + 1)); @@ -455,6 +490,9 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { logger.debug( `tx ${hashStr} included in block ${receipt.blockNumber}. Status: ${receipt.status}. Execution: ${receipt.executionResult}`, ); + if (receipt.blockNumber !== undefined) { + txsPerBlock.set(receipt.blockNumber, (txsPerBlock.get(receipt.blockNumber) ?? 0) + 1); + } pendingTxs.delete(hashStr); successCount++; processedCount++; @@ -467,11 +505,23 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { } if (processedCount > 0) { + lastProgressTime = performance.now(); logger.info( `Processed ${totalSent - pendingTxs.size}/${totalSent} transactions (${successCount} success, ${failureCount} failed)`, ); } + const noProgressSeconds = (performance.now() - lastProgressTime) / 1000; + if (noProgressSeconds > NO_PROGRESS_TIMEOUT_S) { + logger.warn( + `No mining progress for ${Math.floor(noProgressSeconds)}s. ` + + `Giving up on ${pendingTxs.size}/${totalSent} transactions. ` + + `Remaining tx hashes: ${[...pendingTxs.values()].map(h => h.toString()).join(', ')}`, + ); + failureCount += pendingTxs.size; + break; + } + if (miningTimer.s() > TX_MINING_TIMEOUT_S) { const remainingHashes = [...pendingTxs.values()].map(h => h.toString()); logger.warn( @@ -494,20 +544,38 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { metrics.recordSuccessfulTxs(successCount); logger.info(`Transaction inclusion complete: ${successCount} succeeded, ${failureCount} failed`); - const endBlockNumber = await aztecNode.getBlockNumber(); - const currentEpoch = await rollupCheatCodes.getEpoch(); - logger.info( - `Transactions landed in blocks ${startBlockNumber + 1} to ${endBlockNumber}, current epoch: ${currentEpoch}`, - ); + // Map blocks to epochs and find the epoch with the most txs + const txsPerEpoch = new Map(); + const maxBlockPerEpoch = new Map(); - const targetProvenBlock = endBlockNumber; - const proofStartTime = Date.now(); + for (const [blockNum, txCount] of txsPerBlock) { + const header = await aztecNode.getBlockHeader(BlockNumber(blockNum)); + const epoch = Math.floor(Number(header!.getSlot()) / epochDurationSlots); + txsPerEpoch.set(epoch, (txsPerEpoch.get(epoch) ?? 0) + txCount); + maxBlockPerEpoch.set(epoch, Math.max(maxBlockPerEpoch.get(epoch) ?? 0, blockNum)); + } - logger.info(`Waiting for proven chain to advance ${startProvenBlockNumber} -> ${targetProvenBlock}...`); + let targetProofEpoch = 0; + let maxTxCount = 0; + for (const [epoch, count] of txsPerEpoch) { + logger.info(`Epoch ${epoch}: ${count} txs`); + if (count > maxTxCount) { + maxTxCount = count; + targetProofEpoch = epoch; + } + } + + const targetProvenBlock = maxBlockPerEpoch.get(targetProofEpoch)!; + const proofStartTime = Date.now(); + logger.info( + `Epoch ${targetProofEpoch} has the most txs (${maxTxCount}). Waiting for block ${targetProvenBlock} to be proven.`, + ); // Poll for proof completion while detecting reorgs - let lastBlockNumber = endBlockNumber; - const PROOF_TIMEOUT_S = epochDurationSeconds; + let lastBlockNumber = await aztecNode.getBlockNumber(); + const currentProvenBlock = await aztecNode.getProvenBlockNumber(); + logger.info(`Waiting for proven chain to advance ${currentProvenBlock} -> ${targetProvenBlock}...`); + const PROOF_TIMEOUT_S = 2 * epochDurationSeconds; const proofTimer = new Timer(); while (true) { @@ -550,7 +618,7 @@ describe(`prove ${TARGET_TPS}TPS test`, () => { const proofDurationSeconds = proofDurationMs / 1000; metrics.recordProofDuration(proofDurationSeconds); - logger.info(`Epoch proof completed in ${proofDurationSeconds.toFixed(1)}s`); + logger.info(`Epoch ${targetProofEpoch} proof completed in ${proofDurationSeconds.toFixed(1)}s`); const finalProvenBlock = await aztecNode.getProvenBlockNumber(); expect(finalProvenBlock).toBeGreaterThanOrEqual(targetProvenBlock); @@ -563,9 +631,8 @@ async function createTx( wallet: WorkerWallet, accountAddress: AztecAddress, benchmarkContract: AvmGadgetsTestContract, - logger: Logger, + _logger: Logger, ): Promise { - logger.info('Creating prototype transaction...'); const sponsor = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress()); const options = { from: accountAddress, @@ -574,7 +641,6 @@ async function createTx( const interaction = benchmarkContract.methods.keccak_hash_1400(Array(1400).fill(42)); const execPayload = await interaction.request(options); const tx = await wallet.proveTx(execPayload, toSendOptions(options)); - logger.info('Prototype transaction created'); return tx; } @@ -637,6 +703,15 @@ async function startProducing( } } +function formatDuration(totalSeconds: number): string { + const minutes = Math.floor(totalSeconds / 60); + const seconds = Math.round(totalSeconds % 60); + if (minutes === 0) { + return `${seconds}s`; + } + return `${minutes}m ${seconds}s`; +} + async function captureMetricsSnapshot(client: PrometheusClient, logger: Logger): Promise { const snapshot: MetricsSnapshot = { retriedJobs: 0, diff --git a/yarn-project/end-to-end/src/spartan/setup_test_wallets.ts b/yarn-project/end-to-end/src/spartan/setup_test_wallets.ts index 0f0a63458835..d2a0908c62a8 100644 --- a/yarn-project/end-to-end/src/spartan/setup_test_wallets.ts +++ b/yarn-project/end-to-end/src/spartan/setup_test_wallets.ts @@ -121,16 +121,27 @@ export async function deploySponsoredTestAccountsWithTokens( } async function deployAccountWithDiagnostics( - account: { getDeployMethod: () => Promise<{ send: (opts: any) => any }>; address: any }, + account: { getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>; address: any }, paymentMethod: SponsoredFeePaymentMethod, aztecNode: AztecNode, logger: Logger, accountLabel: string, + estimateGas?: boolean, ): Promise { const deployMethod = await account.getDeployMethod(); let txHash; try { - const deployResult = await deployMethod.send({ from: AztecAddress.ZERO, fee: { paymentMethod }, wait: NO_WAIT }); + let gasSettings; + if (estimateGas) { + const sim = await deployMethod.simulate({ from: AztecAddress.ZERO, fee: { paymentMethod } }); + gasSettings = sim.estimatedGas; + logger.info(`${accountLabel} estimated gas: DA=${gasSettings.gasLimits.daGas} L2=${gasSettings.gasLimits.l2Gas}`); + } + const deployResult = await deployMethod.send({ + from: AztecAddress.ZERO, + fee: { paymentMethod, gasSettings }, + wait: NO_WAIT, + }); txHash = deployResult.txHash; await waitForTx(aztecNode, txHash, { timeout: 2400 }); logger.info(`${accountLabel} deployed at ${account.address}`); @@ -153,18 +164,29 @@ async function deployAccountWithDiagnostics( } async function deployAccountsInBatches( - accounts: { getDeployMethod: () => Promise<{ send: (opts: any) => any }>; address: any }[], + accounts: { + getDeployMethod: () => Promise<{ simulate: (opts: any) => any; send: (opts: any) => any }>; + address: any; + }[], paymentMethod: SponsoredFeePaymentMethod, aztecNode: AztecNode, logger: Logger, labelPrefix: string, batchSize = 2, + estimateGas?: boolean, ): Promise { for (let i = 0; i < accounts.length; i += batchSize) { const batch = accounts.slice(i, i + batchSize); await Promise.all( batch.map((account, idx) => - deployAccountWithDiagnostics(account, paymentMethod, aztecNode, logger, `${labelPrefix}${i + idx + 1}`), + deployAccountWithDiagnostics( + account, + paymentMethod, + aztecNode, + logger, + `${labelPrefix}${i + idx + 1}`, + estimateGas, + ), ), ); } @@ -175,6 +197,7 @@ export async function deploySponsoredTestAccounts( aztecNode: AztecNode, logger: Logger, numberOfFundedWallets = 1, + opts?: { estimateGas?: boolean }, ): Promise { const [recipient, ...funded] = await generateSchnorrAccounts(numberOfFundedWallets + 1); const recipientAccount = await wallet.createSchnorrAccount(recipient.secret, recipient.salt); @@ -184,8 +207,23 @@ export async function deploySponsoredTestAccounts( const paymentMethod = new SponsoredFeePaymentMethod(await getSponsoredFPCAddress()); - await deployAccountWithDiagnostics(recipientAccount, paymentMethod, aztecNode, logger, 'Recipient account'); - await deployAccountsInBatches(fundedAccounts, paymentMethod, aztecNode, logger, 'Funded account ', 2); + await deployAccountWithDiagnostics( + recipientAccount, + paymentMethod, + aztecNode, + logger, + 'Recipient account', + opts?.estimateGas, + ); + await deployAccountsInBatches( + fundedAccounts, + paymentMethod, + aztecNode, + logger, + 'Funded account ', + 2, + opts?.estimateGas, + ); return { aztecNode, diff --git a/yarn-project/end-to-end/src/spartan/utils/index.ts b/yarn-project/end-to-end/src/spartan/utils/index.ts index b4ecc612825f..8f917cecdcdc 100644 --- a/yarn-project/end-to-end/src/spartan/utils/index.ts +++ b/yarn-project/end-to-end/src/spartan/utils/index.ts @@ -41,6 +41,9 @@ export { applyNetworkShaping, } from './chaos.js'; +// Helm +export { hasDeployedHelmRelease } from './helm.js'; + // Bot management export { restartBot, installTransferBot, uninstallTransferBot } from './bot.js'; diff --git a/yarn-project/epoch-cache/src/epoch_cache.test.ts b/yarn-project/epoch-cache/src/epoch_cache.test.ts index 555cf707f2bf..e1e3ffba22e1 100644 --- a/yarn-project/epoch-cache/src/epoch_cache.test.ts +++ b/yarn-project/epoch-cache/src/epoch_cache.test.ts @@ -73,6 +73,7 @@ describe('EpochCache', () => { epochDuration: EPOCH_DURATION, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, lagInEpochsForValidatorSet: 2, lagInEpochsForRandao: 2, }; diff --git a/yarn-project/epoch-cache/src/epoch_cache.ts b/yarn-project/epoch-cache/src/epoch_cache.ts index ec197341406a..5c29e207a015 100644 --- a/yarn-project/epoch-cache/src/epoch_cache.ts +++ b/yarn-project/epoch-cache/src/epoch_cache.ts @@ -108,6 +108,7 @@ export class EpochCache implements EpochCacheInterface { lagInEpochsForValidatorSet, lagInEpochsForRandao, targetCommitteeSize, + rollupManaLimit, ] = await Promise.all([ rollup.getL1StartBlock(), rollup.getL1GenesisTime(), @@ -117,6 +118,7 @@ export class EpochCache implements EpochCacheInterface { rollup.getLagInEpochsForValidatorSet(), rollup.getLagInEpochsForRandao(), rollup.getTargetCommitteeSize(), + rollup.getManaLimit(), ] as const); const l1RollupConstants = { @@ -129,6 +131,7 @@ export class EpochCache implements EpochCacheInterface { lagInEpochsForValidatorSet: Number(lagInEpochsForValidatorSet), lagInEpochsForRandao: Number(lagInEpochsForRandao), targetCommitteeSize: Number(targetCommitteeSize), + rollupManaLimit: Number(rollupManaLimit), }; return new EpochCache(rollup, l1RollupConstants, deps.dateProvider); diff --git a/yarn-project/epoch-cache/src/test/test_epoch_cache.ts b/yarn-project/epoch-cache/src/test/test_epoch_cache.ts index 04e8c0afdd72..ecb2b3b47c2b 100644 --- a/yarn-project/epoch-cache/src/test/test_epoch_cache.ts +++ b/yarn-project/epoch-cache/src/test/test_epoch_cache.ts @@ -14,6 +14,7 @@ const DEFAULT_L1_CONSTANTS: L1RollupConstants = { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; /** diff --git a/yarn-project/ethereum/src/contracts/rollup.ts b/yarn-project/ethereum/src/contracts/rollup.ts index 40e10d287284..8132c2bfa451 100644 --- a/yarn-project/ethereum/src/contracts/rollup.ts +++ b/yarn-project/ethereum/src/contracts/rollup.ts @@ -392,16 +392,25 @@ export class RollupContract { epochDuration: number; proofSubmissionEpochs: number; targetCommitteeSize: number; + rollupManaLimit: number; }> { - const [l1StartBlock, l1GenesisTime, slotDuration, epochDuration, proofSubmissionEpochs, targetCommitteeSize] = - await Promise.all([ - this.getL1StartBlock(), - this.getL1GenesisTime(), - this.getSlotDuration(), - this.getEpochDuration(), - this.getProofSubmissionEpochs(), - this.getTargetCommitteeSize(), - ]); + const [ + l1StartBlock, + l1GenesisTime, + slotDuration, + epochDuration, + proofSubmissionEpochs, + targetCommitteeSize, + rollupManaLimit, + ] = await Promise.all([ + this.getL1StartBlock(), + this.getL1GenesisTime(), + this.getSlotDuration(), + this.getEpochDuration(), + this.getProofSubmissionEpochs(), + this.getTargetCommitteeSize(), + this.getManaLimit(), + ]); return { l1StartBlock, l1GenesisTime, @@ -409,6 +418,7 @@ export class RollupContract { epochDuration: Number(epochDuration), proofSubmissionEpochs: Number(proofSubmissionEpochs), targetCommitteeSize, + rollupManaLimit: Number(rollupManaLimit), }; } diff --git a/yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.test.ts b/yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.test.ts index 593dd1831a3d..a3a1d77e0caf 100644 --- a/yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.test.ts +++ b/yarn-project/ethereum/src/l1_tx_utils/l1_tx_utils.test.ts @@ -454,6 +454,50 @@ describe('L1TxUtils', () => { } }); + it('bumps gas fees correctly at very low wei values (ceiling division)', async () => { + await cheatCodes.setNextBlockBaseFeePerGas(1n); + await cheatCodes.evmMine(); + + const originalGetBlobBaseFee = l1Client.getBlobBaseFee; + l1Client.getBlobBaseFee = () => Promise.resolve(1n); + + const originalEstimate = l1Client.estimateMaxPriorityFeePerGas; + l1Client.estimateMaxPriorityFeePerGas = () => Promise.resolve(0n); + + try { + gasUtils.updateConfig({ + ...defaultL1TxUtilsConfig, + stallTimeMs: 12_000, + priorityFeeBumpPercentage: 0, + minimumPriorityFeePerGas: 0, + }); + + const gasPrice = await gasUtils['getGasPrice'](undefined, true); + + // With ceiling division: (1n * 1125n + 999n) / 1000n = 2n + expect(gasPrice.maxFeePerGas).toBe(2n); + expect(gasPrice.maxFeePerBlobGas).toBe(2n); + + // Verify compounding works across multiple iterations + gasUtils.updateConfig({ + ...defaultL1TxUtilsConfig, + stallTimeMs: 24_000, + priorityFeeBumpPercentage: 0, + minimumPriorityFeePerGas: 0, + }); + + const gasPrice2 = await gasUtils['getGasPrice'](undefined, true); + + // Iteration 1: ceil(1 * 1125 / 1000) = 2 + // Iteration 2: ceil(2 * 1125 / 1000) = ceil(2.25) = 3 + expect(gasPrice2.maxFeePerGas).toBe(3n); + expect(gasPrice2.maxFeePerBlobGas).toBe(3n); + } finally { + l1Client.getBlobBaseFee = originalGetBlobBaseFee; + l1Client.estimateMaxPriorityFeePerGas = originalEstimate; + } + }); + it('calculates correct gas prices for retry attempts', async () => { await cheatCodes.setNextBlockBaseFeePerGas(WEI_CONST); await cheatCodes.evmMine(); diff --git a/yarn-project/ethereum/src/l1_tx_utils/readonly_l1_tx_utils.ts b/yarn-project/ethereum/src/l1_tx_utils/readonly_l1_tx_utils.ts index 526a64ea4c18..b54b6d027b64 100644 --- a/yarn-project/ethereum/src/l1_tx_utils/readonly_l1_tx_utils.ts +++ b/yarn-project/ethereum/src/l1_tx_utils/readonly_l1_tx_utils.ts @@ -130,9 +130,10 @@ export class ReadOnlyL1TxUtils { const numBlocks = Math.ceil(gasConfig.stallTimeMs! / BLOCK_TIME_MS); for (let i = 0; i < numBlocks; i++) { // each block can go up 12.5% from previous baseFee - maxFeePerGas = (maxFeePerGas * (1_000n + 125n)) / 1_000n; + // ceil, (a+b-1)/b, to avoid truncation at small values (e.g. 1 wei blob base fee) + maxFeePerGas = (maxFeePerGas * (1_000n + 125n) + 999n) / 1_000n; // same for blob gas fee - maxFeePerBlobGas = (maxFeePerBlobGas * (1_000n + 125n)) / 1_000n; + maxFeePerBlobGas = (maxFeePerBlobGas * (1_000n + 125n) + 999n) / 1_000n; } if (attempt > 0) { @@ -242,13 +243,16 @@ export class ReadOnlyL1TxUtils { const gasConfig = { ...this.config, ..._gasConfig }; let initialEstimate = 0n; if (_blobInputs) { - // @note requests with blobs also require maxFeePerBlobGas to be set + // @note requests with blobs also require maxFeePerBlobGas to be set. + // Use 2x buffer for maxFeePerBlobGas to avoid stale fees and to pass EIP-4844 validation (even if it is a gas estimation call). + // 1. maxFeePerBlobGas >= blobBaseFee + // 2. account balance >= gas * maxFeePerGas + maxFeePerBlobGas * blobCount + value const gasPrice = await this.getGasPrice(gasConfig, true, 0); initialEstimate = await this.client.estimateGas({ account, ...request, ..._blobInputs, - maxFeePerBlobGas: gasPrice.maxFeePerBlobGas!, + maxFeePerBlobGas: gasPrice.maxFeePerBlobGas! * 2n, gas: MAX_L1_TX_LIMIT, blockTag: 'latest', }); diff --git a/yarn-project/foundation/src/config/env_var.ts b/yarn-project/foundation/src/config/env_var.ts index 392b3d713e18..a547219e839c 100644 --- a/yarn-project/foundation/src/config/env_var.ts +++ b/yarn-project/foundation/src/config/env_var.ts @@ -168,6 +168,7 @@ export type EnvVar = | 'PROVER_BROKER_MAX_EPOCHS_TO_KEEP_RESULTS_FOR' | 'PROVER_BROKER_DEBUG_REPLAY_ENABLED' | 'PROVER_CANCEL_JOBS_ON_STOP' + | 'PROVER_ENQUEUE_CONCURRENCY' | 'PROVER_COORDINATION_NODE_URLS' | 'PROVER_PROOF_STORE' | 'PROVER_FAILED_PROOF_STORE' diff --git a/yarn-project/ivc-integration/package.json b/yarn-project/ivc-integration/package.json index 94a0dde8621b..440564d7fc67 100644 --- a/yarn-project/ivc-integration/package.json +++ b/yarn-project/ivc-integration/package.json @@ -93,7 +93,7 @@ "jest-mock-extended": "^4.0.0", "msgpackr": "^1.11.2", "resolve-typescript-plugin": "^2.0.1", - "serve": "^14.2.1", + "serve": "^14.2.6", "ts-loader": "^9.5.4", "ts-node": "^10.9.1", "typescript": "^5.3.3", diff --git a/yarn-project/native/src/native_module.ts b/yarn-project/native/src/native_module.ts index bcea92100216..6966e33193d7 100644 --- a/yarn-project/native/src/native_module.ts +++ b/yarn-project/native/src/native_module.ts @@ -131,7 +131,7 @@ export function cancelSimulation(token: CancellationToken): void { * Maximum number of concurrent AVM simulations. Each simulation spawns a dedicated OS thread, * so this controls resource usage. Defaults to 4. Set to 0 for unlimited. */ -const AVM_MAX_CONCURRENT_SIMULATIONS = parseInt(process.env.AVM_MAX_CONCURRENT_SIMULATIONS ?? '4', 10); +export const AVM_MAX_CONCURRENT_SIMULATIONS = parseInt(process.env.AVM_MAX_CONCURRENT_SIMULATIONS ?? '4', 10); const avmSimulationSemaphore = AVM_MAX_CONCURRENT_SIMULATIONS > 0 ? new Semaphore(AVM_MAX_CONCURRENT_SIMULATIONS) : null; diff --git a/yarn-project/p2p/src/client/factory.ts b/yarn-project/p2p/src/client/factory.ts index eb277343c5a6..78878c6caf20 100644 --- a/yarn-project/p2p/src/client/factory.ts +++ b/yarn-project/p2p/src/client/factory.ts @@ -87,10 +87,16 @@ export async function createP2PClient( // We accept transactions if they are not expired by the next slot and block number (checked based on the ExpirationTimestamp field) const currentBlockNumber = await archiver.getBlockNumber(); const { ts: nextSlotTimestamp } = epochCache.getEpochAndSlotInNextL1Slot(); + const l1Constants = await archiver.getL1Constants(); return createTxValidatorForTransactionsEnteringPendingTxPool( worldStateSynchronizer, nextSlotTimestamp, BlockNumber(currentBlockNumber + 1), + { + rollupManaLimit: l1Constants.rollupManaLimit, + maxBlockL2Gas: config.validateMaxL2BlockGas, + maxBlockDAGas: config.validateMaxDABlockGas, + }, ); }, }, diff --git a/yarn-project/p2p/src/client/p2p_client.ts b/yarn-project/p2p/src/client/p2p_client.ts index a6be4b34799a..f53b3b0504b5 100644 --- a/yarn-project/p2p/src/client/p2p_client.ts +++ b/yarn-project/p2p/src/client/p2p_client.ts @@ -679,10 +679,11 @@ export class P2PClient extends WithTracer implements P2P { if (oldCheckpointNumber <= CheckpointNumber.ZERO) { return false; } - const isEpochPrune = oldCheckpointNumber !== newCheckpoint.number; - this.log.info( - `Detected epoch prune: ${isEpochPrune}. Old checkpoint: ${oldCheckpointNumber}, new checkpoint: ${newCheckpoint.number}`, - ); + const newCheckpointNumber = newCheckpoint.number; + const isEpochPrune = oldCheckpointNumber !== newCheckpointNumber; + if (isEpochPrune) { + this.log.info(`Detected epoch prune to ${newCheckpointNumber}`, { oldCheckpointNumber, newCheckpointNumber }); + } return isEpochPrune; } diff --git a/yarn-project/p2p/src/client/test/p2p_client.integration_batch_txs.test.ts b/yarn-project/p2p/src/client/test/p2p_client.integration_batch_txs.test.ts index 2a935748e48d..59503a89f336 100644 --- a/yarn-project/p2p/src/client/test/p2p_client.integration_batch_txs.test.ts +++ b/yarn-project/p2p/src/client/test/p2p_client.integration_batch_txs.test.ts @@ -76,6 +76,7 @@ describe('p2p client integration batch txs', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); txPool.hasTxs.mockResolvedValue([]); diff --git a/yarn-project/p2p/src/client/test/p2p_client.integration_block_txs.test.ts b/yarn-project/p2p/src/client/test/p2p_client.integration_block_txs.test.ts index f9de992f1810..9f8464e4dd08 100644 --- a/yarn-project/p2p/src/client/test/p2p_client.integration_block_txs.test.ts +++ b/yarn-project/p2p/src/client/test/p2p_client.integration_block_txs.test.ts @@ -66,6 +66,7 @@ describe('p2p client integration block txs protocol ', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); txPool.isEmpty.mockResolvedValue(true); diff --git a/yarn-project/p2p/src/client/test/p2p_client.integration_message_propagation.test.ts b/yarn-project/p2p/src/client/test/p2p_client.integration_message_propagation.test.ts index 265aec7b6709..ca9ad2bbd2ad 100644 --- a/yarn-project/p2p/src/client/test/p2p_client.integration_message_propagation.test.ts +++ b/yarn-project/p2p/src/client/test/p2p_client.integration_message_propagation.test.ts @@ -70,6 +70,7 @@ describe('p2p client integration message propagation', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); const mockMerkleTreeOps = mock(); diff --git a/yarn-project/p2p/src/client/test/p2p_client.integration_reqresp.test.ts b/yarn-project/p2p/src/client/test/p2p_client.integration_reqresp.test.ts index 39bb76ecdc3a..78fc5ac35473 100644 --- a/yarn-project/p2p/src/client/test/p2p_client.integration_reqresp.test.ts +++ b/yarn-project/p2p/src/client/test/p2p_client.integration_reqresp.test.ts @@ -56,6 +56,7 @@ describe('p2p client integration reqresp', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); txPool.isEmpty.mockResolvedValue(true); diff --git a/yarn-project/p2p/src/client/test/p2p_client.integration_status_handshake.test.ts b/yarn-project/p2p/src/client/test/p2p_client.integration_status_handshake.test.ts index 5a01506ff304..b571b1b25001 100644 --- a/yarn-project/p2p/src/client/test/p2p_client.integration_status_handshake.test.ts +++ b/yarn-project/p2p/src/client/test/p2p_client.integration_status_handshake.test.ts @@ -55,6 +55,7 @@ describe('p2p client integration status handshake', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); txPool.isEmpty.mockResolvedValue(true); diff --git a/yarn-project/p2p/src/config.ts b/yarn-project/p2p/src/config.ts index 73d37be73276..a6bf73c00280 100644 --- a/yarn-project/p2p/src/config.ts +++ b/yarn-project/p2p/src/config.ts @@ -43,6 +43,12 @@ export interface P2PConfig /** Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set. */ validateMaxTxsPerBlock?: number; + /** Maximum L2 gas per block for validation. When set, txs exceeding this limit are rejected. */ + validateMaxL2BlockGas?: number; + + /** Maximum DA gas per block for validation. When set, txs exceeding this limit are rejected. */ + validateMaxDABlockGas?: number; + /** A flag dictating whether the P2P subsystem should be enabled. */ p2pEnabled: boolean; @@ -211,6 +217,16 @@ export const p2pConfigMappings: ConfigMappingsType = { 'Maximum transactions per block for validation. Overrides maxTxsPerBlock for gossip validation when set.', parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined), }, + validateMaxL2BlockGas: { + env: 'VALIDATOR_MAX_L2_BLOCK_GAS', + description: 'Maximum L2 gas per block for validation. When set, txs exceeding this limit are rejected.', + parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined), + }, + validateMaxDABlockGas: { + env: 'VALIDATOR_MAX_DA_BLOCK_GAS', + description: 'Maximum DA gas per block for validation. When set, txs exceeding this limit are rejected.', + parseEnv: (val: string) => (val ? parseInt(val, 10) : undefined), + }, p2pEnabled: { env: 'P2P_ENABLED', description: 'A flag dictating whether the P2P subsystem should be enabled.', diff --git a/yarn-project/p2p/src/mem_pools/tx_pool/priority.ts b/yarn-project/p2p/src/mem_pools/tx_pool/priority.ts index bb8cb284565d..c2677d49558e 100644 --- a/yarn-project/p2p/src/mem_pools/tx_pool/priority.ts +++ b/yarn-project/p2p/src/mem_pools/tx_pool/priority.ts @@ -1,3 +1,4 @@ +import { minBigint } from '@aztec/foundation/bigint'; import { Buffer32 } from '@aztec/foundation/buffer'; import type { Tx } from '@aztec/stdlib/tx'; @@ -11,10 +12,12 @@ export function getPendingTxPriority(tx: Tx): string { } /** - * Returns the priority of a tx. + * Returns the priority of a tx based on the priority fees, capped by the max fees per gas. */ export function getTxPriorityFee(tx: Tx): bigint { - const priorityFees = tx.getGasSettings().maxPriorityFeesPerGas; - const totalFees = priorityFees.feePerDaGas + priorityFees.feePerL2Gas; + const { maxPriorityFeesPerGas: priorityFees, maxFeesPerGas } = tx.getGasSettings(); + const totalFees = + minBigint(maxFeesPerGas.feePerDaGas, priorityFees.feePerDaGas) + + minBigint(maxFeesPerGas.feePerL2Gas, priorityFees.feePerL2Gas); return totalFees; } diff --git a/yarn-project/p2p/src/mem_pools/tx_pool/tx_pool_test_suite.ts b/yarn-project/p2p/src/mem_pools/tx_pool/tx_pool_test_suite.ts index 0cb778223378..752216460af4 100644 --- a/yarn-project/p2p/src/mem_pools/tx_pool/tx_pool_test_suite.ts +++ b/yarn-project/p2p/src/mem_pools/tx_pool/tx_pool_test_suite.ts @@ -204,7 +204,9 @@ export function describeTxPool(getTxPool: () => TxPool) { it('returns pending tx hashes sorted by priority', async () => { const withPriorityFee = (tx: Tx, fee: number) => { - unfreeze(tx.data.constants.txContext.gasSettings).maxPriorityFeesPerGas = new GasFees(fee, fee); + const gs = unfreeze(tx.data.constants.txContext.gasSettings); + gs.maxPriorityFeesPerGas = new GasFees(fee, fee); + gs.maxFeesPerGas = new GasFees(fee, fee); return tx; }; diff --git a/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.compat.test.ts b/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.compat.test.ts index 7f0e52312729..c0d75aeec210 100644 --- a/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.compat.test.ts +++ b/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.compat.test.ts @@ -97,7 +97,7 @@ describe('TxPoolV2 Compatibility Tests', () => { }); const mockFixedSizeTx = async (maxPriorityFeesPerGas?: GasFees) => { - const tx = await mockTx(nextTxSeed++, { maxPriorityFeesPerGas }); + const tx = await mockTx(nextTxSeed++, { maxPriorityFeesPerGas, maxFeesPerGas: maxPriorityFeesPerGas }); jest.spyOn(tx, 'getSize').mockReturnValue(mockFixedTxSize); return tx; }; @@ -272,7 +272,9 @@ describe('TxPoolV2 Compatibility Tests', () => { it('returns pending tx hashes sorted by priority', async () => { const withPriorityFee = (tx: Tx, fee: number) => { - unfreeze(tx.data.constants.txContext.gasSettings).maxPriorityFeesPerGas = new GasFees(fee, fee); + const gs = unfreeze(tx.data.constants.txContext.gasSettings); + gs.maxPriorityFeesPerGas = new GasFees(fee, fee); + gs.maxFeesPerGas = new GasFees(fee, fee); return tx; }; @@ -681,6 +683,7 @@ describe('TxPoolV2 Compatibility Tests', () => { const mockPublicTx = (seed: number, fee: number) => mockTx(seed, { maxPriorityFeesPerGas: new GasFees(fee, fee), + maxFeesPerGas: new GasFees(fee, fee), numberOfNonRevertiblePublicCallRequests: 1, }); diff --git a/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts b/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts index f778f6bb3f14..1d41cc370bf1 100644 --- a/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts +++ b/yarn-project/p2p/src/mem_pools/tx_pool_v2/tx_pool_v2.test.ts @@ -152,7 +152,8 @@ describe('TxPoolV2', () => { await archiveStore.delete(); }); - const mockTxWithFee = (seed: number, fee: number) => mockTx(seed, { maxPriorityFeesPerGas: new GasFees(fee, fee) }); + const mockTxWithFee = (seed: number, fee: number) => + mockTx(seed, { maxPriorityFeesPerGas: new GasFees(fee, fee), maxFeesPerGas: new GasFees(fee, fee) }); // Helper functions for string-based TxHash comparisons const toStrings = (hashes: TxHash[]) => hashes.map(h => h.toString()); @@ -161,6 +162,7 @@ describe('TxPoolV2', () => { const mockPublicTx = (seed: number, fee: number = 1) => mockTx(seed, { maxPriorityFeesPerGas: new GasFees(fee, fee), + maxFeesPerGas: new GasFees(fee, fee), numberOfNonRevertiblePublicCallRequests: 1, }); @@ -2786,6 +2788,50 @@ describe('TxPoolV2', () => { expect(pending[2].toString()).toEqual(hashOf(tx1)); }); + it('caps priority by maxFeesPerGas when maxPriorityFeesPerGas exceeds it', async () => { + // txGamed has absurdly high maxPriorityFeesPerGas but low maxFeesPerGas. + // Its effective priority should be capped by maxFeesPerGas (5 + 5 = 10). + const txGamed = await mockTx(1, { + maxPriorityFeesPerGas: new GasFees(1000, 1000), + maxFeesPerGas: new GasFees(5, 5), + }); + + // txHonest has properly set fees: priority 10 per dimension, max fees 10 per dimension. + // Its effective priority = 10 + 10 = 20. + const txHonest = await mockTxWithFee(2, 10); + + await pool.addPendingTxs([txGamed, txHonest]); + + // txHonest (effective priority 20) should rank above txGamed (effective priority 10, capped) + const pending = toStrings(await pool.getPendingTxHashes()); + expect(pending[0]).toEqual(hashOf(txHonest)); + expect(pending[1]).toEqual(hashOf(txGamed)); + }); + + it('tx with maxPriorityFeesPerGas > maxFeesPerGas does not evict properly priced tx', async () => { + await pool.updateConfig({ maxPendingTxCount: 1 }); + + // txHonest has priority fee = max fee = 10 per dimension, effective priority = 20 + const txHonest = await mockTxWithFee(1, 10); + await pool.addPendingTxs([txHonest]); + clearCallbackTracking(); + + // txGamed tries to game priority with huge priority fees but low max fees. + // Effective priority = min(1000, 5) + min(1000, 5) = 10, which is lower than txHonest's 20. + const txGamed = await mockTx(2, { + maxPriorityFeesPerGas: new GasFees(1000, 1000), + maxFeesPerGas: new GasFees(5, 5), + }); + + const result = await pool.addPendingTxs([txGamed]); + + // txGamed should be ignored since its capped priority (10) < txHonest's priority (20) + expect(toStrings(result.ignored)).toContain(hashOf(txGamed)); + expect(await pool.getPendingTxCount()).toBe(1); + expect(await pool.getTxStatus(txHonest.getTxHash())).toBe('pending'); + expectNoCallbacks(); + }); + it('getPendingTxHashes uses tx hash as tiebreaker when fees are equal', async () => { // Create transactions with the same priority fee const tx1 = await mockTxWithFee(1, 5); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/allowed_public_setup.ts b/yarn-project/p2p/src/msg_validators/tx_validator/allowed_public_setup.ts index b8709732a192..41231ae207b2 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/allowed_public_setup.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/allowed_public_setup.ts @@ -1,55 +1,30 @@ import { ProtocolContractAddress } from '@aztec/protocol-contracts'; import { AuthRegistryArtifact } from '@aztec/protocol-contracts/auth-registry'; import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice'; -import { FunctionSelector, countArgumentsSize } from '@aztec/stdlib/abi'; -import type { ContractArtifact, FunctionAbi } from '@aztec/stdlib/abi'; import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; -/** Returns the expected calldata length for a function: 1 (selector) + arguments size. */ -function getCalldataLength(artifact: ContractArtifact, functionName: string): number { - const allFunctions: FunctionAbi[] = (artifact.functions as FunctionAbi[]).concat( - artifact.nonDispatchPublicFunctions || [], - ); - const fn = allFunctions.find(f => f.name === functionName); - if (!fn) { - throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`); - } - return 1 + countArgumentsSize(fn); -} +import { buildAllowedElement } from './allowed_setup_helpers.js'; let defaultAllowedSetupFunctions: AllowedElement[] | undefined; /** Returns the default list of functions allowed to run in the setup phase of a transaction. */ export async function getDefaultAllowedSetupFunctions(): Promise { if (defaultAllowedSetupFunctions === undefined) { - const setAuthorizedInternalSelector = await FunctionSelector.fromSignature('_set_authorized((Field),Field,bool)'); - const setAuthorizedSelector = await FunctionSelector.fromSignature('set_authorized(Field,bool)'); - const increaseBalanceSelector = await FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'); - - defaultAllowedSetupFunctions = [ + defaultAllowedSetupFunctions = await Promise.all([ // AuthRegistry: needed for authwit support via private path (set_authorized_private enqueues _set_authorized) - { - address: ProtocolContractAddress.AuthRegistry, - selector: setAuthorizedInternalSelector, - calldataLength: getCalldataLength(AuthRegistryArtifact, '_set_authorized'), + buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, '_set_authorized', { onlySelf: true, rejectNullMsgSender: true, - }, + }), // AuthRegistry: needed for authwit support via public path (PublicFeePaymentMethod calls set_authorized directly) - { - address: ProtocolContractAddress.AuthRegistry, - selector: setAuthorizedSelector, - calldataLength: getCalldataLength(AuthRegistryArtifact, 'set_authorized'), + buildAllowedElement(AuthRegistryArtifact, { address: ProtocolContractAddress.AuthRegistry }, 'set_authorized', { rejectNullMsgSender: true, - }, + }), // FeeJuice: needed for claiming on the same tx as a spend (claim_and_end_setup enqueues this) - { - address: ProtocolContractAddress.FeeJuice, - selector: increaseBalanceSelector, - calldataLength: getCalldataLength(FeeJuiceArtifact, '_increase_public_balance'), + buildAllowedElement(FeeJuiceArtifact, { address: ProtocolContractAddress.FeeJuice }, '_increase_public_balance', { onlySelf: true, - }, - ]; + }), + ]); } return defaultAllowedSetupFunctions; } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/allowed_setup_helpers.ts b/yarn-project/p2p/src/msg_validators/tx_validator/allowed_setup_helpers.ts new file mode 100644 index 000000000000..3e63283c4696 --- /dev/null +++ b/yarn-project/p2p/src/msg_validators/tx_validator/allowed_setup_helpers.ts @@ -0,0 +1,31 @@ +import type { Fr } from '@aztec/foundation/curves/bn254'; +import { FunctionSelector, countArgumentsSize, getAllFunctionAbis } from '@aztec/stdlib/abi'; +import type { ContractArtifact } from '@aztec/stdlib/abi'; +import type { AztecAddress } from '@aztec/stdlib/aztec-address'; +import type { AllowedElement } from '@aztec/stdlib/interfaces/server'; + +/** + * Builds an AllowedElement from a contract artifact, deriving both the function selector + * and calldata length from the artifact instead of hardcoding signature strings. + */ +export async function buildAllowedElement( + artifact: ContractArtifact, + target: { address: AztecAddress } | { classId: Fr }, + functionName: string, + opts?: { onlySelf?: boolean; rejectNullMsgSender?: boolean }, +): Promise { + const allFunctions = getAllFunctionAbis(artifact); + const fn = allFunctions.find(f => f.name === functionName); + if (!fn) { + throw new Error(`Unknown function ${functionName} in artifact ${artifact.name}`); + } + const selector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters); + const calldataLength = 1 + countArgumentsSize(fn); + return { + ...target, + selector, + calldataLength, + ...(opts?.onlySelf ? { onlySelf: true } : {}), + ...(opts?.rejectNullMsgSender ? { rejectNullMsgSender: true } : {}), + } as AllowedElement; +} diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/factory.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/factory.test.ts index b52fb4ac740a..7cb2e794566c 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/factory.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/factory.test.ts @@ -208,6 +208,7 @@ describe('Validator factory functions', () => { timestamp: 100n, blockNumber: BlockNumber(5), txsPermitted: true, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); const aggregate = validator as AggregateTxValidator; @@ -235,6 +236,7 @@ describe('Validator factory functions', () => { timestamp: 100n, blockNumber: BlockNumber(5), txsPermitted: true, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); const aggregate = validator as AggregateTxValidator; @@ -252,6 +254,7 @@ describe('Validator factory functions', () => { timestamp: 100n, blockNumber: BlockNumber(5), txsPermitted: true, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); const aggregate = validator as AggregateTxValidator; @@ -296,7 +299,12 @@ describe('Validator factory functions', () => { describe('createTxValidatorForTransactionsEnteringPendingTxPool', () => { it('contains the state-dependent checks missed by well-formedness validators', async () => { - const validator = await createTxValidatorForTransactionsEnteringPendingTxPool(synchronizer, 100n, BlockNumber(5)); + const validator = await createTxValidatorForTransactionsEnteringPendingTxPool( + synchronizer, + 100n, + BlockNumber(5), + { rollupManaLimit: Number.MAX_SAFE_INTEGER }, + ); const aggregate = validator as AggregateTxValidator; expect(getValidatorNames(aggregate)).toEqual([ @@ -308,7 +316,9 @@ describe('Validator factory functions', () => { }); it('syncs world state before creating the validator', async () => { - await createTxValidatorForTransactionsEnteringPendingTxPool(synchronizer, 100n, BlockNumber(5)); + await createTxValidatorForTransactionsEnteringPendingTxPool(synchronizer, 100n, BlockNumber(5), { + rollupManaLimit: Number.MAX_SAFE_INTEGER, + }); expect(synchronizer.syncImmediate).toHaveBeenCalled(); }); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/factory.ts b/yarn-project/p2p/src/msg_validators/tx_validator/factory.ts index cf915d26421c..9acd13d88c3d 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/factory.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/factory.ts @@ -97,6 +97,7 @@ export function createFirstStageTxValidationsForGossipedTransactions( txsPermitted: boolean, allowedInSetup: AllowedElement[] = [], bindings?: LoggerBindings, + gasLimitOpts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number }, ): Record { const merkleTree = worldStateSynchronizer.getCommitted(); @@ -158,6 +159,7 @@ export function createFirstStageTxValidationsForGossipedTransactions( ProtocolContractAddress.FeeJuice, gasFees, bindings, + gasLimitOpts, ), severity: PeerErrorSeverity.MidToleranceError, }, @@ -278,6 +280,9 @@ export function createTxValidatorForAcceptingTxsOverRPC( timestamp, blockNumber, txsPermitted, + rollupManaLimit, + maxBlockL2Gas, + maxBlockDAGas, }: { l1ChainId: number; rollupVersion: number; @@ -287,6 +292,9 @@ export function createTxValidatorForAcceptingTxsOverRPC( timestamp: UInt64; blockNumber: BlockNumber; txsPermitted: boolean; + rollupManaLimit: number; + maxBlockL2Gas?: number; + maxBlockDAGas?: number; }, bindings?: LoggerBindings, ): TxValidator { @@ -317,7 +325,11 @@ export function createTxValidatorForAcceptingTxsOverRPC( if (!skipFeeEnforcement) { validators.push( - new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings), + new GasTxValidator(new DatabasePublicStateSource(db), ProtocolContractAddress.FeeJuice, gasFees, bindings, { + rollupManaLimit, + maxBlockL2Gas, + maxBlockDAGas, + }), ); } @@ -403,6 +415,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool( worldStateSynchronizer: WorldStateSynchronizer, timestamp: bigint, blockNumber: BlockNumber, + gasLimitOpts: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number }, bindings?: LoggerBindings, ): Promise> { await worldStateSynchronizer.syncImmediate(); @@ -419,7 +432,7 @@ export async function createTxValidatorForTransactionsEnteringPendingTxPool( }, }; return new AggregateTxValidator( - new GasLimitsValidator(bindings), + new GasLimitsValidator({ ...gasLimitOpts, bindings }), new TimestampTxValidator({ timestamp, blockNumber }, bindings), new DoubleSpendTxValidator(nullifierSource, bindings), new BlockHeaderTxValidator(archiveSource, bindings), diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/fee_payer_balance.ts b/yarn-project/p2p/src/msg_validators/tx_validator/fee_payer_balance.ts index 4ce80e9cae29..af3936effa58 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/fee_payer_balance.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/fee_payer_balance.ts @@ -1,5 +1,6 @@ +import { FeeJuiceArtifact } from '@aztec/protocol-contracts/fee-juice'; import { getCallRequestsWithCalldataByPhase } from '@aztec/simulator/server'; -import { FunctionSelector } from '@aztec/stdlib/abi'; +import { FunctionSelector, getAllFunctionAbis } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { type Tx, TxExecutionPhase } from '@aztec/stdlib/tx'; @@ -8,7 +9,10 @@ export type FeePayerBalanceDelta = { claimAmount: bigint; }; -const increasePublicBalanceSelectorPromise = FunctionSelector.fromSignature('_increase_public_balance((Field),u128)'); +const increasePublicBalanceSelectorPromise = (() => { + const fn = getAllFunctionAbis(FeeJuiceArtifact).find(f => f.name === '_increase_public_balance')!; + return FunctionSelector.fromNameAndParameters(fn.name, fn.parameters); +})(); export function getTxFeeLimit(tx: Tx): bigint { return tx.data.constants.txContext.gasSettings.getFeeLimit().toBigInt(); diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts index d616b5547802..719be28a8454 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.test.ts @@ -1,6 +1,7 @@ import { DEFAULT_DA_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, + MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS, PRIVATE_TX_L2_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD, @@ -26,7 +27,7 @@ import { import assert from 'assert'; import { type MockProxy, mock, mockFn } from 'jest-mock-extended'; -import { GasTxValidator } from './gas_validator.js'; +import { GasLimitsValidator, GasTxValidator } from './gas_validator.js'; import { patchNonRevertibleFn, patchRevertibleFn } from './test_utils.js'; describe('GasTxValidator', () => { @@ -208,6 +209,146 @@ describe('GasTxValidator', () => { }); await expectInvalid(privateTx, TX_ERROR_GAS_LIMIT_TOO_HIGH); }); + + describe('block gas limits (rollupManaLimit, maxBlockL2Gas, maxBlockDAGas)', () => { + it('rejects tx exceeding rollupManaLimit (L2)', async () => { + const rollupManaLimit = 1_000_000; + const validator = new GasLimitsValidator({ rollupManaLimit }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, rollupManaLimit + 1), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('rejects tx exceeding maxBlockL2Gas', async () => { + const maxBlockL2Gas = 1_000_000; + const validator = new GasLimitsValidator({ maxBlockL2Gas }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, maxBlockL2Gas + 1), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('uses the minimum of all L2 limits', async () => { + const rollupManaLimit = 2_000_000; + const maxBlockL2Gas = 1_000_000; + const validator = new GasLimitsValidator({ rollupManaLimit, maxBlockL2Gas }); + // Between maxBlockL2Gas and rollupManaLimit — should be rejected (min wins) + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, 1_500_000), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('accepts tx at exactly the effective L2 limit', async () => { + const maxBlockL2Gas = 1_000_000; + const validator = new GasLimitsValidator({ maxBlockL2Gas }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, maxBlockL2Gas), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ result: 'valid' }); + }); + + it('falls back to MAX_PROCESSABLE_L2_GAS when no additional L2 limits are set', async () => { + const validator = new GasLimitsValidator(); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, MAX_PROCESSABLE_L2_GAS + 1), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('rejects tx exceeding maxBlockDAGas', async () => { + const maxBlockDAGas = 100_000; + const validator = new GasLimitsValidator({ maxBlockDAGas }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(maxBlockDAGas + 1, PUBLIC_TX_L2_GAS_OVERHEAD), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('accepts tx at exactly the effective DA limit', async () => { + const maxBlockDAGas = 100_000; + const validator = new GasLimitsValidator({ maxBlockDAGas }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(maxBlockDAGas, PUBLIC_TX_L2_GAS_OVERHEAD), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ result: 'valid' }); + }); + + it('falls back to MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT when no DA limit is set', async () => { + const validator = new GasLimitsValidator(); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT + 1, PUBLIC_TX_L2_GAS_OVERHEAD), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('forwards limits through GasTxValidator', async () => { + const maxBlockL2Gas = 1_000_000; + const validator = new GasTxValidator(publicStateSource, feeJuiceAddress, gasFees, undefined, { + maxBlockL2Gas, + }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(DEFAULT_DA_GAS_LIMIT, maxBlockL2Gas + 1), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + + it('forwards DA limits through GasTxValidator', async () => { + const maxBlockDAGas = 100_000; + const validator = new GasTxValidator(publicStateSource, feeJuiceAddress, gasFees, undefined, { + maxBlockDAGas, + }); + tx.data.constants.txContext.gasSettings = GasSettings.default({ + gasLimits: new Gas(maxBlockDAGas + 1, PUBLIC_TX_L2_GAS_OVERHEAD), + maxFeesPerGas: gasFees.clone(), + teardownGasLimits: new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, 1), + }); + await expect(validator.validateTx(tx)).resolves.toEqual({ + result: 'invalid', + reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH], + }); + }); + }); }); it('skips txs with not enough fee per da gas', async () => { diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts index 8ace5ceabbc6..19b94402e324 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/gas_validator.ts @@ -1,4 +1,5 @@ import { + MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS, PRIVATE_TX_L2_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD, @@ -49,16 +50,31 @@ export interface HasGasLimitData { */ export class GasLimitsValidator implements TxValidator { #log: Logger; - - constructor(bindings?: LoggerBindings) { - this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings); + #effectiveMaxL2Gas: number; + #effectiveMaxDAGas: number; + #rollupManaLimit: number; + #maxBlockL2Gas: number; + #maxBlockDAGas: number; + + constructor(opts?: { + rollupManaLimit?: number; + maxBlockL2Gas?: number; + maxBlockDAGas?: number; + bindings?: LoggerBindings; + }) { + this.#log = createLogger('sequencer:tx_validator:tx_gas', opts?.bindings); + this.#rollupManaLimit = opts?.rollupManaLimit ?? Infinity; + this.#maxBlockL2Gas = opts?.maxBlockL2Gas ?? Infinity; + this.#maxBlockDAGas = opts?.maxBlockDAGas ?? Infinity; + this.#effectiveMaxL2Gas = Math.min(MAX_PROCESSABLE_L2_GAS, this.#rollupManaLimit, this.#maxBlockL2Gas); + this.#effectiveMaxDAGas = Math.min(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, this.#maxBlockDAGas); } validateTx(tx: T): Promise { return Promise.resolve(this.validateGasLimit(tx)); } - /** Checks gas limits are >= fixed minimums and <= AVM max processable L2 gas. */ + /** Checks gas limits are >= fixed minimums and <= effective max gas (L2 and DA). */ validateGasLimit(tx: T): TxValidationResult { const gasLimits = tx.data.constants.txContext.gasSettings.gasLimits; const minGasLimits = new Gas( @@ -74,10 +90,21 @@ export class GasLimitsValidator implements TxValidato return { result: 'invalid', reason: [TX_ERROR_INSUFFICIENT_GAS_LIMIT] }; } - if (gasLimits.l2Gas > MAX_PROCESSABLE_L2_GAS) { - this.#log.verbose(`Rejecting transaction due to the gas limit(s) being higher than the maximum processable gas`, { + if (gasLimits.l2Gas > this.#effectiveMaxL2Gas) { + this.#log.verbose(`Rejecting transaction due to the L2 gas limit being higher than the effective maximum`, { gasLimits, - minGasLimits, + effectiveMaxL2Gas: this.#effectiveMaxL2Gas, + rollupManaLimit: this.#rollupManaLimit, + maxBlockL2Gas: this.#maxBlockL2Gas, + }); + return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] }; + } + + if (gasLimits.daGas > this.#effectiveMaxDAGas) { + this.#log.verbose(`Rejecting transaction due to the DA gas limit being higher than the effective maximum`, { + gasLimits, + effectiveMaxDAGas: this.#effectiveMaxDAGas, + maxBlockDAGas: this.#maxBlockDAGas, }); return { result: 'invalid', reason: [TX_ERROR_GAS_LIMIT_TOO_HIGH] }; } @@ -106,21 +133,27 @@ export class GasTxValidator implements TxValidator { #publicDataSource: PublicStateSource; #feeJuiceAddress: AztecAddress; #gasFees: GasFees; + #gasLimitOpts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number }; constructor( publicDataSource: PublicStateSource, feeJuiceAddress: AztecAddress, gasFees: GasFees, private bindings?: LoggerBindings, + opts?: { rollupManaLimit?: number; maxBlockL2Gas?: number; maxBlockDAGas?: number }, ) { this.#log = createLogger('sequencer:tx_validator:tx_gas', bindings); this.#publicDataSource = publicDataSource; this.#feeJuiceAddress = feeJuiceAddress; this.#gasFees = gasFees; + this.#gasLimitOpts = opts; } async validateTx(tx: Tx): Promise { - const gasLimitValidation = new GasLimitsValidator(this.bindings).validateGasLimit(tx); + const gasLimitValidation = new GasLimitsValidator({ + ...this.#gasLimitOpts, + bindings: this.bindings, + }).validateGasLimit(tx); if (gasLimitValidation.result === 'invalid') { return Promise.resolve(gasLimitValidation); } diff --git a/yarn-project/p2p/src/msg_validators/tx_validator/index.ts b/yarn-project/p2p/src/msg_validators/tx_validator/index.ts index dcdd4fb050e9..893796772a3b 100644 --- a/yarn-project/p2p/src/msg_validators/tx_validator/index.ts +++ b/yarn-project/p2p/src/msg_validators/tx_validator/index.ts @@ -8,6 +8,7 @@ export * from './gas_validator.js'; export * from './phases_validator.js'; export * from './test_utils.js'; export * from './allowed_public_setup.js'; +export * from './allowed_setup_helpers.js'; export * from './archive_cache.js'; export * from './tx_permitted_validator.js'; export * from './timestamp_validator.js'; diff --git a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts index 2a81e7a1350d..061263fb20c7 100644 --- a/yarn-project/p2p/src/services/libp2p/libp2p_service.ts +++ b/yarn-project/p2p/src/services/libp2p/libp2p_service.ts @@ -1,5 +1,6 @@ import type { EpochCacheInterface } from '@aztec/epoch-cache'; import { BlockNumber, type SlotNumber } from '@aztec/foundation/branded-types'; +import { maxBy } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/curves/bn254'; import { type Logger, createLibp2pComponentLogger, createLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; @@ -19,6 +20,7 @@ import { P2PMessage, type ValidationResult as P2PValidationResult, PeerErrorSeverity, + PeerErrorSeverityByHarshness, TopicType, createTopicString, getTopicsForConfig, @@ -235,11 +237,11 @@ export class LibP2PService extends WithTracer implements P2PService { this.gossipSubEventHandler = this.handleGossipSubEvent.bind(this); this.blockReceivedCallback = async (block: BlockProposal): Promise => { - this.logger.debug( - `Handler not yet registered: Block received callback not set. Received block for slot ${block.slotNumber} from peer.`, + this.logger.warn( + `Handler for block received not yet registered on P2P service. Received block ${block.blockNumber} for slot ${block.slotNumber} from peer.`, { p2pMessageIdentifier: await block.p2pMessageLoggingIdentifier() }, ); - return false; + return true; }; this.checkpointReceivedCallback = ( @@ -1190,7 +1192,7 @@ export class LibP2PService extends WithTracer implements P2PService { // Note: Validators do NOT attest to individual blocks, only to checkpoint proposals. const isValid = await this.blockReceivedCallback(block, sender); if (!isValid) { - this.logger.warn(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo()); + this.logger.info(`Block proposal validation failed for block ${block.blockNumber}`, block.toBlockInfo()); } } @@ -1624,6 +1626,7 @@ export class LibP2PService extends WithTracer implements P2PService { ...(this.config.txPublicSetupAllowListExtend ?? []), ]; const blockNumber = BlockNumber(currentBlockNumber + 1); + const l1Constants = await this.archiver.getL1Constants(); return createFirstStageTxValidationsForGossipedTransactions( nextSlotTimestamp, @@ -1637,6 +1640,11 @@ export class LibP2PService extends WithTracer implements P2PService { !this.config.disableTransactions, allowedInSetup, this.logger.getBindings(), + { + rollupManaLimit: l1Constants.rollupManaLimit, + maxBlockL2Gas: this.config.validateMaxL2BlockGas, + maxBlockDAGas: this.config.validateMaxDABlockGas, + }, ); } @@ -1662,8 +1670,10 @@ export class LibP2PService extends WithTracer implements P2PService { // A promise that resolves when all validations have been run const allValidations = await Promise.all(validationPromises); - const failed = allValidations.find(x => !x.isValid); - if (failed) { + const failures = allValidations.filter(x => !x.isValid); + if (failures.length > 0) { + // Pick the most severe failure (lowest tolerance = harshest penalty) + const failed = maxBy(failures, f => PeerErrorSeverityByHarshness.indexOf(f.severity))!; return { allPassed: false, failure: { diff --git a/yarn-project/p2p/src/test-helpers/testbench-utils.ts b/yarn-project/p2p/src/test-helpers/testbench-utils.ts index a4f249ecbe69..b375e80df0ca 100644 --- a/yarn-project/p2p/src/test-helpers/testbench-utils.ts +++ b/yarn-project/p2p/src/test-helpers/testbench-utils.ts @@ -292,6 +292,7 @@ export function createMockEpochCache(): EpochCacheInterface { ethereumSlotDuration: 1, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }), }; } diff --git a/yarn-project/package.json b/yarn-project/package.json index cc721aaa5779..caa1508cd661 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -93,6 +93,11 @@ "@aztec/noir-noir_js": "file:../noir/packages/noir_js", "jest-runner@npm:^29.7.0": "patch:jest-runner@npm%3A29.7.0#~/.yarn/patches/jest-runner-npm-29.7.0-3bc9f82b58.patch", "ws": "^8.17.1", - "d3-color": "^3.1.0" + "d3-color": "^3.1.0", + "rollup": "^4.59.0", + "systeminformation": "^5.31.0", + "node-forge": "^1.3.2", + "koa": "^2.16.4", + "serialize-javascript": "^7.0.3" } } diff --git a/yarn-project/prover-client/src/mocks/test_context.ts b/yarn-project/prover-client/src/mocks/test_context.ts index b27adcec0d97..78f9301c39de 100644 --- a/yarn-project/prover-client/src/mocks/test_context.ts +++ b/yarn-project/prover-client/src/mocks/test_context.ts @@ -116,7 +116,7 @@ export class TestContext { const broker = new TestBroker(proverCount, localProver); const facade = new BrokerCircuitProverFacade(broker); - const orchestrator = new TestProvingOrchestrator(ws, facade, EthAddress.ZERO); + const orchestrator = new TestProvingOrchestrator(ws, facade, EthAddress.ZERO, false, 10); await broker.start(); facade.start(); diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.ts index 001e91e0de34..a038867350b2 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.ts @@ -12,6 +12,7 @@ import { Fr } from '@aztec/foundation/curves/bn254'; import { AbortError } from '@aztec/foundation/error'; import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log'; import { promiseWithResolvers } from '@aztec/foundation/promise'; +import { SerialQueue } from '@aztec/foundation/queue'; import { assertLength } from '@aztec/foundation/serialize'; import { pushTestData } from '@aztec/foundation/testing'; import { elapsed } from '@aztec/foundation/timer'; @@ -94,17 +95,20 @@ export class ProvingOrchestrator implements EpochProver { // eslint-disable-next-line aztec-custom/no-non-primitive-in-collections private dbs: Map = new Map(); private logger: Logger; + private deferredJobQueue = new SerialQueue(); constructor( private dbProvider: ReadonlyWorldStateAccess & ForkMerkleTreeOperations, private prover: ServerCircuitProver, private readonly proverId: EthAddress, private readonly cancelJobsOnStop: boolean = false, + private readonly enqueueConcurrency: number, telemetryClient: TelemetryClient = getTelemetryClient(), bindings?: LoggerBindings, ) { this.logger = createLogger('prover-client:orchestrator', bindings); this.metrics = new ProvingOrchestratorMetrics(telemetryClient, 'ProvingOrchestrator'); + this.deferredJobQueue.start(this.enqueueConcurrency); } get tracer(): Tracer { @@ -119,9 +123,11 @@ export class ProvingOrchestrator implements EpochProver { return this.dbs.size; } - public stop(): Promise { + public async stop(): Promise { + // Grab the old queue before cancel() replaces it, so we can await its draining. + const oldQueue = this.deferredJobQueue; this.cancel(); - return Promise.resolve(); + await oldQueue.cancel(); } public startNewEpoch( @@ -514,6 +520,11 @@ export class ProvingOrchestrator implements EpochProver { * If cancelJobsOnStop is false (default), jobs remain in the broker queue and can be reused on restart/reorg. */ public cancel() { + void this.deferredJobQueue.cancel(); + // Recreate the queue so it can accept jobs for subsequent epochs. + this.deferredJobQueue = new SerialQueue(); + this.deferredJobQueue.start(this.enqueueConcurrency); + if (this.cancelJobsOnStop) { for (const controller of this.pendingProvingJobs) { controller.abort(); @@ -623,8 +634,9 @@ export class ProvingOrchestrator implements EpochProver { } }; - // let the callstack unwind before adding the job to the queue - setImmediate(() => void safeJob()); + // Enqueue onto the serial queue with limited workers to avoid starving the event loop. + // Workers yield between jobs via await, allowing I/O callbacks to process. + void this.deferredJobQueue.put(() => safeJob()); } private async updateL1ToL2MessageTree(l1ToL2Messages: Fr[], db: MerkleTreeWriteOperations) { diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator_lifecycle.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator_lifecycle.test.ts index d8838354136c..687f294711ed 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator_lifecycle.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator_lifecycle.test.ts @@ -29,7 +29,7 @@ describe('prover/orchestrator/lifecycle', () => { it('cancels proving requests', async () => { const prover: ServerCircuitProver = new TestCircuitProver(); // Pass cancelJobsOnStop=true to test that cancellation actually aborts jobs - const orchestrator = new ProvingOrchestrator(context.worldState, prover, EthAddress.ZERO, true); + const orchestrator = new ProvingOrchestrator(context.worldState, prover, EthAddress.ZERO, true, 10); const spy = jest.spyOn(prover, 'getBaseParityProof'); const deferredPromises: PromiseWithResolvers[] = []; @@ -73,7 +73,7 @@ describe('prover/orchestrator/lifecycle', () => { it('does not abort proving requests when cancelJobsOnStop is false (default)', async () => { const prover: ServerCircuitProver = new TestCircuitProver(); // Default behavior: cancelJobsOnStop=false, jobs remain in queue for reuse - const orchestrator = new ProvingOrchestrator(context.worldState, prover, EthAddress.ZERO, false); + const orchestrator = new ProvingOrchestrator(context.worldState, prover, EthAddress.ZERO, false, 10); const spy = jest.spyOn(prover, 'getBaseParityProof'); const deferredPromises: PromiseWithResolvers[] = []; diff --git a/yarn-project/prover-client/src/prover-client/prover-client.ts b/yarn-project/prover-client/src/prover-client/prover-client.ts index 89b866220c06..27c55717a2a6 100644 --- a/yarn-project/prover-client/src/prover-client/prover-client.ts +++ b/yarn-project/prover-client/src/prover-client/prover-client.ts @@ -54,6 +54,7 @@ export class ProverClient implements EpochProverManager { facade, this.config.proverId, this.config.cancelJobsOnStop, + this.config.enqueueConcurrency, this.telemetry, bindings, ); @@ -156,7 +157,7 @@ export class ProverClient implements EpochProverManager { } export function buildServerCircuitProver( - config: ActualProverConfig & ACVMConfig & BBConfig, + config: Omit & ACVMConfig & BBConfig, telemetry: TelemetryClient, ): Promise { if (config.realProofs) { diff --git a/yarn-project/prover-client/src/proving_broker/broker_prover_facade.ts b/yarn-project/prover-client/src/proving_broker/broker_prover_facade.ts index 37cd1671490b..c9537af6c601 100644 --- a/yarn-project/prover-client/src/proving_broker/broker_prover_facade.ts +++ b/yarn-project/prover-client/src/proving_broker/broker_prover_facade.ts @@ -5,7 +5,6 @@ import type { RECURSIVE_PROOF_LENGTH, } from '@aztec/constants'; import { EpochNumber } from '@aztec/foundation/branded-types'; -import { sha256 } from '@aztec/foundation/crypto/sha256'; import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log'; import { type PromiseWithResolvers, RunningPromise, promiseWithResolvers } from '@aztec/foundation/promise'; import { truncate } from '@aztec/foundation/string'; @@ -46,6 +45,8 @@ import type { TxRollupPublicInputs, } from '@aztec/stdlib/rollup'; +import { createHash } from 'node:crypto'; + import { InlineProofStore, type ProofStore } from './proof_store/index.js'; // Perform a snapshot sync every 30 seconds @@ -659,8 +660,12 @@ export class BrokerCircuitProverFacade implements ServerCircuitProver { ); } - private generateId(type: ProvingRequestType, inputs: { toBuffer(): Buffer }, epochNumber = EpochNumber.ZERO) { - const inputsHash = sha256(inputs.toBuffer()); - return makeProvingJobId(epochNumber, type, inputsHash.toString('hex')); + private generateId( + type: ProvingRequestType, + inputs: { toBuffer(): Buffer }, + epochNumber = EpochNumber.ZERO, + ): ProvingJobId { + const inputsHash = createHash('sha256').update(inputs.toBuffer()).digest('hex'); + return makeProvingJobId(epochNumber, type, inputsHash); } } diff --git a/yarn-project/prover-node/package.json b/yarn-project/prover-node/package.json index 38affb9d5405..ad69c6047308 100644 --- a/yarn-project/prover-node/package.json +++ b/yarn-project/prover-node/package.json @@ -66,6 +66,7 @@ "@aztec/foundation": "workspace:^", "@aztec/kv-store": "workspace:^", "@aztec/l1-artifacts": "workspace:^", + "@aztec/native": "workspace:^", "@aztec/node-keystore": "workspace:^", "@aztec/node-lib": "workspace:^", "@aztec/noir-protocol-circuits-types": "workspace:^", diff --git a/yarn-project/prover-node/src/config.ts b/yarn-project/prover-node/src/config.ts index 9ba657d77f0a..06434a4631c8 100644 --- a/yarn-project/prover-node/src/config.ts +++ b/yarn-project/prover-node/src/config.ts @@ -60,7 +60,7 @@ export const specificProverNodeConfigMappings: ConfigMappingsType checkpoint.toBlobFields()); - this.log.info(`Blob fields per checkpoint: ${timer.ms()}ms`); const finalBlobBatchingChallenges = await buildFinalBlobChallenges(blobFieldsPerCheckpoint); - this.log.info(`Final blob batching challeneger: ${timer.ms()}ms`); + this.metrics.recordBlobProcessing(blobTimer.ms()); this.prover.startNewEpoch(epochNumber, epochSizeCheckpoints, finalBlobBatchingChallenges); + const chonkTimer = new Timer(); await this.prover.startChonkVerifierCircuits(Array.from(this.txs.values())); + this.metrics.recordChonkVerifier(chonkTimer.ms()); // Everything in the epoch should have the same chainId and version. const { chainId, version } = this.checkpoints[0].blocks[0].header.globalVariables; const previousBlockHeaders = this.gatherPreviousBlockHeaders(); - await asyncPool(this.config.parallelBlockLimit ?? 32, this.checkpoints, async checkpoint => { + const allCheckpointsTimer = new Timer(); + + const parallelism = this.config.parallelBlockLimit + ? this.config.parallelBlockLimit + : AVM_MAX_CONCURRENT_SIMULATIONS > 0 + ? AVM_MAX_CONCURRENT_SIMULATIONS + : this.checkpoints.length; + + await asyncPool(parallelism, this.checkpoints, async checkpoint => { this.checkState(); + const checkpointTimer = new Timer(); const checkpointIndex = checkpoint.number - fromCheckpoint; const checkpointConstants = CheckpointConstantData.from({ @@ -196,6 +208,7 @@ export class EpochProvingJob implements Traceable { ); for (let blockIndex = 0; blockIndex < checkpoint.blocks.length; blockIndex++) { + const blockTimer = new Timer(); const block = checkpoint.blocks[blockIndex]; const globalVariables = block.header.globalVariables; const txs = this.getTxs(block); @@ -241,8 +254,11 @@ export class EpochProvingJob implements Traceable { // Mark block as completed to pad it const expectedBlockHeader = block.header; await this.prover.setBlockCompleted(block.number, expectedBlockHeader); + this.metrics.recordBlockProcessing(blockTimer.ms()); } + this.metrics.recordCheckpointProcessing(checkpointTimer.ms()); }); + this.metrics.recordAllCheckpointsProcessing(allCheckpointsTimer.ms()); const executionTime = timer.ms(); diff --git a/yarn-project/prover-node/src/metrics.ts b/yarn-project/prover-node/src/metrics.ts index 3e0faf714895..386b475b1b55 100644 --- a/yarn-project/prover-node/src/metrics.ts +++ b/yarn-project/prover-node/src/metrics.ts @@ -25,6 +25,12 @@ export class ProverNodeJobMetrics { provingJobBlocks: Gauge; provingJobTransactions: Gauge; + private blobProcessingDuration: Gauge; + private chonkVerifierDuration: Gauge; + private blockProcessingDuration: Histogram; + private checkpointProcessingDuration: Histogram; + private allCheckpointsProcessingDuration: Gauge; + constructor( private meter: Meter, public readonly tracer: Tracer, @@ -35,6 +41,14 @@ export class ProverNodeJobMetrics { this.provingJobCheckpoints = this.meter.createGauge(Metrics.PROVER_NODE_JOB_CHECKPOINTS); this.provingJobBlocks = this.meter.createGauge(Metrics.PROVER_NODE_JOB_BLOCKS); this.provingJobTransactions = this.meter.createGauge(Metrics.PROVER_NODE_JOB_TRANSACTIONS); + + this.blobProcessingDuration = this.meter.createGauge(Metrics.PROVER_NODE_BLOB_PROCESSING_LAST_DURATION); + this.chonkVerifierDuration = this.meter.createGauge(Metrics.PROVER_NODE_CHONK_VERIFIER_LAST_DURATION); + this.blockProcessingDuration = this.meter.createHistogram(Metrics.PROVER_NODE_BLOCK_PROCESSING_DURATION); + this.checkpointProcessingDuration = this.meter.createHistogram(Metrics.PROVER_NODE_CHECKPOINT_PROCESSING_DURATION); + this.allCheckpointsProcessingDuration = this.meter.createGauge( + Metrics.PROVER_NODE_ALL_CHECKPOINTS_PROCESSING_LAST_DURATION, + ); } public recordProvingJob( @@ -50,6 +64,26 @@ export class ProverNodeJobMetrics { this.provingJobBlocks.record(Math.floor(numBlocks)); this.provingJobTransactions.record(Math.floor(numTxs)); } + + public recordBlobProcessing(durationMs: number) { + this.blobProcessingDuration.record(Math.ceil(durationMs)); + } + + public recordChonkVerifier(durationMs: number) { + this.chonkVerifierDuration.record(Math.ceil(durationMs)); + } + + public recordBlockProcessing(durationMs: number) { + this.blockProcessingDuration.record(Math.ceil(durationMs)); + } + + public recordCheckpointProcessing(durationMs: number) { + this.checkpointProcessingDuration.record(Math.ceil(durationMs)); + } + + public recordAllCheckpointsProcessing(durationMs: number) { + this.allCheckpointsProcessingDuration.record(Math.ceil(durationMs)); + } } export class ProverNodeRewardsMetrics { diff --git a/yarn-project/prover-node/src/prover-node.ts b/yarn-project/prover-node/src/prover-node.ts index 8adf039d7651..2a88ad75f866 100644 --- a/yarn-project/prover-node/src/prover-node.ts +++ b/yarn-project/prover-node/src/prover-node.ts @@ -84,7 +84,7 @@ export class ProverNode implements EpochMonitorHandler, ProverNodeApi, Traceable this.config = { proverNodePollingIntervalMs: 1_000, proverNodeMaxPendingJobs: 100, - proverNodeMaxParallelBlocksPerEpoch: 32, + proverNodeMaxParallelBlocksPerEpoch: 0, txGatheringIntervalMs: 1_000, txGatheringBatchSize: 10, txGatheringMaxParallelRequestsPerNode: 100, diff --git a/yarn-project/prover-node/tsconfig.json b/yarn-project/prover-node/tsconfig.json index 211b82a617cb..ef271c18a38a 100644 --- a/yarn-project/prover-node/tsconfig.json +++ b/yarn-project/prover-node/tsconfig.json @@ -36,6 +36,9 @@ { "path": "../l1-artifacts" }, + { + "path": "../native" + }, { "path": "../node-keystore" }, diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts index 5d1e5a656cfb..9e9a14805f57 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts @@ -6,8 +6,9 @@ import { MembershipWitness } from '@aztec/foundation/trees'; import type { FunctionSelector, NoteSelector } from '@aztec/stdlib/abi'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import { BlockHash } from '@aztec/stdlib/block'; -import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; +import type { ContractInstance, PartialAddress } from '@aztec/stdlib/contract'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; +import type { PublicKeys } from '@aztec/stdlib/keys'; import type { ContractClassLog, Tag } from '@aztec/stdlib/logs'; import type { Note, NoteStatus } from '@aztec/stdlib/note'; import { type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees'; @@ -85,7 +86,9 @@ export interface IUtilityExecutionOracle { nullifier: Fr, ): Promise; utilityGetBlockHeader(blockNumber: BlockNumber): Promise; - utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise; + utilityTryGetPublicKeysAndPartialAddress( + account: AztecAddress, + ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined>; utilityGetAuthWitness(messageHash: Fr): Promise; utilityGetNotes( owner: AztecAddress | undefined, diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts index f957d44326a8..9e0d38befcba 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts @@ -9,11 +9,11 @@ import type { KeyStore } from '@aztec/key-store'; import type { AuthWitness } from '@aztec/stdlib/auth-witness'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { BlockHash } from '@aztec/stdlib/block'; -import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; +import type { CompleteAddress, ContractInstance, PartialAddress } from '@aztec/stdlib/contract'; import { siloNullifier } from '@aztec/stdlib/hash'; import type { AztecNode } from '@aztec/stdlib/interfaces/server'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; -import { computeAddressSecret } from '@aztec/stdlib/keys'; +import { type PublicKeys, computeAddressSecret } from '@aztec/stdlib/keys'; import { deriveEcdhSharedSecret } from '@aztec/stdlib/logs'; import { getNonNullifiedL1ToL2MessageWitness } from '@aztec/stdlib/messaging'; import type { NoteStatus } from '@aztec/stdlib/note'; @@ -232,12 +232,18 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra } /** - * Retrieve the complete address associated to a given address. + * Retrieve the public keys and partial address associated to a given address. * @param account - The account address. - * @returns A complete address associated with the input address, or `undefined` if not registered. + * @returns The public keys and partial address, or `undefined` if the account is not registered. */ - public utilityTryGetPublicKeysAndPartialAddress(account: AztecAddress): Promise { - return this.addressStore.getCompleteAddress(account); + public async utilityTryGetPublicKeysAndPartialAddress( + account: AztecAddress, + ): Promise<{ publicKeys: PublicKeys; partialAddress: PartialAddress } | undefined> { + const completeAddress = await this.addressStore.getCompleteAddress(account); + if (!completeAddress) { + return undefined; + } + return { publicKeys: completeAddress.publicKeys, partialAddress: completeAddress.partialAddress }; } protected async getCompleteAddressOrFail(account: AztecAddress): Promise { diff --git a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.test.ts b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.test.ts index f1a702e992f2..3543c78fc84f 100644 --- a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.test.ts @@ -78,7 +78,7 @@ describe('CheckpointProposalJob', () => { let job: TestCheckpointProposalJob; let timetable: SequencerTimetable; - let l1Constants: L1RollupConstants & { rollupManaLimit: number }; + let l1Constants: L1RollupConstants; let config: ResolvedSequencerConfig; let lastBlockNumber: BlockNumber; @@ -141,7 +141,7 @@ describe('CheckpointProposalJob', () => { epochDuration: 16, proofSubmissionEpochs: 4, targetCommitteeSize: 48, - rollupManaLimit: Infinity, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; dateProvider = new TestDateProvider(); diff --git a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.timing.test.ts b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.timing.test.ts index 1b7cabc8fe9e..69ba62b93dc1 100644 --- a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.timing.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.timing.test.ts @@ -208,7 +208,7 @@ describe('CheckpointProposalJob Timing Tests', () => { let slasherClient: MockProxy; let metrics: MockProxy; - let l1Constants: L1RollupConstants & { rollupManaLimit: number }; + let l1Constants: L1RollupConstants; let config: ResolvedSequencerConfig; // Test state @@ -330,7 +330,7 @@ describe('CheckpointProposalJob Timing Tests', () => { epochDuration: 16, proofSubmissionEpochs: 4, targetCommitteeSize: 48, - rollupManaLimit: Infinity, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; // Initialize test state diff --git a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts index 3e9cd16150c8..4d38f965723e 100644 --- a/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts +++ b/yarn-project/sequencer-client/src/sequencer/checkpoint_proposal_job.ts @@ -542,8 +542,7 @@ export class CheckpointProposalJob implements Traceable { try { // Wait until we have enough txs to build the block - const minTxs = this.config.minTxsPerBlock; - const { availableTxs, canStartBuilding } = await this.waitForMinTxs(opts); + const { availableTxs, canStartBuilding, minTxs } = await this.waitForMinTxs(opts); if (!canStartBuilding) { this.log.warn( `Not enough txs to build block ${blockNumber} at index ${indexWithinCheckpoint} in slot ${this.slot} (got ${availableTxs} txs but needs ${minTxs})`, @@ -665,7 +664,7 @@ export class CheckpointProposalJob implements Traceable { blockNumber: BlockNumber; indexWithinCheckpoint: IndexWithinCheckpoint; buildDeadline: Date | undefined; - }): Promise<{ canStartBuilding: boolean; availableTxs: number }> { + }): Promise<{ canStartBuilding: boolean; availableTxs: number; minTxs: number }> { const { indexWithinCheckpoint, blockNumber, buildDeadline, forceCreate } = opts; // We only allow a block with 0 txs in the first block of the checkpoint @@ -682,7 +681,7 @@ export class CheckpointProposalJob implements Traceable { // If we're past deadline, or we have no deadline, give up const now = this.dateProvider.nowAsDate(); if (startBuildingDeadline === undefined || now >= startBuildingDeadline) { - return { canStartBuilding: false, availableTxs: availableTxs }; + return { canStartBuilding: false, availableTxs, minTxs }; } // Wait a bit before checking again @@ -695,7 +694,7 @@ export class CheckpointProposalJob implements Traceable { availableTxs = await this.p2pClient.getPendingTxCount(); } - return { canStartBuilding: true, availableTxs }; + return { canStartBuilding: true, availableTxs, minTxs }; } /** diff --git a/yarn-project/sequencer-client/src/sequencer/checkpoint_voter.ha.integration.test.ts b/yarn-project/sequencer-client/src/sequencer/checkpoint_voter.ha.integration.test.ts index 254485252ec5..e5c0c52dc7c1 100644 --- a/yarn-project/sequencer-client/src/sequencer/checkpoint_voter.ha.integration.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/checkpoint_voter.ha.integration.test.ts @@ -67,7 +67,7 @@ describe('CheckpointVoter HA Integration', () => { l1GenesisTime: 1n, slotDuration: 24, ethereumSlotDuration: DefaultL1ContractsConfig.ethereumSlotDuration, - rollupManaLimit: Infinity, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; /** diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 464340b385ff..c30a93fb770e 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -78,9 +78,10 @@ describe('sequencer', () => { let block: L2Block; let globalVariables: GlobalVariables; - let l1Constants: Pick & { - rollupManaLimit: number; - }; + let l1Constants: Pick< + L1RollupConstants, + 'l1GenesisTime' | 'slotDuration' | 'ethereumSlotDuration' | 'rollupManaLimit' + >; let sequencer: TestSequencer; @@ -162,7 +163,7 @@ describe('sequencer', () => { ); const l1GenesisTime = BigInt(Math.floor(Date.now() / 1000)); - l1Constants = { l1GenesisTime, slotDuration, ethereumSlotDuration, rollupManaLimit: Infinity }; + l1Constants = { l1GenesisTime, slotDuration, ethereumSlotDuration, rollupManaLimit: Number.MAX_SAFE_INTEGER }; epochCache = mockDeep(); epochCache.isEscapeHatchOpen.mockResolvedValue(false); @@ -274,6 +275,7 @@ describe('sequencer', () => { getCheckpointedBlocksForEpoch: mockFn().mockResolvedValue([]), getCheckpointsForEpoch: mockFn().mockResolvedValue([]), getCheckpointsDataForEpoch: mockFn().mockResolvedValue([]), + getSyncedL2SlotNumber: mockFn().mockResolvedValue(SlotNumber(Number.MAX_SAFE_INTEGER)), }); l1ToL2MessageSource = mock({ @@ -398,14 +400,16 @@ describe('sequencer', () => { expectPublisherProposeL2Block(); }); - it('builds a block only when synced to previous L1 slot', async () => { + it('builds a block only when synced to previous L2 slot', async () => { await setupSingleTxBlock(); - l2BlockSource.getL1Timestamp.mockResolvedValue(1000n - BigInt(ethereumSlotDuration) - 1n); + // Archiver reports it hasn't synced any slot yet, so sequencer should not propose + l2BlockSource.getSyncedL2SlotNumber.mockResolvedValue(undefined); await sequencer.work(); expect(publisher.enqueueProposeCheckpoint).not.toHaveBeenCalled(); - l2BlockSource.getL1Timestamp.mockResolvedValue(1000n - BigInt(ethereumSlotDuration)); + // Archiver reports synced to slot 0, which satisfies syncedL2Slot + 1 >= slot (slot=1) + l2BlockSource.getSyncedL2SlotNumber.mockResolvedValue(SlotNumber(0)); await sequencer.work(); expect(publisher.enqueueProposeCheckpoint).toHaveBeenCalled(); }); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 7da938a6c828..d75788ea3cf4 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -14,7 +14,7 @@ import type { P2P } from '@aztec/p2p'; import type { SlasherClientInterface } from '@aztec/slasher'; import type { BlockData, L2BlockSink, L2BlockSource, ValidateCheckpointResult } from '@aztec/stdlib/block'; import type { Checkpoint } from '@aztec/stdlib/checkpoint'; -import { getSlotAtTimestamp, getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers'; +import { getSlotStartBuildTimestamp } from '@aztec/stdlib/epoch-helpers'; import { type ResolvedSequencerConfig, type SequencerConfig, @@ -281,8 +281,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter TypedEventEmitter { - // Check that the archiver and dependencies have synced to the previous L1 slot at least + // Check that the archiver has fully synced the L2 slot before the one we want to propose in. // TODO(#14766): Archiver reports L1 timestamp based on L1 blocks seen, which means that a missed L1 block will // cause the archiver L1 timestamp to fall behind, and cause this sequencer to start processing one L1 slot later. - const l1Timestamp = await this.l2BlockSource.getL1Timestamp(); - const { slot, ts } = args; - if (l1Timestamp === undefined || l1Timestamp + BigInt(this.l1Constants.ethereumSlotDuration) < ts) { + const syncedL2Slot = await this.l2BlockSource.getSyncedL2SlotNumber(); + const { slot } = args; + if (syncedL2Slot === undefined || syncedL2Slot + 1 < slot) { this.log.debug(`Cannot propose block at next L2 slot ${slot} due to pending sync from L1`, { slot, - ts, - l1Timestamp, + syncedL2Slot, }); return undefined; } @@ -524,7 +522,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter TypedEventEmitter TypedEventEmitter { - const { pendingChainValidationStatus, l1Timestamp } = syncedTo; + const { pendingChainValidationStatus, syncedL2Slot } = syncedTo; if (pendingChainValidationStatus.valid) { return; } @@ -735,7 +733,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter & { - /** Total L2 gas (mana) allowed per checkpoint. Fetched from L1 getManaLimit(). */ - rollupManaLimit: number; -}; + 'ethereumSlotDuration' | 'l1GenesisTime' | 'slotDuration' | 'rollupManaLimit' +>; diff --git a/yarn-project/slasher/src/tally_slasher_client.test.ts b/yarn-project/slasher/src/tally_slasher_client.test.ts index 62f5b492fa99..f4488da31abd 100644 --- a/yarn-project/slasher/src/tally_slasher_client.test.ts +++ b/yarn-project/slasher/src/tally_slasher_client.test.ts @@ -138,6 +138,7 @@ describe('TallySlasherClient', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 8, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }); // Create mocks for L1 contracts diff --git a/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts b/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts index dd52040bdef7..7b8b7004db56 100644 --- a/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts +++ b/yarn-project/slasher/src/watchers/epoch_prune_watcher.test.ts @@ -59,6 +59,7 @@ describe('EpochPruneWatcher', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; epochCache.getL1Constants.mockReturnValue(l1Constants); diff --git a/yarn-project/stdlib/src/abi/decoder.test.ts b/yarn-project/stdlib/src/abi/decoder.test.ts index 70183ba2654b..03bd867cd98f 100644 --- a/yarn-project/stdlib/src/abi/decoder.test.ts +++ b/yarn-project/stdlib/src/abi/decoder.test.ts @@ -269,4 +269,60 @@ describe('decoder', () => { { x: 1n, y: 2n, is_infinite: false }, ]); }); + + it('decodes Option::Some as the wrapped value', () => { + const decoded = decodeFromAbi( + [ + { + kind: 'struct', + path: 'std::option::Option', + fields: [ + { name: '_is_some', type: { kind: 'boolean' } }, + { + name: '_value', + type: { + kind: 'struct', + path: 'Test::CustomStruct', + fields: [ + { name: 'w', type: { kind: 'field' } }, + { name: 'x', type: { kind: 'boolean' } }, + ], + }, + }, + ], + }, + ], + [new Fr(1n), new Fr(7n), new Fr(1n)], + ); + + expect(decoded).toEqual({ w: 7n, x: true }); + }); + + it('decodes Option::None as undefined', () => { + const decoded = decodeFromAbi( + [ + { + kind: 'struct', + path: 'std::option::Option', + fields: [ + { name: '_is_some', type: { kind: 'boolean' } }, + { + name: '_value', + type: { + kind: 'struct', + path: 'Test::CustomStruct', + fields: [ + { name: 'w', type: { kind: 'field' } }, + { name: 'x', type: { kind: 'boolean' } }, + ], + }, + }, + ], + }, + ], + [Fr.ZERO, new Fr(7n), new Fr(1n)], + ); + + expect(decoded).toBeUndefined(); + }); }); diff --git a/yarn-project/stdlib/src/abi/decoder.ts b/yarn-project/stdlib/src/abi/decoder.ts index 69f1ac106d81..a373a8ac05e1 100644 --- a/yarn-project/stdlib/src/abi/decoder.ts +++ b/yarn-project/stdlib/src/abi/decoder.ts @@ -2,12 +2,19 @@ import { Fr } from '@aztec/foundation/curves/bn254'; import { AztecAddress } from '../aztec-address/index.js'; import type { ABIParameter, ABIVariable, AbiType } from './abi.js'; -import { isAztecAddressStruct, parseSignedInt } from './utils.js'; +import { isAztecAddressStruct, isOptionStruct, parseSignedInt } from './utils.js'; /** * The type of our decoded ABI. */ -export type AbiDecoded = bigint | boolean | string | AztecAddress | AbiDecoded[] | { [key: string]: AbiDecoded }; +export type AbiDecoded = + | bigint + | boolean + | string + | AztecAddress + | AbiDecoded[] + | { [key: string]: AbiDecoded } + | undefined; /** * Decodes values using a provided ABI. @@ -51,6 +58,11 @@ class AbiDecoder { if (isAztecAddressStruct(abiType)) { return new AztecAddress(this.getNextField().toBuffer()); } + if (isOptionStruct(abiType)) { + const isSome = this.decodeNext(abiType.fields[0].type); + const value = this.decodeNext(abiType.fields[1].type); + return isSome ? value : undefined; + } for (const field of abiType.fields) { struct[field.name] = this.decodeNext(field.type); diff --git a/yarn-project/stdlib/src/abi/encoder.test.ts b/yarn-project/stdlib/src/abi/encoder.test.ts index c26e9ae78045..0bf1c64ab57e 100644 --- a/yarn-project/stdlib/src/abi/encoder.test.ts +++ b/yarn-project/stdlib/src/abi/encoder.test.ts @@ -160,6 +160,82 @@ describe('abi/encoder', () => { expect(encodeArguments(abi, [{ inner: value }])).toEqual([value]); }); + describe('option struct inputs', () => { + const optionStructAbi: FunctionAbi = { + name: 'test', + isInitializer: false, + functionType: FunctionType.PRIVATE, + isOnlySelf: false, + isStatic: false, + parameters: [ + { + name: 'value', + type: { + kind: 'struct', + path: 'std::option::Option', + fields: [ + { name: '_is_some', type: { kind: 'boolean' } }, + { + name: '_value', + type: { + kind: 'struct', + path: 'Test::CustomStruct', + fields: [ + { name: 'w', type: { kind: 'field' } }, + { name: 'x', type: { kind: 'boolean' } }, + { name: 'y', type: { kind: 'integer', sign: 'unsigned', width: 64 } }, + { name: 'z', type: { kind: 'integer', sign: 'signed', width: 64 } }, + ], + }, + }, + ], + }, + visibility: 'private', + }, + ], + returnTypes: [], + errorTypes: {}, + }; + + const someValue = { w: 1n, x: true, y: 2n, z: -3n }; + + it('encodes a direct value as Some', () => { + expect(encodeArguments(optionStructAbi, [someValue])).toEqual([ + new Fr(1n), + new Fr(1n), + new Fr(1n), + new Fr(2n), + new Fr((1n << 64n) - 3n), + ]); + }); + + it.each([undefined, null])('encodes %p as None', value => { + expect(encodeArguments(optionStructAbi, [value])).toEqual([Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO, Fr.ZERO]); + }); + + it('encodes the lowered ABI shape for Some', () => { + // eslint-disable-next-line camelcase + expect(encodeArguments(optionStructAbi, [{ _is_some: true, _value: someValue }])).toEqual([ + new Fr(1n), + new Fr(1n), + new Fr(1n), + new Fr(2n), + new Fr((1n << 64n) - 3n), + ]); + }); + + it('encodes the lowered ABI shape for None without requiring _value', () => { + // eslint-disable-next-line camelcase + expect(encodeArguments(optionStructAbi, [{ _is_some: false }])).toEqual([ + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + Fr.ZERO, + ]); + }); + }); + it('throws when passing string argument as field', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', diff --git a/yarn-project/stdlib/src/abi/encoder.ts b/yarn-project/stdlib/src/abi/encoder.ts index c4748c8e41f8..ecd0c127819b 100644 --- a/yarn-project/stdlib/src/abi/encoder.ts +++ b/yarn-project/stdlib/src/abi/encoder.ts @@ -1,7 +1,13 @@ import { Fr } from '@aztec/foundation/curves/bn254'; import type { AbiType, FunctionAbi } from './abi.js'; -import { isAddressStruct, isBoundedVecStruct, isFunctionSelectorStruct, isWrappedFieldStruct } from './utils.js'; +import { + isAddressStruct, + isBoundedVecStruct, + isFunctionSelectorStruct, + isOptionStruct, + isWrappedFieldStruct, +} from './utils.js'; /** * Encodes arguments for a function call. @@ -43,6 +49,32 @@ class ArgumentEncoder { * @param name - Name. */ private encodeArgument(abiType: AbiType, arg: any, name?: string) { + if (isOptionStruct(abiType)) { + const optionType = abiType as Extract; + const [isSomeField, valueField] = optionType.fields; + + if (arg === undefined || arg === null) { + this.encodeArgument(isSomeField.type, false, `${name}._is_some`); + this.#encodeDefaultValue(valueField.type); + return; + } + + if (typeof arg === 'object' && '_is_some' in arg) { + this.encodeArgument(isSomeField.type, arg._is_some, `${name}._is_some`); + + if (arg._is_some) { + this.encodeArgument(valueField.type, arg._value, `${name}._value`); + } else { + this.#encodeDefaultValue(valueField.type); + } + return; + } + + this.encodeArgument(isSomeField.type, true, `${name}._is_some`); + this.encodeArgument(valueField.type, arg, `${name}._value`); + return; + } + if (arg === undefined || arg == null) { throw new Error(`Undefined argument ${name ?? 'unnamed'} of type ${abiType.kind}`); } @@ -227,6 +259,14 @@ class ArgumentEncoder { this.encodeArgument(lenField.type, arg.length, 'len'); } } + + /** + * Appends the flattened zero value for an ABI type. + * Option::None still serializes the wrapped value, so we need to zero-fill its footprint. + */ + #encodeDefaultValue(abiType: AbiType) { + this.flattened.push(...new Array(ArgumentEncoder.typeSize(abiType)).fill(Fr.ZERO)); + } } /** diff --git a/yarn-project/stdlib/src/abi/event_metadata_definition.ts b/yarn-project/stdlib/src/abi/event_metadata_definition.ts index 889a34466842..bf60d04b7c5a 100644 --- a/yarn-project/stdlib/src/abi/event_metadata_definition.ts +++ b/yarn-project/stdlib/src/abi/event_metadata_definition.ts @@ -1,8 +1,10 @@ import type { AbiType } from './abi.js'; import type { EventSelector } from './event_selector.js'; +/** Metadata for a contract event, used to decode emitted event logs back into structured data. */ export type EventMetadataDefinition = { eventSelector: EventSelector; abiType: AbiType; + /** Names of the event's struct members (not serialized Noir Field elements). */ fieldNames: string[]; }; diff --git a/yarn-project/stdlib/src/abi/utils.ts b/yarn-project/stdlib/src/abi/utils.ts index e9bc23565c0c..a1dea3316468 100644 --- a/yarn-project/stdlib/src/abi/utils.ts +++ b/yarn-project/stdlib/src/abi/utils.ts @@ -81,6 +81,31 @@ export function isBoundedVecStruct(abiType: AbiType) { ); } +/** + * Returns whether the ABI type is Noir's std::option::Option lowered to a struct. + * @param abiType - Type to check. + * @returns A boolean indicating whether the ABI type is an Option struct. + */ +export function isOptionStruct(abiType: AbiType) { + return ( + abiType.kind === 'struct' && + abiType.path === 'std::option::Option' && + abiType.fields.length === 2 && + abiType.fields[0].name === '_is_some' && + abiType.fields[1].name === '_value' + ); +} + +/** + * Returns whether `null` or `undefined` can be mapped to a valid ABI value for this type. + * + * @param abiType - Type to check. + * @returns A boolean indicating whether nullish values are valid shorthand for this ABI type. + */ +export function canBeMappedFromNullOrUndefined(abiType: AbiType) { + return isOptionStruct(abiType); +} + /** * Returns a bigint by parsing a serialized 2's complement signed int. * @param b - The signed int as a buffer diff --git a/yarn-project/stdlib/src/block/l2_block_source.ts b/yarn-project/stdlib/src/block/l2_block_source.ts index 39368d09ad99..75f181a003f2 100644 --- a/yarn-project/stdlib/src/block/l2_block_source.ts +++ b/yarn-project/stdlib/src/block/l2_block_source.ts @@ -176,14 +176,16 @@ export interface L2BlockSource { getSettledTxReceipt(txHash: TxHash): Promise; /** - * Returns the current L2 slot number based on the currently synced L1 timestamp. + * Returns the last L2 slot number that has been fully synchronized from L1. + * An L2 slot is fully synced when all L1 blocks that fall within its time range have been processed. */ - getL2SlotNumber(): Promise; + getSyncedL2SlotNumber(): Promise; /** - * Returns the current L2 epoch number based on the currently synced L1 timestamp. + * Returns the last L2 epoch number that has been fully synchronized from L1. + * An epoch is fully synced when all its L2 slots have been fully synced. */ - getL2EpochNumber(): Promise; + getSyncedL2EpochNumber(): Promise; /** * Returns all checkpointed block headers for a given epoch. diff --git a/yarn-project/stdlib/src/epoch-helpers/index.test.ts b/yarn-project/stdlib/src/epoch-helpers/index.test.ts index 1dfe16d60cee..150d8216714d 100644 --- a/yarn-project/stdlib/src/epoch-helpers/index.test.ts +++ b/yarn-project/stdlib/src/epoch-helpers/index.test.ts @@ -14,6 +14,7 @@ describe('EpochHelpers', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; }); diff --git a/yarn-project/stdlib/src/epoch-helpers/index.ts b/yarn-project/stdlib/src/epoch-helpers/index.ts index 3dc686828083..637afa3caf09 100644 --- a/yarn-project/stdlib/src/epoch-helpers/index.ts +++ b/yarn-project/stdlib/src/epoch-helpers/index.ts @@ -12,6 +12,7 @@ export type L1RollupConstants = { ethereumSlotDuration: number; proofSubmissionEpochs: number; targetCommitteeSize: number; + rollupManaLimit: number; }; export const EmptyL1RollupConstants: L1RollupConstants = { @@ -22,6 +23,7 @@ export const EmptyL1RollupConstants: L1RollupConstants = { ethereumSlotDuration: 1, proofSubmissionEpochs: 1, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, }; export const L1RollupConstantsSchema = zodFor()( @@ -33,6 +35,7 @@ export const L1RollupConstantsSchema = zodFor()( ethereumSlotDuration: z.number(), proofSubmissionEpochs: z.number(), targetCommitteeSize: z.number(), + rollupManaLimit: z.number(), }), ); diff --git a/yarn-project/stdlib/src/interfaces/archiver.test.ts b/yarn-project/stdlib/src/interfaces/archiver.test.ts index 710118ceb5e9..c996c11d7178 100644 --- a/yarn-project/stdlib/src/interfaces/archiver.test.ts +++ b/yarn-project/stdlib/src/interfaces/archiver.test.ts @@ -185,13 +185,13 @@ describe('ArchiverApiSchema', () => { expect(result).toBeInstanceOf(TxReceipt); }); - it('getL2SlotNumber', async () => { - const result = await context.client.getL2SlotNumber(); + it('getSyncedL2SlotNumber', async () => { + const result = await context.client.getSyncedL2SlotNumber(); expect(result).toBe(SlotNumber(1)); }); - it('getL2EpochNumber', async () => { - const result = await context.client.getL2EpochNumber(); + it('getSyncedL2EpochNumber', async () => { + const result = await context.client.getSyncedL2EpochNumber(); expect(result).toBe(EpochNumber(1)); }); @@ -508,10 +508,10 @@ class MockArchiver implements ArchiverApi { expect(txHash).toBeInstanceOf(TxHash); return Promise.resolve(TxReceipt.empty()); } - getL2SlotNumber(): Promise { + getSyncedL2SlotNumber(): Promise { return Promise.resolve(SlotNumber(1)); } - getL2EpochNumber(): Promise { + getSyncedL2EpochNumber(): Promise { return Promise.resolve(EpochNumber(1)); } async getCheckpointsForEpoch(epochNumber: EpochNumber): Promise { diff --git a/yarn-project/stdlib/src/interfaces/archiver.ts b/yarn-project/stdlib/src/interfaces/archiver.ts index 949c66575040..16ed315e131c 100644 --- a/yarn-project/stdlib/src/interfaces/archiver.ts +++ b/yarn-project/stdlib/src/interfaces/archiver.ts @@ -114,8 +114,8 @@ export const ArchiverApiSchema: ApiSchemaFor = { getL2BlockByArchive: z.function().args(schemas.Fr).returns(L2Block.schema.optional()), getTxEffect: z.function().args(TxHash.schema).returns(indexedTxSchema().optional()), getSettledTxReceipt: z.function().args(TxHash.schema).returns(TxReceipt.schema.optional()), - getL2SlotNumber: z.function().args().returns(schemas.SlotNumber.optional()), - getL2EpochNumber: z.function().args().returns(EpochNumberSchema.optional()), + getSyncedL2SlotNumber: z.function().args().returns(schemas.SlotNumber.optional()), + getSyncedL2EpochNumber: z.function().args().returns(EpochNumberSchema.optional()), getCheckpointsForEpoch: z.function().args(EpochNumberSchema).returns(z.array(Checkpoint.schema)), getCheckpointsDataForEpoch: z.function().args(EpochNumberSchema).returns(z.array(CheckpointDataSchema)), getCheckpointedBlocksForEpoch: z.function().args(EpochNumberSchema).returns(z.array(CheckpointedL2Block.schema)), diff --git a/yarn-project/stdlib/src/interfaces/aztec-node-admin.test.ts b/yarn-project/stdlib/src/interfaces/aztec-node-admin.test.ts index 61014496fe1e..bd25de2fb0c1 100644 --- a/yarn-project/stdlib/src/interfaces/aztec-node-admin.test.ts +++ b/yarn-project/stdlib/src/interfaces/aztec-node-admin.test.ts @@ -138,6 +138,7 @@ class MockAztecNodeAdmin implements AztecNodeAdmin { proverTestDelayMs: 100, proverTestDelayFactor: 1, cancelJobsOnStop: false, + enqueueConcurrency: 10, proverAgentCount: 1, coinbase: EthAddress.random(), maxPendingTxCount: 1000, diff --git a/yarn-project/stdlib/src/interfaces/block-builder.ts b/yarn-project/stdlib/src/interfaces/block-builder.ts index 87ed1444fff5..7b79c7134760 100644 --- a/yarn-project/stdlib/src/interfaces/block-builder.ts +++ b/yarn-project/stdlib/src/interfaces/block-builder.ts @@ -53,7 +53,7 @@ export interface PublicProcessorValidator { nullifierCache?: { addNullifiers: (nullifiers: Buffer[]) => void }; } -export type FullNodeBlockBuilderConfig = Pick & +export type FullNodeBlockBuilderConfig = Pick & Pick & Pick< SequencerConfig, @@ -64,10 +64,7 @@ export type FullNodeBlockBuilderConfig = Pick & { - /** Total L2 gas (mana) allowed per checkpoint. Fetched from L1 getManaLimit(). */ - rollupManaLimit: number; - }; + >; export const FullNodeBlockBuilderConfigKeys: (keyof FullNodeBlockBuilderConfig)[] = [ 'l1GenesisTime', diff --git a/yarn-project/stdlib/src/interfaces/prover-client.ts b/yarn-project/stdlib/src/interfaces/prover-client.ts index 1c6f44df7690..45a9c5b6e65f 100644 --- a/yarn-project/stdlib/src/interfaces/prover-client.ts +++ b/yarn-project/stdlib/src/interfaces/prover-client.ts @@ -23,6 +23,8 @@ export type ActualProverConfig = { * When true, jobs are explicitly cancelled with the broker, which prevents reuse. */ cancelJobsOnStop: boolean; + /** Max concurrent jobs the orchestrator serializes and enqueues to the broker. */ + enqueueConcurrency: number; }; /** @@ -53,6 +55,7 @@ export const ProverConfigSchema = zodFor()( proofStore: z.string().optional(), failedProofStore: z.string().optional(), cancelJobsOnStop: z.boolean(), + enqueueConcurrency: z.number(), }), ); @@ -107,6 +110,11 @@ export const proverConfigMappings: ConfigMappingsType = { 'When true, jobs are explicitly cancelled with the broker, which prevents reuse.', ...booleanConfigHelper(false), }, + enqueueConcurrency: { + env: 'PROVER_ENQUEUE_CONCURRENCY', + description: 'Max concurrent jobs the orchestrator serializes and enqueues to the broker.', + ...numberConfigHelper(10), + }, }; function parseProverId(str?: string) { diff --git a/yarn-project/stdlib/src/l1-contracts/slash_factory.test.ts b/yarn-project/stdlib/src/l1-contracts/slash_factory.test.ts index 4b482065bc18..f203338ca03c 100644 --- a/yarn-project/stdlib/src/l1-contracts/slash_factory.test.ts +++ b/yarn-project/stdlib/src/l1-contracts/slash_factory.test.ts @@ -42,6 +42,7 @@ describe('SlashFactory', () => { ethereumSlotDuration: 12, proofSubmissionEpochs: 2, targetCommitteeSize: 48, + rollupManaLimit: Number.MAX_SAFE_INTEGER, slashingRoundSize: 100, slashingPayloadLifetimeInRounds: 3, logsBatchSize: 50, diff --git a/yarn-project/stdlib/src/logs/public_log.ts b/yarn-project/stdlib/src/logs/public_log.ts index 5932261b4b90..490e39a0bcae 100644 --- a/yarn-project/stdlib/src/logs/public_log.ts +++ b/yarn-project/stdlib/src/logs/public_log.ts @@ -120,8 +120,8 @@ export class FlatPublicLogs { export class PublicLog { constructor( - public contractAddress: AztecAddress, - public fields: Fr[], + public readonly contractAddress: AztecAddress, + public readonly fields: Fr[], ) {} static from(fields: FieldsOf) { @@ -146,7 +146,9 @@ export class PublicLog { return this.fields.length + PUBLIC_LOG_HEADER_LENGTH; } + /** Returns the serialized log (field as in noir field and not a struct field). */ getEmittedFields() { + // We slice from 0 to return a shallow copy. return this.fields.slice(0); } diff --git a/yarn-project/stdlib/src/p2p/peer_error.ts b/yarn-project/stdlib/src/p2p/peer_error.ts index 73be41ebada2..f3edb326fb55 100644 --- a/yarn-project/stdlib/src/p2p/peer_error.ts +++ b/yarn-project/stdlib/src/p2p/peer_error.ts @@ -15,3 +15,10 @@ export enum PeerErrorSeverity { */ HighToleranceError = 'HighToleranceError', } + +/** Severities ordered from mildest to harshest. */ +export const PeerErrorSeverityByHarshness = [ + PeerErrorSeverity.HighToleranceError, + PeerErrorSeverity.MidToleranceError, + PeerErrorSeverity.LowToleranceError, +] as const; diff --git a/yarn-project/stdlib/src/validators/errors.ts b/yarn-project/stdlib/src/validators/errors.ts index 24c082518b14..ab10f044c23e 100644 --- a/yarn-project/stdlib/src/validators/errors.ts +++ b/yarn-project/stdlib/src/validators/errors.ts @@ -36,6 +36,15 @@ export class FailedToReExecuteTransactionsError extends ValidatorError { } } +export class ReExInitialStateMismatchError extends ValidatorError { + constructor( + public readonly expectedArchiveRoot: Fr, + public readonly actualArchiveRoot: Fr, + ) { + super('Re-execution initial state mismatch'); + } +} + export class ReExStateMismatchError extends ValidatorError { constructor( public readonly expectedArchiveRoot: Fr, diff --git a/yarn-project/telemetry-client/src/metrics.ts b/yarn-project/telemetry-client/src/metrics.ts index 4c1a58ba1761..a2985f0c337a 100644 --- a/yarn-project/telemetry-client/src/metrics.ts +++ b/yarn-project/telemetry-client/src/metrics.ts @@ -1120,6 +1120,36 @@ export const PROVER_NODE_JOB_TRANSACTIONS: MetricDefinition = { description: 'Number of transactions in a proven epoch', valueType: ValueType.INT, }; +export const PROVER_NODE_BLOB_PROCESSING_LAST_DURATION: MetricDefinition = { + name: 'aztec.prover_node.blob_processing.last_duration', + description: 'Duration of blob processing step in epoch proving job', + unit: 'ms', + valueType: ValueType.INT, +}; +export const PROVER_NODE_CHONK_VERIFIER_LAST_DURATION: MetricDefinition = { + name: 'aztec.prover_node.chonk_verifier.last_duration', + description: 'Duration of chonk verifier enqueuing in epoch proving job', + unit: 'ms', + valueType: ValueType.INT, +}; +export const PROVER_NODE_BLOCK_PROCESSING_DURATION: MetricDefinition = { + name: 'aztec.prover_node.block_processing.duration', + description: 'Duration of processing a single block in epoch proving job', + unit: 'ms', + valueType: ValueType.INT, +}; +export const PROVER_NODE_CHECKPOINT_PROCESSING_DURATION: MetricDefinition = { + name: 'aztec.prover_node.checkpoint_processing.duration', + description: 'Duration of processing a single checkpoint in epoch proving job', + unit: 'ms', + valueType: ValueType.INT, +}; +export const PROVER_NODE_ALL_CHECKPOINTS_PROCESSING_LAST_DURATION: MetricDefinition = { + name: 'aztec.prover_node.all_checkpoints_processing.last_duration', + description: 'Duration of processing all checkpoints in epoch proving job', + unit: 'ms', + valueType: ValueType.INT, +}; export const PROVER_NODE_REWARDS_TOTAL: MetricDefinition = { name: 'aztec.prover_node.rewards_total', description: 'The rewards earned (total)', diff --git a/yarn-project/txe/src/state_machine/archiver.ts b/yarn-project/txe/src/state_machine/archiver.ts index c601ed33ce85..31b9dcbe9221 100644 --- a/yarn-project/txe/src/state_machine/archiver.ts +++ b/yarn-project/txe/src/state_machine/archiver.ts @@ -79,12 +79,12 @@ export class TXEArchiver extends ArchiverDataSourceBase { }; } - public getL2SlotNumber(): Promise { - throw new Error('TXE Archiver does not implement "getL2SlotNumber"'); + public getSyncedL2SlotNumber(): Promise { + throw new Error('TXE Archiver does not implement "getSyncedL2SlotNumber"'); } - public getL2EpochNumber(): Promise { - throw new Error('TXE Archiver does not implement "getL2EpochNumber"'); + public getSyncedL2EpochNumber(): Promise { + throw new Error('TXE Archiver does not implement "getSyncedL2EpochNumber"'); } public isEpochComplete(_epochNumber: EpochNumber): Promise { diff --git a/yarn-project/validator-client/src/block_proposal_handler.ts b/yarn-project/validator-client/src/block_proposal_handler.ts index 2bb4f0d8d555..43c890bdafa8 100644 --- a/yarn-project/validator-client/src/block_proposal_handler.ts +++ b/yarn-project/validator-client/src/block_proposal_handler.ts @@ -15,9 +15,11 @@ import { Gas } from '@aztec/stdlib/gas'; import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server'; import { type L1ToL2MessageSource, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging'; import type { BlockProposal } from '@aztec/stdlib/p2p'; +import { MerkleTreeId } from '@aztec/stdlib/trees'; import type { CheckpointGlobalVariables, FailedTx, Tx } from '@aztec/stdlib/tx'; import { ReExFailedTxsError, + ReExInitialStateMismatchError, ReExStateMismatchError, ReExTimeoutError, TransactionsNotAvailableError, @@ -30,6 +32,7 @@ import type { ValidatorMetrics } from './metrics.js'; export type BlockProposalValidationFailureReason = | 'invalid_proposal' | 'parent_block_not_found' + | 'block_source_not_synced' | 'parent_block_wrong_slot' | 'in_hash_mismatch' | 'global_variables_mismatch' @@ -37,6 +40,7 @@ export type BlockProposalValidationFailureReason = | 'txs_not_available' | 'state_mismatch' | 'failed_txs' + | 'initial_state_mismatch' | 'timeout' | 'unknown_error'; @@ -138,7 +142,13 @@ export class BlockProposalHandler { return { isValid: false, reason: 'invalid_proposal' }; } - const proposalInfo = { ...proposal.toBlockInfo(), proposer: proposer.toString() }; + const proposalInfo = { + ...proposal.toBlockInfo(), + proposer: proposer.toString(), + blockNumber: undefined as BlockNumber | undefined, + checkpointNumber: undefined as CheckpointNumber | undefined, + }; + this.log.info(`Processing proposal for slot ${slotNumber}`, { ...proposalInfo, txHashes: proposal.txHashes.map(t => t.toString()), @@ -152,7 +162,20 @@ export class BlockProposalHandler { return { isValid: false, reason: 'invalid_proposal' }; } - // Check that the parent proposal is a block we know, otherwise reexecution would fail + // Ensure the block source is synced before checking for existing blocks, + // since a pending checkpoint prune may remove blocks we'd otherwise find. + // This affects mostly the block_number_already_exists check, since a pending + // checkpoint prune could remove a block that would conflict with this proposal. + // TODO(@Maddiaa0): This may break staggered slots. + const blockSourceSync = await this.waitForBlockSourceSync(slotNumber); + if (!blockSourceSync) { + this.log.warn(`Block source is not synced, skipping processing`, proposalInfo); + return { isValid: false, reason: 'block_source_not_synced' }; + } + + // Check that the parent proposal is a block we know, otherwise reexecution would fail. + // If we don't find it immediately, we keep retrying for a while; it may be we still + // need to process other block proposals to get to it. const parentBlock = await this.getParentBlock(proposal); if (parentBlock === undefined) { this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo); @@ -174,6 +197,7 @@ export class BlockProposalHandler { parentBlock === 'genesis' ? BlockNumber(INITIAL_L2_BLOCK_NUM) : BlockNumber(parentBlock.header.getBlockNumber() + 1); + proposalInfo.blockNumber = blockNumber; // Check that this block number does not exist already const existingBlock = await this.blockSource.getBlockHeader(blockNumber); @@ -189,7 +213,7 @@ export class BlockProposalHandler { deadline: this.getReexecutionDeadline(slotNumber, config), }); - // If reexecution is disabled, bail. We are just interested in triggering tx collection. + // If reexecution is disabled, bail. We were just interested in triggering tx collection. if (!shouldReexecute) { this.log.info( `Received valid block ${blockNumber} proposal at index ${proposal.indexWithinCheckpoint} on slot ${slotNumber}`, @@ -204,6 +228,7 @@ export class BlockProposalHandler { return { isValid: false, blockNumber, reason: checkpointResult.reason }; } const checkpointNumber = checkpointResult.checkpointNumber; + proposalInfo.checkpointNumber = checkpointNumber; // Check that I have the same set of l1ToL2Messages as the proposal const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber); @@ -425,8 +450,46 @@ export class BlockProposalHandler { return new Date(nextSlotTimestampSeconds * 1000); } - private getReexecuteFailureReason(err: any) { - if (err instanceof ReExStateMismatchError) { + /** Waits for the block source to sync L1 data up to at least the slot before the given one. */ + private async waitForBlockSourceSync(slot: SlotNumber): Promise { + const deadline = this.getReexecutionDeadline(slot, this.checkpointsBuilder.getConfig()); + const timeoutMs = deadline.getTime() - this.dateProvider.now(); + if (slot === 0) { + return true; + } + + // Make a quick check before triggering an archiver sync + const syncedSlot = await this.blockSource.getSyncedL2SlotNumber(); + if (syncedSlot !== undefined && syncedSlot + 1 >= slot) { + return true; + } + + try { + // Trigger an immediate sync of the block source, and wait until it reports being synced to the required slot + return await retryUntil( + async () => { + await this.blockSource.syncImmediate(); + const syncedSlot = await this.blockSource.getSyncedL2SlotNumber(); + return syncedSlot !== undefined && syncedSlot + 1 >= slot; + }, + 'wait for block source sync', + timeoutMs / 1000, + 0.5, + ); + } catch (err) { + if (err instanceof TimeoutError) { + this.log.warn(`Timed out waiting for block source to sync to slot ${slot}`); + return false; + } else { + throw err; + } + } + } + + private getReexecuteFailureReason(err: any): BlockProposalValidationFailureReason { + if (err instanceof ReExInitialStateMismatchError) { + return 'initial_state_mismatch'; + } else if (err instanceof ReExStateMismatchError) { return 'state_mismatch'; } else if (err instanceof ReExFailedTxsError) { return 'failed_txs'; @@ -467,6 +530,13 @@ export class BlockProposalHandler { await this.worldState.syncImmediate(parentBlockNumber); await using fork = await this.worldState.fork(parentBlockNumber); + // Verify the fork's archive root matches the proposal's expected last archive. + // If they don't match, our world state synced to a different chain and reexecution would fail. + const forkArchiveRoot = new Fr((await fork.getTreeInfo(MerkleTreeId.ARCHIVE)).root); + if (!forkArchiveRoot.equals(proposal.blockHeader.lastArchive.root)) { + throw new ReExInitialStateMismatchError(proposal.blockHeader.lastArchive.root, forkArchiveRoot); + } + // Build checkpoint constants from proposal (excludes blockNumber which is per-block) const constants: CheckpointGlobalVariables = { chainId: new Fr(config.l1ChainId), diff --git a/yarn-project/validator-client/src/key_store/ha_key_store.ts b/yarn-project/validator-client/src/key_store/ha_key_store.ts index a6fd29bcd9d3..91c8279642e9 100644 --- a/yarn-project/validator-client/src/key_store/ha_key_store.ts +++ b/yarn-project/validator-client/src/key_store/ha_key_store.ts @@ -240,7 +240,7 @@ export class HAKeyStore implements ExtendedValidatorKeyStore { } if (error instanceof SlashingProtectionError) { - this.log.warn(`Duty already signed by another node with different payload`, { + this.log.info(`Duty already signed by another node with different payload`, { dutyType: context.dutyType, slot: context.slot, existingMessageHash: error.existingMessageHash, diff --git a/yarn-project/validator-client/src/validator.integration.test.ts b/yarn-project/validator-client/src/validator.integration.test.ts index 10a89a85bc92..4074d08dceea 100644 --- a/yarn-project/validator-client/src/validator.integration.test.ts +++ b/yarn-project/validator-client/src/validator.integration.test.ts @@ -53,6 +53,7 @@ describe('ValidatorClient Integration', () => { proofSubmissionEpochs: 2, l1StartBlock: 0n, targetCommitteeSize: 48, + rollupManaLimit: 200_000_000, }; const emptyL1ToL2Messages: Fr[] = []; diff --git a/yarn-project/validator-client/src/validator.test.ts b/yarn-project/validator-client/src/validator.test.ts index 14799f855c4b..52d8916c5a2f 100644 --- a/yarn-project/validator-client/src/validator.test.ts +++ b/yarn-project/validator-client/src/validator.test.ts @@ -121,6 +121,8 @@ describe('ValidatorClient', () => { blockSource.getCheckpointedBlocksForEpoch.mockResolvedValue([]); blockSource.getCheckpointsDataForEpoch.mockResolvedValue([]); blockSource.getBlocksForSlot.mockResolvedValue([]); + blockSource.getSyncedL2SlotNumber.mockResolvedValue(SlotNumber(Number.MAX_SAFE_INTEGER)); + blockSource.syncImmediate.mockResolvedValue(undefined); epochCache.isEscapeHatchOpenAtSlot.mockResolvedValue(false); l1ToL2MessageSource = mock(); txProvider = mock(); @@ -311,6 +313,7 @@ describe('ValidatorClient', () => { worldState.fork.mockResolvedValue({ close: () => Promise.resolve(), [Symbol.asyncDispose]: () => Promise.resolve(), + getTreeInfo: () => Promise.resolve({ root: proposal.blockHeader.lastArchive.root.toBuffer() }), } as never); }; @@ -528,6 +531,7 @@ describe('ValidatorClient', () => { blockSource.getBlockDataByArchive.mockResolvedValueOnce(undefined); blockSource.getBlockDataByArchive.mockResolvedValueOnce(undefined); const isValid = await validatorClient.validateBlockProposal(proposal, sender); + // Direct call returns undefined, then retryUntil: 2 undefined + 1 success = 4 total expect(blockSource.getBlockDataByArchive).toHaveBeenCalledTimes(4); expect(isValid).toBe(true); }); diff --git a/yarn-project/validator-client/src/validator.ts b/yarn-project/validator-client/src/validator.ts index 087ae2d31724..6293175d54da 100644 --- a/yarn-project/validator-client/src/validator.ts +++ b/yarn-project/validator-client/src/validator.ts @@ -387,7 +387,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter) // Ignore proposals from ourselves (may happen in HA setups) if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) { - this.log.warn(`Ignoring block proposal from self for slot ${slotNumber}`, { + this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, { proposer: proposer.toString(), slotNumber, }); @@ -423,9 +423,10 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter) ); if (!validationResult.isValid) { - this.log.warn(`Block proposal validation failed: ${validationResult.reason}`, proposalInfo); - const reason = validationResult.reason || 'unknown'; + + this.log.warn(`Block proposal validation failed: ${reason}`, proposalInfo); + // Classify failure reason: bad proposal vs node issue const badProposalReasons: BlockProposalValidationFailureReason[] = [ 'invalid_proposal', @@ -497,7 +498,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter) // Ignore proposals from ourselves (may happen in HA setups) if (this.getValidatorAddresses().some(addr => addr.equals(proposer))) { - this.log.warn(`Ignoring block proposal from self for slot ${slotNumber}`, { + this.log.debug(`Ignoring block proposal from self for slot ${slotNumber}`, { proposer: proposer.toString(), slotNumber, }); diff --git a/yarn-project/validator-ha-signer/src/slashing_protection_service.ts b/yarn-project/validator-ha-signer/src/slashing_protection_service.ts index ffe8a2a8e30d..e40feeda042e 100644 --- a/yarn-project/validator-ha-signer/src/slashing_protection_service.ts +++ b/yarn-project/validator-ha-signer/src/slashing_protection_service.ts @@ -85,7 +85,7 @@ export class SlashingProtectionService { if (isNew) { // We successfully acquired the lock - this.log.info(`Acquired lock for duty ${dutyType} at slot ${slot}`, { + this.log.verbose(`Acquired lock for duty ${dutyType} at slot ${slot}`, { validatorAddress: validatorAddress.toString(), nodeId, }); @@ -159,7 +159,7 @@ export class SlashingProtectionService { ); if (success) { - this.log.info(`Recorded successful signing for duty ${dutyType} at slot ${slot}`, { + this.log.verbose(`Recorded successful signing for duty ${dutyType} at slot ${slot}`, { validatorAddress: validatorAddress.toString(), nodeId, }); diff --git a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts index ad85df243053..c6d77400acb7 100644 --- a/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts +++ b/yarn-project/world-state/src/synchronizer/server_world_state_synchronizer.ts @@ -405,7 +405,7 @@ export class ServerWorldStateSynchronizer } private async handleChainPruned(blockNumber: BlockNumber) { - this.log.warn(`Chain pruned to block ${blockNumber}`); + this.log.info(`Chain pruned to block ${blockNumber}`); const status = await this.merkleTreeDb.unwindBlocks(blockNumber); this.provenBlockNumber = undefined; this.instrumentation.updateWorldStateMetrics(status); diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index cb1b1d09ce4d..c7882d55d56a 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -1469,7 +1469,7 @@ __metadata: playwright: "npm:1.49.0" puppeteer: "npm:^24.22.3" resolve-typescript-plugin: "npm:^2.0.1" - serve: "npm:^14.2.1" + serve: "npm:^14.2.6" ts-loader: "npm:^9.5.4" ts-node: "npm:^10.9.1" tslib: "npm:^2.4.0" @@ -4005,22 +4005,6 @@ __metadata: languageName: node linkType: hard -"@isaacs/balanced-match@npm:^4.0.1": - version: 4.0.1 - resolution: "@isaacs/balanced-match@npm:4.0.1" - checksum: 10/102fbc6d2c0d5edf8f6dbf2b3feb21695a21bc850f11bc47c4f06aa83bd8884fde3fe9d6d797d619901d96865fdcb4569ac2a54c937992c48885c5e3d9967fe8 - languageName: node - linkType: hard - -"@isaacs/brace-expansion@npm:^5.0.0": - version: 5.0.0 - resolution: "@isaacs/brace-expansion@npm:5.0.0" - dependencies: - "@isaacs/balanced-match": "npm:^4.0.1" - checksum: 10/cf3b7f206aff12128214a1df764ac8cdbc517c110db85249b945282407e3dfc5c6e66286383a7c9391a059fc8e6e6a8ca82262fc9d2590bd615376141fbebd2d - languageName: node - linkType: hard - "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -5990,156 +5974,177 @@ __metadata: languageName: node linkType: hard -"@rollup/rollup-android-arm-eabi@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-android-arm-eabi@npm:4.52.3" +"@rollup/rollup-android-arm-eabi@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.59.0" conditions: os=android & cpu=arm languageName: node linkType: hard -"@rollup/rollup-android-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-android-arm64@npm:4.52.3" +"@rollup/rollup-android-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-android-arm64@npm:4.59.0" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-darwin-arm64@npm:4.52.3" +"@rollup/rollup-darwin-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.59.0" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-darwin-x64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-darwin-x64@npm:4.52.3" +"@rollup/rollup-darwin-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.59.0" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-freebsd-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-freebsd-arm64@npm:4.52.3" +"@rollup/rollup-freebsd-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-arm64@npm:4.59.0" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-freebsd-x64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-freebsd-x64@npm:4.52.3" +"@rollup/rollup-freebsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-freebsd-x64@npm:4.59.0" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.52.3" +"@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm-musleabihf@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.52.3" +"@rollup/rollup-linux-arm-musleabihf@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.59.0" conditions: os=linux & cpu=arm & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-arm64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.52.3" +"@rollup/rollup-linux-arm64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-arm64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-arm64-musl@npm:4.52.3" +"@rollup/rollup-linux-arm64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.59.0" conditions: os=linux & cpu=arm64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-loong64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.52.3" +"@rollup/rollup-linux-loong64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.59.0" conditions: os=linux & cpu=loong64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-ppc64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.52.3" +"@rollup/rollup-linux-loong64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-loong64-musl@npm:4.59.0" + conditions: os=linux & cpu=loong64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-ppc64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.59.0" conditions: os=linux & cpu=ppc64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.52.3" +"@rollup/rollup-linux-ppc64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.59.0" + conditions: os=linux & cpu=ppc64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-riscv64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.52.3" +"@rollup/rollup-linux-riscv64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.59.0" conditions: os=linux & cpu=riscv64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-linux-s390x-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.52.3" +"@rollup/rollup-linux-s390x-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.59.0" conditions: os=linux & cpu=s390x & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-x64-gnu@npm:4.52.3" +"@rollup/rollup-linux-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=glibc languageName: node linkType: hard -"@rollup/rollup-linux-x64-musl@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-linux-x64-musl@npm:4.52.3" +"@rollup/rollup-linux-x64-musl@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.59.0" conditions: os=linux & cpu=x64 & libc=musl languageName: node linkType: hard -"@rollup/rollup-openharmony-arm64@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-openharmony-arm64@npm:4.52.3" +"@rollup/rollup-openbsd-x64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openbsd-x64@npm:4.59.0" + conditions: os=openbsd & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-openharmony-arm64@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-openharmony-arm64@npm:4.59.0" conditions: os=openharmony & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-arm64-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.52.3" +"@rollup/rollup-win32-arm64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.59.0" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@rollup/rollup-win32-ia32-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.52.3" +"@rollup/rollup-win32-ia32-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.59.0" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@rollup/rollup-win32-x64-gnu@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-x64-gnu@npm:4.52.3" +"@rollup/rollup-win32-x64-gnu@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-gnu@npm:4.59.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@rollup/rollup-win32-x64-msvc@npm:4.52.3": - version: 4.52.3 - resolution: "@rollup/rollup-win32-x64-msvc@npm:4.52.3" +"@rollup/rollup-win32-x64-msvc@npm:4.59.0": + version: 4.59.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.59.0" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -9188,7 +9193,7 @@ __metadata: languageName: node linkType: hard -"accepts@npm:^1.3.5, accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": +"accepts@npm:^1.3.5, accepts@npm:~1.3.4, accepts@npm:~1.3.8": version: 1.3.8 resolution: "accepts@npm:1.3.8" dependencies: @@ -9318,15 +9323,15 @@ __metadata: languageName: node linkType: hard -"ajv@npm:8.12.0, ajv@npm:~8.12.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" +"ajv@npm:8.18.0": + version: 8.18.0 + resolution: "ajv@npm:8.18.0" dependencies: - fast-deep-equal: "npm:^3.1.1" + fast-deep-equal: "npm:^3.1.3" + fast-uri: "npm:^3.0.1" json-schema-traverse: "npm:^1.0.0" require-from-string: "npm:^2.0.2" - uri-js: "npm:^4.2.2" - checksum: 10/b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 + checksum: 10/bfed9de827a2b27c6d4084324eda76a4e32bdde27410b3e9b81d06e6f8f5c78370fc6b93fe1d869f1939ff1d7c4ae8896960995acb8425e3e9288c8884247c48 languageName: node linkType: hard @@ -9354,6 +9359,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:~8.12.0": + version: 8.12.0 + resolution: "ajv@npm:8.12.0" + dependencies: + fast-deep-equal: "npm:^3.1.1" + json-schema-traverse: "npm:^1.0.0" + require-from-string: "npm:^2.0.2" + uri-js: "npm:^4.2.2" + checksum: 10/b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 + languageName: node + linkType: hard + "ansi-align@npm:^3.0.1": version: 3.0.1 resolution: "ansi-align@npm:3.0.1" @@ -9764,6 +9781,13 @@ __metadata: languageName: node linkType: hard +"balanced-match@npm:^4.0.2": + version: 4.0.4 + resolution: "balanced-match@npm:4.0.4" + checksum: 10/fb07bb66a0959c2843fc055838047e2a95ccebb837c519614afb067ebfdf2fa967ca8d712c35ced07f2cd26fc6f07964230b094891315ad74f11eba3d53178a0 + languageName: node + linkType: hard + "bare-events@npm:^2.5.4, bare-events@npm:^2.7.0": version: 2.7.0 resolution: "bare-events@npm:2.7.0" @@ -10022,6 +10046,24 @@ __metadata: languageName: node linkType: hard +"brace-expansion@npm:^2.0.2": + version: 2.0.2 + resolution: "brace-expansion@npm:2.0.2" + dependencies: + balanced-match: "npm:^1.0.0" + checksum: 10/01dff195e3646bc4b0d27b63d9bab84d2ebc06121ff5013ad6e5356daa5a9d6b60fa26cf73c74797f2dc3fbec112af13578d51f75228c1112b26c790a87b0488 + languageName: node + linkType: hard + +"brace-expansion@npm:^5.0.2": + version: 5.0.4 + resolution: "brace-expansion@npm:5.0.4" + dependencies: + balanced-match: "npm:^4.0.2" + checksum: 10/cfd57e20d8ded9578149e47ae4d3fff2b2f78d06b54a32a73057bddff65c8e9b930613f0cbcfefedf12dd117151e19d4da16367d5127c54f3bff02d8a4479bb2 + languageName: node + linkType: hard + "braces@npm:^3.0.3, braces@npm:~3.0.2": version: 3.0.3 resolution: "braces@npm:3.0.3" @@ -10945,7 +10987,7 @@ __metadata: languageName: node linkType: hard -"compressible@npm:^2.0.18, compressible@npm:~2.0.16, compressible@npm:~2.0.18": +"compressible@npm:^2.0.18, compressible@npm:~2.0.18": version: 2.0.18 resolution: "compressible@npm:2.0.18" dependencies: @@ -10954,18 +10996,18 @@ __metadata: languageName: node linkType: hard -"compression@npm:1.7.4": - version: 1.7.4 - resolution: "compression@npm:1.7.4" +"compression@npm:1.8.1": + version: 1.8.1 + resolution: "compression@npm:1.8.1" dependencies: - accepts: "npm:~1.3.5" - bytes: "npm:3.0.0" - compressible: "npm:~2.0.16" + bytes: "npm:3.1.2" + compressible: "npm:~2.0.18" debug: "npm:2.6.9" - on-headers: "npm:~1.0.2" - safe-buffer: "npm:5.1.2" + negotiator: "npm:~0.6.4" + on-headers: "npm:~1.1.0" + safe-buffer: "npm:5.2.1" vary: "npm:~1.1.2" - checksum: 10/469cd097908fe1d3ff146596d4c24216ad25eabb565c5456660bdcb3a14c82ebc45c23ce56e19fc642746cf407093b55ab9aa1ac30b06883b27c6c736e6383c2 + checksum: 10/e7552bfbd780f2003c6fe8decb44561f5cc6bc82f0c61e81122caff5ec656f37824084f52155b1e8ef31d7656cecbec9a2499b7a68e92e20780ffb39b479abb7 languageName: node linkType: hard @@ -16136,9 +16178,9 @@ __metadata: languageName: node linkType: hard -"koa@npm:^2.16.1": - version: 2.16.2 - resolution: "koa@npm:2.16.2" +"koa@npm:^2.16.4": + version: 2.16.4 + resolution: "koa@npm:2.16.4" dependencies: accepts: "npm:^1.3.5" cache-content-type: "npm:^1.0.0" @@ -16163,7 +16205,7 @@ __metadata: statuses: "npm:^1.5.0" type-is: "npm:^1.6.16" vary: "npm:^1.1.2" - checksum: 10/741e389b31a36752c47543f06bcb9b63c19b2649487a266bd83ff363e651d864bbff5d1154a0b310f5db4d11e03060440df0113bad3ef82ac9f051874c789dee + checksum: 10/f49e76c2cb7db4facbf215eef964c1eb3f0012c2f64490dfd9b349727e11c7f429f4bf16a47f725e41325415ffebefab0ca6ece3b1187518b42f979e4dbf6e01 languageName: node linkType: hard @@ -16926,39 +16968,39 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" +"minimatch@npm:3.1.5, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": + version: 3.1.5 + resolution: "minimatch@npm:3.1.5" dependencies: brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 + checksum: 10/b11a7ee5773cd34c1a0c8436cdbe910901018fb4b6cb47aa508a18d567f6efd2148507959e35fba798389b161b8604a2d704ccef751ea36bd4582f9852b7d63f languageName: node linkType: hard "minimatch@npm:^10.1.1, minimatch@npm:^9.0.3 || ^10.0.1": - version: 10.1.1 - resolution: "minimatch@npm:10.1.1" + version: 10.2.4 + resolution: "minimatch@npm:10.2.4" dependencies: - "@isaacs/brace-expansion": "npm:^5.0.0" - checksum: 10/110f38921ea527022e90f7a5f43721838ac740d0a0c26881c03b57c261354fb9a0430e40b2c56dfcea2ef3c773768f27210d1106f1f2be19cde3eea93f26f45e + brace-expansion: "npm:^5.0.2" + checksum: 10/aea4874e521c55bb60744685bbffe3d152e5460f84efac3ea936e6bbe2ceba7deb93345fec3f9bb17f7b6946776073a64d40ae32bf5f298ad690308121068a1f languageName: node linkType: hard "minimatch@npm:^5.0.1, minimatch@npm:^5.1.6": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" + version: 5.1.9 + resolution: "minimatch@npm:5.1.9" dependencies: brace-expansion: "npm:^2.0.1" - checksum: 10/126b36485b821daf96d33b5c821dac600cc1ab36c87e7a532594f9b1652b1fa89a1eebcaad4dff17c764dce1a7ac1531327f190fed5f97d8f6e5f889c116c429 + checksum: 10/23b4feb64dcb77ba93b70a72be551eb2e2677ac02178cf1ed3d38836cc4cd84802d90b77f60ef87f2bac64d270d2d8eba242e428f0554ea4e36bfdb7e9d25d0c languageName: node linkType: hard "minimatch@npm:^9.0.1, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4, minimatch@npm:^9.0.5": - version: 9.0.5 - resolution: "minimatch@npm:9.0.5" + version: 9.0.9 + resolution: "minimatch@npm:9.0.9" dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 + brace-expansion: "npm:^2.0.2" + checksum: 10/b91fad937deaffb68a45a2cb731ff3cff1c3baf9b6469c879477ed16f15c8f4ce39d63a3f75c2455107c2fdff0f3ab597d97dc09e2e93b883aafcf926ef0c8f9 languageName: node linkType: hard @@ -17455,10 +17497,10 @@ __metadata: languageName: node linkType: hard -"node-forge@npm:^1, node-forge@npm:^1.1.0": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 10/05bab6868633bf9ad4c3b1dd50ec501c22ffd69f556cdf169a00998ca1d03e8107a6032ba013852f202035372021b845603aeccd7dfcb58cdb7430013b3daa8d +"node-forge@npm:^1.3.2": + version: 1.3.3 + resolution: "node-forge@npm:1.3.3" + checksum: 10/f41c31b9296771a4b8c955d58417471712f54f324603a35f8e6cbac19d5e6eaaf5fd5fd14584dfedecbf46a05438ded6eee60a5f2f0822fc5061aaa073cfc75d languageName: node linkType: hard @@ -17733,6 +17775,13 @@ __metadata: languageName: node linkType: hard +"on-headers@npm:~1.1.0": + version: 1.1.0 + resolution: "on-headers@npm:1.1.0" + checksum: 10/98aa64629f986fb8cc4517dd8bede73c980e31208cba97f4442c330959f60ced3dc6214b83420491f5111fc7c4f4343abe2ea62c85f505cf041d67850f238776 + languageName: node + linkType: hard + "on-net-listen@npm:^1.1.0": version: 1.1.2 resolution: "on-net-listen@npm:1.1.2" @@ -19422,32 +19471,35 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^4.43.0": - version: 4.52.3 - resolution: "rollup@npm:4.52.3" - dependencies: - "@rollup/rollup-android-arm-eabi": "npm:4.52.3" - "@rollup/rollup-android-arm64": "npm:4.52.3" - "@rollup/rollup-darwin-arm64": "npm:4.52.3" - "@rollup/rollup-darwin-x64": "npm:4.52.3" - "@rollup/rollup-freebsd-arm64": "npm:4.52.3" - "@rollup/rollup-freebsd-x64": "npm:4.52.3" - "@rollup/rollup-linux-arm-gnueabihf": "npm:4.52.3" - "@rollup/rollup-linux-arm-musleabihf": "npm:4.52.3" - "@rollup/rollup-linux-arm64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-arm64-musl": "npm:4.52.3" - "@rollup/rollup-linux-loong64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-ppc64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-riscv64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-riscv64-musl": "npm:4.52.3" - "@rollup/rollup-linux-s390x-gnu": "npm:4.52.3" - "@rollup/rollup-linux-x64-gnu": "npm:4.52.3" - "@rollup/rollup-linux-x64-musl": "npm:4.52.3" - "@rollup/rollup-openharmony-arm64": "npm:4.52.3" - "@rollup/rollup-win32-arm64-msvc": "npm:4.52.3" - "@rollup/rollup-win32-ia32-msvc": "npm:4.52.3" - "@rollup/rollup-win32-x64-gnu": "npm:4.52.3" - "@rollup/rollup-win32-x64-msvc": "npm:4.52.3" +"rollup@npm:^4.59.0": + version: 4.59.0 + resolution: "rollup@npm:4.59.0" + dependencies: + "@rollup/rollup-android-arm-eabi": "npm:4.59.0" + "@rollup/rollup-android-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-arm64": "npm:4.59.0" + "@rollup/rollup-darwin-x64": "npm:4.59.0" + "@rollup/rollup-freebsd-arm64": "npm:4.59.0" + "@rollup/rollup-freebsd-x64": "npm:4.59.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm-musleabihf": "npm:4.59.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.59.0" + "@rollup/rollup-linux-loong64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-loong64-musl": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-ppc64-musl": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-riscv64-musl": "npm:4.59.0" + "@rollup/rollup-linux-s390x-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.59.0" + "@rollup/rollup-linux-x64-musl": "npm:4.59.0" + "@rollup/rollup-openbsd-x64": "npm:4.59.0" + "@rollup/rollup-openharmony-arm64": "npm:4.59.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.59.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.59.0" + "@rollup/rollup-win32-x64-gnu": "npm:4.59.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.59.0" "@types/estree": "npm:1.0.8" fsevents: "npm:~2.3.2" dependenciesMeta: @@ -19473,8 +19525,12 @@ __metadata: optional: true "@rollup/rollup-linux-loong64-gnu": optional: true + "@rollup/rollup-linux-loong64-musl": + optional: true "@rollup/rollup-linux-ppc64-gnu": optional: true + "@rollup/rollup-linux-ppc64-musl": + optional: true "@rollup/rollup-linux-riscv64-gnu": optional: true "@rollup/rollup-linux-riscv64-musl": @@ -19485,6 +19541,8 @@ __metadata: optional: true "@rollup/rollup-linux-x64-musl": optional: true + "@rollup/rollup-openbsd-x64": + optional: true "@rollup/rollup-openharmony-arm64": optional: true "@rollup/rollup-win32-arm64-msvc": @@ -19499,7 +19557,7 @@ __metadata: optional: true bin: rollup: dist/bin/rollup - checksum: 10/c4db19a7a04fa93b176ccca67a2ff9806f1edf8e4c2d55a362a6557fd957fe330109043b43ba4b8771fb7722d2cb3ef958b11a1b9c44ee4b6c20ee8f8f5ccdea + checksum: 10/728237932aad7022c0640cd126b9fe5285f2578099f22a0542229a17785320a6553b74582fa5977877541c1faf27de65ed2750bc89dbb55b525405244a46d9f1 languageName: node linkType: hard @@ -19557,13 +19615,6 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10/7eb5b48f2ed9a594a4795677d5a150faa7eb54483b2318b568dc0c4fc94092a6cce5be02c7288a0500a156282f5276d5688bce7259299568d1053b2150ef374a - languageName: node - linkType: hard - "safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" @@ -19571,6 +19622,13 @@ __metadata: languageName: node linkType: hard +"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": + version: 5.1.2 + resolution: "safe-buffer@npm:5.1.2" + checksum: 10/7eb5b48f2ed9a594a4795677d5a150faa7eb54483b2318b568dc0c4fc94092a6cce5be02c7288a0500a156282f5276d5688bce7259299568d1053b2150ef374a + languageName: node + linkType: hard + "safe-regex-test@npm:^1.1.0": version: 1.1.0 resolution: "safe-regex-test@npm:1.1.0" @@ -19752,27 +19810,25 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^6.0.2": - version: 6.0.2 - resolution: "serialize-javascript@npm:6.0.2" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10/445a420a6fa2eaee4b70cbd884d538e259ab278200a2ededd73253ada17d5d48e91fb1f4cd224a236ab62ea7ba0a70c6af29fc93b4f3d3078bf7da1c031fde58 +"serialize-javascript@npm:^7.0.3": + version: 7.0.4 + resolution: "serialize-javascript@npm:7.0.4" + checksum: 10/f96d59d6053739785822750e6ffbe06ec5a2651b836b3e6c76742c613e1b2fcb846b5df92294857ecfe69730fe36a1968c0eb8f258b02fd9173a1d5e73f0a32f languageName: node linkType: hard -"serve-handler@npm:6.1.6": - version: 6.1.6 - resolution: "serve-handler@npm:6.1.6" +"serve-handler@npm:6.1.7": + version: 6.1.7 + resolution: "serve-handler@npm:6.1.7" dependencies: bytes: "npm:3.0.0" content-disposition: "npm:0.5.2" mime-types: "npm:2.1.18" - minimatch: "npm:3.1.2" + minimatch: "npm:3.1.5" path-is-inside: "npm:1.0.2" path-to-regexp: "npm:3.3.0" range-parser: "npm:1.2.0" - checksum: 10/7e7d93eb7e69fcd9f9c5afc2ef2b46cb0072b4af13cbabef9bca725afb350ddae6857d8c8be2c256f7ce1f7677c20347801399c11caa5805c0090339f894e8f2 + checksum: 10/2366e53cc8e8376d58abb289293b930111fa5da6d14bb31eafac5b1162f332c45c6f394c7d78fdcf6b5736e12caf9370b02d05c7e8a75291d2fc6a55b52b14ea languageName: node linkType: hard @@ -19815,24 +19871,24 @@ __metadata: languageName: node linkType: hard -"serve@npm:^14.2.1": - version: 14.2.4 - resolution: "serve@npm:14.2.4" +"serve@npm:^14.2.6": + version: 14.2.6 + resolution: "serve@npm:14.2.6" dependencies: "@zeit/schemas": "npm:2.36.0" - ajv: "npm:8.12.0" + ajv: "npm:8.18.0" arg: "npm:5.0.2" boxen: "npm:7.0.0" chalk: "npm:5.0.1" chalk-template: "npm:0.4.0" clipboardy: "npm:3.0.0" - compression: "npm:1.7.4" + compression: "npm:1.8.1" is-port-reachable: "npm:4.0.0" - serve-handler: "npm:6.1.6" + serve-handler: "npm:6.1.7" update-check: "npm:1.5.4" bin: serve: build/main.js - checksum: 10/79627f399226b765f6e2f0f62faeceda5db17d00f40f9ad9faa39049729ea4ce7b595a72cc0dba3543947288772cb60f2b0ab91efa3bbedfe644ca7ee0484df1 + checksum: 10/5ed677e260b21eb6c3f04d5d109f258a06272881d91cbb71a6e2dae6045653d59ae535c94644c017b03db5b472e35523cda287328feaa1d629d4674960ceaa86 languageName: node linkType: hard @@ -20793,12 +20849,12 @@ __metadata: languageName: node linkType: hard -"systeminformation@npm:5.23.8": - version: 5.23.8 - resolution: "systeminformation@npm:5.23.8" +"systeminformation@npm:^5.31.0": + version: 5.31.1 + resolution: "systeminformation@npm:5.31.1" bin: systeminformation: lib/cli.js - checksum: 10/a722b50a2740a4f880901ccbeb854d12d6abe33c3777c5db040eeee4282a1bf52d73d9f41d63d69e897b2cab083c993f1c8f7217c386989456eb920cb2b6b3b7 + checksum: 10/1fff0b2827f7de2ec5379385c9bb12896db92186ee1d721cb08791ae7277a02f39fb8f3060df47312b70fe88c5b91a70726e7265ca8e5bab1f87780fb2acb991 conditions: (os=darwin | os=linux | os=win32 | os=freebsd | os=openbsd | os=netbsd | os=sunos | os=android) languageName: node linkType: hard