From 48dbc5887c32ee891e94d41c614c96913812e6ab Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Fri, 5 Jan 2024 18:10:38 +0100 Subject: [PATCH 01/70] deps: update bls-keystore to v3.0.0 (#6253) --- packages/cli/package.json | 2 +- packages/test-utils/package.json | 2 +- yarn.lock | 126 +++---------------------------- 3 files changed, 14 insertions(+), 116 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index d566258e7f5d..047672c18855 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -56,7 +56,7 @@ "@chainsafe/as-sha256": "^0.3.1", "@chainsafe/bls": "7.1.1", "@chainsafe/bls-keygen": "^0.3.0", - "@chainsafe/bls-keystore": "^2.0.0", + "@chainsafe/bls-keystore": "^3.0.0", "@chainsafe/blst": "^0.2.9", "@chainsafe/discv5": "^5.1.0", "@chainsafe/persistent-merkle-tree": "^0.6.1", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 586be26fccab..6f6152375e1f 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -62,7 +62,7 @@ ], "dependencies": { "@chainsafe/bls": "7.1.1", - "@chainsafe/bls-keystore": "^2.0.0", + "@chainsafe/bls-keystore": "^3.0.0", "@lodestar/params": "^1.13.0", "@lodestar/utils": "^1.13.0", "axios": "^1.3.4", diff --git a/yarn.lock b/yarn.lock index 291225ebedf5..ccdbf1a57273 100644 --- a/yarn.lock +++ b/yarn.lock @@ -511,15 +511,13 @@ "@noble/hashes" "^1.0.0" "@scure/bip39" "^1.0.0" -"@chainsafe/bls-keystore@^2.0.0": - version "2.0.0" - resolved "https://registry.npmjs.org/@chainsafe/bls-keystore/-/bls-keystore-2.0.0.tgz" - integrity sha512-XGtgGKdjYqKP09SUsfwaStsYuWuXB56/614dC1XhggG4LH8KTrFOjxb9SkS+T1BUu5doCXd9YA+gNLy01zv+Ww== +"@chainsafe/bls-keystore@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@chainsafe/bls-keystore/-/bls-keystore-3.0.0.tgz#e28c979f7664417e4917fa0d4d32fa2b9416e9c6" + integrity sha512-vlRIIXnn555wq2emhqnSR7btno17M0sCcfdQ+Dhgr7IH6n0CMoTGw9qcrpnNYwM+9OPm3matSYeZc9mNlXf7fQ== dependencies: - ajv "^6.12.2" - buffer "^5.4.3" - ethereum-cryptography "^0.1.3" - uuid "^3.3.3" + ethereum-cryptography "^1.0.0" + uuid "8.3.2" "@chainsafe/bls@7.1.1": version "7.1.1" @@ -3389,13 +3387,6 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== -"@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz" - integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== - dependencies: - "@types/node" "*" - "@types/qs@^6.9.7": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -3426,13 +3417,6 @@ resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== -"@types/secp256k1@^4.0.1": - version "4.0.2" - resolved "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.2.tgz" - integrity sha512-QMg+9v0bbNJ2peLuHRWxzmy0HRJIG6gFZNhaRSp7S3ggSbCCxiqQB2/ybvhXyhHOCequpNkrx7OavNhrWOsW0A== - dependencies: - "@types/node" "*" - "@types/semver@^7.5.0": version "7.5.2" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" @@ -4122,16 +4106,6 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.2: - version "6.12.3" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz" - integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -4595,13 +4569,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: - version "3.0.8" - resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.8.tgz" - integrity sha512-Rl/1AWP4J/zRrk54hhlxH4drNxPJXYUaKffODVI53/dAsV4t9fBxyxYKAVPU1XBHxYwOWP9h9H0hM2MVw4YfJA== - dependencies: - safe-buffer "^5.0.1" - base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -4737,11 +4704,6 @@ bl@^5.0.0: inherits "^2.0.4" readable-stream "^3.4.0" -blakejs@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/blakejs/-/blakejs-1.1.0.tgz" - integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= - bls-eth-wasm@^0.4.8: version "0.4.8" resolved "https://registry.npmjs.org/bls-eth-wasm/-/bls-eth-wasm-0.4.8.tgz" @@ -4846,7 +4808,7 @@ browser-stdout@1.3.1: resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: +browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== @@ -4917,22 +4879,6 @@ browserslist@^4.14.5: node-releases "^2.0.6" update-browserslist-db "^1.0.4" -bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= - dependencies: - base-x "^3.0.2" - -bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -6534,7 +6480,7 @@ electron@^26.2.2: "@types/node" "^18.11.18" extract-zip "^2.0.1" -elliptic@6.5.4, elliptic@^6.5.2, elliptic@^6.5.3: +elliptic@6.5.4, elliptic@^6.5.3: version "6.5.4" resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== @@ -7187,28 +7133,7 @@ esutils@^2.0.2: resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - -ethereum-cryptography@^1.2.0: +ethereum-cryptography@^1.0.0, ethereum-cryptography@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz#5ccfa183e85fdaf9f9b299a79430c044268c9b3a" integrity sha512-6yFQC9b5ug6/17CQpCyE3k9eKBMdhyVjzUy1WkiuY/E4vj/SXDBbCw8QEIaXqf0Mf2SnY6RmpDcwlUmBSS0EJw== @@ -8475,7 +8400,7 @@ hash-base@^3.0.0: readable-stream "^3.6.0" safe-buffer "^5.2.0" -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== @@ -9949,14 +9874,6 @@ karma@^6.4.2: ua-parser-js "^0.7.30" yargs "^16.1.1" -keccak@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/keccak/-/keccak-3.0.1.tgz" - integrity sha512-epq90L9jlFWCW7+pQa6JOnKn2Xgl2mtI664seYR6MHskvI9agt7AnDqmAlp9TqU4/caMYbA08Hi5DMZAl5zdkA== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - keypress@0.1.x: version "0.1.0" resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.1.0.tgz#4a3188d4291b66b4f65edb99f806aa9ae293592a" @@ -11210,11 +11127,6 @@ nise@^5.1.4: just-extend "^4.0.2" path-to-regexp "^1.7.0" -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - node-addon-api@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -11256,11 +11168,6 @@ node-forge@^1.1.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp-build@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz" - integrity sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg== - node-gyp-build@^4.3.0: version "4.5.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.5.0.tgz#7a64eefa0b21112f89f58379da128ac177f20e40" @@ -12310,7 +12217,7 @@ pathval@^1.1.1: resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: +pbkdf2@^3.0.3, pbkdf2@^3.0.9: version "3.1.2" resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== @@ -13388,20 +13295,11 @@ schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -scrypt-js@3.0.1, scrypt-js@^3.0.0: +scrypt-js@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== -secp256k1@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz" - integrity sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg== - dependencies: - elliptic "^6.5.2" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - secure-json-parse@^2.5.0: version "2.7.0" resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-2.7.0.tgz#5a5f9cd6ae47df23dba3151edd06855d47e09862" From b3e5621ae825ba97eff1f79387df478e635fb14e Mon Sep 17 00:00:00 2001 From: g11tech Date: Sun, 7 Jan 2024 21:51:17 +0530 Subject: [PATCH 02/70] feat: schedule deneb on goerli (#6254) --- packages/config/src/chainConfig/networks/goerli.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/config/src/chainConfig/networks/goerli.ts b/packages/config/src/chainConfig/networks/goerli.ts index 9386c10b0577..f1fc0ab2418c 100644 --- a/packages/config/src/chainConfig/networks/goerli.ts +++ b/packages/config/src/chainConfig/networks/goerli.ts @@ -34,4 +34,7 @@ export const goerliChainConfig: ChainConfig = { // Capella CAPELLA_FORK_VERSION: b("0x03001020"), CAPELLA_FORK_EPOCH: 162304, + // Deneb + DENEB_FORK_VERSION: b("0x04001020"), + DENEB_FORK_EPOCH: 231680, }; From fce884d89086af890da2b40d64480b0fddded8b9 Mon Sep 17 00:00:00 2001 From: g11tech Date: Mon, 8 Jan 2024 23:35:33 +0530 Subject: [PATCH 03/70] feat: add and support builder_boost_factor query param to produceBlockV3 api (#6236) * feat: add and support builder_boost_factor query param to produceBlockV3 api lint * add keymanager endpoint and update the test * update builder boost factor to bigint * update the help Co-authored-by: Nico Flaig * remove comment * validate and use boostfactor ranges as per spec * fix test * correct typo Co-authored-by: NC * fix the block selection condition * fixes for spec complaince * fix the keymanager routes * comment typo fix Co-authored-by: Nico Flaig --------- Co-authored-by: Nico Flaig Co-authored-by: NC --- packages/api/src/beacon/routes/validator.ts | 10 +++ packages/api/src/keymanager/routes.ts | 69 +++++++++++++++++++ .../test/unit/beacon/testData/validator.ts | 32 +++++++-- packages/api/test/unit/keymanager/testData.ts | 13 ++++ .../src/api/impl/validator/index.ts | 25 ++++++- packages/cli/src/cmds/validator/handler.ts | 1 + .../cli/src/cmds/validator/keymanager/impl.ts | 23 +++++++ packages/cli/src/cmds/validator/options.ts | 9 +++ packages/validator/src/index.ts | 2 +- packages/validator/src/services/block.ts | 60 +++++++++++----- .../src/services/prepareBeaconProposer.ts | 3 +- .../validator/src/services/validatorStore.ts | 66 +++++++++++++++++- .../test/unit/services/block.test.ts | 26 +++++++ 13 files changed, 312 insertions(+), 27 deletions(-) diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 78fc1a67d32c..0746797cbf0e 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -13,6 +13,7 @@ import { Slot, ssz, UintNum64, + UintBn64, ValidatorIndex, RootHex, StringType, @@ -53,6 +54,7 @@ export enum BuilderSelection { export type ExtraProduceBlockOps = { feeRecipient?: string; builderSelection?: BuilderSelection; + builderBoostFactor?: UintBn64; strictFeeRecipientCheck?: boolean; blindedLocal?: boolean; }; @@ -487,6 +489,7 @@ export type ReqTypes = { skip_randao_verification?: boolean; fee_recipient?: string; builder_selection?: string; + builder_boost_factor?: string; strict_fee_recipient_check?: boolean; blinded_local?: boolean; }; @@ -555,6 +558,7 @@ export function getReqSerializers(): ReqSerializers { fee_recipient: opts?.feeRecipient, skip_randao_verification: skipRandaoVerification, builder_selection: opts?.builderSelection, + builder_boost_factor: opts?.builderBoostFactor?.toString(), strict_fee_recipient_check: opts?.strictFeeRecipientCheck, blinded_local: opts?.blindedLocal, }, @@ -567,6 +571,7 @@ export function getReqSerializers(): ReqSerializers { { feeRecipient: query.fee_recipient, builderSelection: query.builder_selection as BuilderSelection, + builderBoostFactor: parseBuilderBoostFactor(query.builder_boost_factor), strictFeeRecipientCheck: query.strict_fee_recipient_check, blindedLocal: query.blinded_local, }, @@ -579,6 +584,7 @@ export function getReqSerializers(): ReqSerializers { fee_recipient: Schema.String, skip_randao_verification: Schema.Boolean, builder_selection: Schema.String, + builder_boost_factor: Schema.String, strict_fee_recipient_check: Schema.Boolean, blinded_local: Schema.Boolean, }, @@ -785,3 +791,7 @@ export function getReturnTypes(): ReturnTypes { getLiveness: jsonType("snake"), }; } + +function parseBuilderBoostFactor(builderBoostFactorInput?: string | number | bigint): bigint | undefined { + return builderBoostFactorInput !== undefined ? BigInt(builderBoostFactorInput) : undefined; +} diff --git a/packages/api/src/keymanager/routes.ts b/packages/api/src/keymanager/routes.ts index 09f5e7610604..48f928e86100 100644 --- a/packages/api/src/keymanager/routes.ts +++ b/packages/api/src/keymanager/routes.ts @@ -72,6 +72,10 @@ export type GasLimitData = { pubkey: string; gasLimit: number; }; +export type BuilderBoostFactorData = { + pubkey: string; + builderBoostFactor: bigint; +}; export type SignerDefinition = { pubkey: PubkeyHex; @@ -247,6 +251,27 @@ export type Api = { > >; + getBuilderBoostFactor( + pubkey: string + ): Promise>; + setBuilderBoostFactor( + pubkey: string, + builderBoostFactor: bigint + ): Promise< + ApiClientResponse< + {[HttpStatusCode.OK]: void; [HttpStatusCode.NO_CONTENT]: void}, + HttpStatusCode.UNAUTHORIZED | HttpStatusCode.FORBIDDEN | HttpStatusCode.NOT_FOUND + > + >; + deleteBuilderBoostFactor( + pubkey: string + ): Promise< + ApiClientResponse< + {[HttpStatusCode.OK]: void; [HttpStatusCode.NO_CONTENT]: void}, + HttpStatusCode.UNAUTHORIZED | HttpStatusCode.FORBIDDEN | HttpStatusCode.NOT_FOUND + > + >; + /** * Create a signed voluntary exit message for an active validator, identified by a public key known to the validator * client. This endpoint returns a `SignedVoluntaryExit` object, which can be used to initiate voluntary exit via the @@ -290,6 +315,10 @@ export const routesData: RoutesData = { setGasLimit: {url: "/eth/v1/validator/{pubkey}/gas_limit", method: "POST", statusOk: 202}, deleteGasLimit: {url: "/eth/v1/validator/{pubkey}/gas_limit", method: "DELETE", statusOk: 204}, + getBuilderBoostFactor: {url: "/eth/v1/validator/{pubkey}/builder_boost_factor", method: "GET"}, + setBuilderBoostFactor: {url: "/eth/v1/validator/{pubkey}/builder_boost_factor", method: "POST", statusOk: 202}, + deleteBuilderBoostFactor: {url: "/eth/v1/validator/{pubkey}/builder_boost_factor", method: "DELETE", statusOk: 204}, + signVoluntaryExit: {url: "/eth/v1/validator/{pubkey}/voluntary_exit", method: "POST"}, }; @@ -326,6 +355,10 @@ export type ReqTypes = { setGasLimit: {params: {pubkey: string}; body: {gas_limit: string}}; deleteGasLimit: {params: {pubkey: string}}; + getBuilderBoostFactor: {params: {pubkey: string}}; + setBuilderBoostFactor: {params: {pubkey: string}; body: {builder_boost_factor: string}}; + deleteBuilderBoostFactor: {params: {pubkey: string}}; + signVoluntaryExit: {params: {pubkey: string}; query: {epoch?: number}}; }; @@ -423,6 +456,33 @@ export function getReqSerializers(): ReqSerializers { params: {pubkey: Schema.StringRequired}, }, }, + + getBuilderBoostFactor: { + writeReq: (pubkey) => ({params: {pubkey}}), + parseReq: ({params: {pubkey}}) => [pubkey], + schema: { + params: {pubkey: Schema.StringRequired}, + }, + }, + setBuilderBoostFactor: { + writeReq: (pubkey, builderBoostFactor) => ({ + params: {pubkey}, + body: {builder_boost_factor: builderBoostFactor.toString(10)}, + }), + parseReq: ({params: {pubkey}, body: {builder_boost_factor}}) => [pubkey, BigInt(builder_boost_factor)], + schema: { + params: {pubkey: Schema.StringRequired}, + body: Schema.Object, + }, + }, + deleteBuilderBoostFactor: { + writeReq: (pubkey) => ({params: {pubkey}}), + parseReq: ({params: {pubkey}}) => [pubkey], + schema: { + params: {pubkey: Schema.StringRequired}, + }, + }, + signVoluntaryExit: { writeReq: (pubkey, epoch) => ({params: {pubkey}, query: epoch !== undefined ? {epoch} : {}}), parseReq: ({params: {pubkey}, query: {epoch}}) => [pubkey, epoch], @@ -455,6 +515,15 @@ export function getReturnTypes(): ReturnTypes { {jsonCase: "eth2"} ) ), + getBuilderBoostFactor: ContainerData( + new ContainerType( + { + pubkey: stringType, + builderBoostFactor: ssz.UintBn64, + }, + {jsonCase: "eth2"} + ) + ), signVoluntaryExit: ContainerData(ssz.phase0.SignedVoluntaryExit), }; } diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index c10f67fa4095..2688f2080eba 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -50,7 +50,13 @@ export const testData: GenericServerTestCases = { randaoReveal, graffiti, undefined, - {feeRecipient: undefined, builderSelection: undefined, strictFeeRecipientCheck: undefined}, + { + feeRecipient, + builderSelection: undefined, + strictFeeRecipientCheck: undefined, + blindedLocal: undefined, + builderBoostFactor: 100n, + }, ] as unknown as GenericServerTestCases["produceBlock"]["args"], res: {data: ssz.phase0.BeaconBlock.defaultValue()}, }, @@ -60,7 +66,13 @@ export const testData: GenericServerTestCases = { randaoReveal, graffiti, undefined, - {feeRecipient: undefined, builderSelection: undefined, strictFeeRecipientCheck: undefined}, + { + feeRecipient, + builderSelection: undefined, + strictFeeRecipientCheck: undefined, + blindedLocal: undefined, + builderBoostFactor: 100n, + }, ] as unknown as GenericServerTestCases["produceBlockV2"]["args"], res: { data: ssz.altair.BeaconBlock.defaultValue(), @@ -75,7 +87,13 @@ export const testData: GenericServerTestCases = { randaoReveal, graffiti, true, - {feeRecipient, builderSelection: undefined, strictFeeRecipientCheck: undefined}, + { + feeRecipient, + builderSelection: undefined, + strictFeeRecipientCheck: undefined, + blindedLocal: undefined, + builderBoostFactor: 100n, + }, ], res: { data: ssz.altair.BeaconBlock.defaultValue(), @@ -92,7 +110,13 @@ export const testData: GenericServerTestCases = { randaoReveal, graffiti, undefined, - {feeRecipient: undefined, builderSelection: undefined, strictFeeRecipientCheck: undefined}, + { + feeRecipient, + builderSelection: undefined, + strictFeeRecipientCheck: undefined, + blindedLocal: undefined, + builderBoostFactor: 100n, + }, ] as unknown as GenericServerTestCases["produceBlindedBlock"]["args"], res: { data: ssz.bellatrix.BlindedBeaconBlock.defaultValue(), diff --git a/packages/api/test/unit/keymanager/testData.ts b/packages/api/test/unit/keymanager/testData.ts index a4fc72fc8e2d..2c66610c8733 100644 --- a/packages/api/test/unit/keymanager/testData.ts +++ b/packages/api/test/unit/keymanager/testData.ts @@ -13,6 +13,7 @@ const pubkeyRand = "0x84105a985058fc8740a48bf1ede9d223ef09e8c6b1735ba0a55cf4a9ff const ethaddressRand = "0xabcf8e0d4e9587369b2301d0790347320302cc09"; const graffitiRandUtf8 = "636861696e736166652f6c6f64657374"; const gasLimitRand = 30_000_000; +const builderBoostFactorRand = BigInt(100); export const testData: GenericServerTestCases = { listKeys: { @@ -99,4 +100,16 @@ export const testData: GenericServerTestCases = { args: [pubkeyRand, 1], res: {data: ssz.phase0.SignedVoluntaryExit.defaultValue()}, }, + getBuilderBoostFactor: { + args: [pubkeyRand], + res: {data: {pubkey: pubkeyRand, builderBoostFactor: builderBoostFactorRand}}, + }, + setBuilderBoostFactor: { + args: [pubkeyRand, builderBoostFactorRand], + res: undefined, + }, + deleteBuilderBoostFactor: { + args: [pubkeyRand], + res: undefined, + }, }; diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 395684960c7f..9f98c606d525 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -19,6 +19,7 @@ import { isForkExecution, ForkSeq, } from "@lodestar/params"; +import {MAX_BUILDER_BOOST_FACTOR} from "@lodestar/validator"; import { Root, Slot, @@ -423,7 +424,12 @@ export function getValidatorApi({ graffiti, // TODO deneb: skip randao verification _skipRandaoVerification?: boolean, - {feeRecipient, builderSelection, strictFeeRecipientCheck}: routes.validator.ExtraProduceBlockOps = {} + { + feeRecipient, + builderSelection, + builderBoostFactor, + strictFeeRecipientCheck, + }: routes.validator.ExtraProduceBlockOps = {} ) { notWhileSyncing(); await waitForSlot(slot); // Must never request for a future slot > currentSlot @@ -436,7 +442,14 @@ export function getValidatorApi({ const fork = config.getForkName(slot); // set some sensible opts + // builderSelection will be deprecated and will run in mode MaxProfit if builder is enabled + // and the actual selection will be determined using builderBoostFactor passed by the validator builderSelection = builderSelection ?? routes.validator.BuilderSelection.MaxProfit; + builderBoostFactor = builderBoostFactor ?? BigInt(100); + if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) { + throw new ApiError(400, `Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR`); + } + const isBuilderEnabled = ForkSeq[fork] >= ForkSeq.bellatrix && chain.executionBuilder !== undefined && @@ -448,6 +461,8 @@ export function getValidatorApi({ slot, isBuilderEnabled, strictFeeRecipientCheck, + // winston logger doesn't like bigint + builderBoostFactor: `${builderBoostFactor}`, }); // Start calls for building execution and builder blocks const blindedBlockPromise = isBuilderEnabled @@ -541,7 +556,12 @@ export function getValidatorApi({ if (fullBlock && blindedBlock) { switch (builderSelection) { case routes.validator.BuilderSelection.MaxProfit: { - if (blockValueEngine >= blockValueBuilder) { + if ( + // explicitly handle the two special values mentioned in spec for builder preferred / engine preferred + builderBoostFactor !== MAX_BUILDER_BOOST_FACTOR && + (builderBoostFactor === BigInt(0) || + blockValueEngine >= (blockValueBuilder * builderBoostFactor) / BigInt(100)) + ) { executionPayloadSource = ProducedBlockSource.engine; } else { executionPayloadSource = ProducedBlockSource.builder; @@ -562,6 +582,7 @@ export function getValidatorApi({ logger.verbose(`Selected executionPayloadSource=${executionPayloadSource} block`, { builderSelection, // winston logger doesn't like bigint + builderBoostFactor: `${builderBoostFactor}`, enginePayloadValue: `${enginePayloadValue}`, builderPayloadValue: `${builderPayloadValue}`, consensusBlockValueEngine: `${consensusBlockValueEngine}`, diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 69e4610bff0e..57b00d78c706 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -227,6 +227,7 @@ function getProposerConfigFromArgs( selection: parseBuilderSelection( args["builder.selection"] ?? (args["builder"] ? defaultOptions.builderAliasSelection : undefined) ), + boostFactor: args["builder.boostFactor"], }, }; diff --git a/packages/cli/src/cmds/validator/keymanager/impl.ts b/packages/cli/src/cmds/validator/keymanager/impl.ts index 2abda3c9642e..4628c96285df 100644 --- a/packages/cli/src/cmds/validator/keymanager/impl.ts +++ b/packages/cli/src/cmds/validator/keymanager/impl.ts @@ -390,6 +390,29 @@ export class KeymanagerApi implements Api { }; } + async getBuilderBoostFactor(pubkeyHex: string): ReturnType { + const builderBoostFactor = this.validator.validatorStore.getBuilderBoostFactor(pubkeyHex); + return {data: {pubkey: pubkeyHex, builderBoostFactor}}; + } + + async setBuilderBoostFactor(pubkeyHex: string, builderBoostFactor: bigint): Promise { + this.checkIfProposerWriteEnabled(); + this.validator.validatorStore.setBuilderBoostFactor(pubkeyHex, builderBoostFactor); + this.persistedKeysBackend.writeProposerConfig( + pubkeyHex, + this.validator.validatorStore.getProposerConfig(pubkeyHex) + ); + } + + async deleteBuilderBoostFactor(pubkeyHex: string): Promise { + this.checkIfProposerWriteEnabled(); + this.validator.validatorStore.deleteBuilderBoostFactor(pubkeyHex); + this.persistedKeysBackend.writeProposerConfig( + pubkeyHex, + this.validator.validatorStore.getProposerConfig(pubkeyHex) + ); + } + /** * Create and sign a voluntary exit message for an active validator */ diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 41069cfbdd34..e68e04a4b884 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -45,6 +45,7 @@ export type IValidatorCliArgs = AccountValidatorArgs & builder?: boolean; "builder.selection"?: string; + "builder.boostFactor"?: bigint; useProduceBlockV3?: boolean; broadcastValidation?: string; @@ -246,6 +247,14 @@ export const validatorOptions: CliCommandOptions = { group: "builder", }, + "builder.boostFactor": { + type: "number", + description: + "Percentage multiplier the block producing beacon node must apply to boost (>100) or dampen (<100) builder block value for selection against execution block. The multiplier is ignored if `--builder.selection` is set to anything other than `maxprofit`", + defaultDescription: `${defaultOptions.builderBoostFactor}`, + group: "builder", + }, + useProduceBlockV3: { type: "boolean", description: "Enable/disable usage of produceBlockV3 that might not be supported by all beacon clients yet", diff --git a/packages/validator/src/index.ts b/packages/validator/src/index.ts index 381db59b7c85..4619b924ef63 100644 --- a/packages/validator/src/index.ts +++ b/packages/validator/src/index.ts @@ -1,5 +1,5 @@ export {Validator, type ValidatorOptions} from "./validator.js"; -export {ValidatorStore, SignerType, defaultOptions} from "./services/validatorStore.js"; +export {ValidatorStore, SignerType, defaultOptions, MAX_BUILDER_BOOST_FACTOR} from "./services/validatorStore.js"; export type { Signer, SignerLocal, diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index b59902870c92..c11af904b34d 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -121,13 +121,15 @@ export class BlockProposingService { const debugLogCtx = {...logCtx, validator: pubkeyHex}; const strictFeeRecipientCheck = this.validatorStore.strictFeeRecipientCheck(pubkeyHex); - const builderSelection = this.validatorStore.getBuilderSelection(pubkeyHex); + const {selection: builderSelection, boostFactor: builderBoostFactor} = + this.validatorStore.getBuilderSelectionParams(pubkeyHex); const feeRecipient = this.validatorStore.getFeeRecipient(pubkeyHex); const blindedLocal = this.opts.blindedLocal; this.logger.debug("Producing block", { ...debugLogCtx, builderSelection, + builderBoostFactor, feeRecipient, strictFeeRecipientCheck, useProduceBlockV3: this.opts.useProduceBlockV3, @@ -139,15 +141,20 @@ export class BlockProposingService { const produceOpts = { feeRecipient, strictFeeRecipientCheck, - builderSelection, + builderBoostFactor, blindedLocal, }; - const blockContents = await produceBlockFn(this.config, slot, randaoReveal, graffiti, produceOpts).catch( - (e: Error) => { - this.metrics?.blockProposingErrors.inc({error: "produce"}); - throw extendError(e, "Failed to produce block"); - } - ); + const blockContents = await produceBlockFn( + this.config, + slot, + randaoReveal, + graffiti, + produceOpts, + builderSelection + ).catch((e: Error) => { + this.metrics?.blockProposingErrors.inc({error: "produce"}); + throw extendError(e, "Failed to produce block"); + }); this.logger.debug("Produced block", {...debugLogCtx, ...blockContents.debugLogCtx}); this.metrics?.blocksProduced.inc(); @@ -195,13 +202,15 @@ export class BlockProposingService { slot: Slot, randaoReveal: BLSSignature, graffiti: string, - {feeRecipient, strictFeeRecipientCheck, builderSelection, blindedLocal}: routes.validator.ExtraProduceBlockOps + {feeRecipient, strictFeeRecipientCheck, builderBoostFactor, blindedLocal}: routes.validator.ExtraProduceBlockOps, + builderSelection: routes.validator.BuilderSelection ): Promise => { const res = await this.api.validator.produceBlockV3(slot, randaoReveal, graffiti, false, { feeRecipient, builderSelection, strictFeeRecipientCheck, blindedLocal, + builderBoostFactor, }); ApiError.assert(res, "Failed to produce block: validator.produceBlockV2"); const {response} = res; @@ -223,7 +232,7 @@ export class BlockProposingService { api: "produceBlockV3", }; - return parseProduceBlockResponse(response, debugLogCtx); + return parseProduceBlockResponse(response, debugLogCtx, builderSelection); }; /** a wrapper function used for backward compatibility with the clients who don't have v3 implemented yet */ @@ -232,7 +241,8 @@ export class BlockProposingService { slot: Slot, randaoReveal: BLSSignature, graffiti: string, - {builderSelection}: routes.validator.ExtraProduceBlockOps + _opts: routes.validator.ExtraProduceBlockOps, + builderSelection: routes.validator.BuilderSelection ): Promise => { // other clients have always implemented builder vs execution race in produce blinded block // so if builderSelection is executiononly then only we call produceBlockV2 else produceBlockV3 always @@ -248,7 +258,8 @@ export class BlockProposingService { return parseProduceBlockResponse( {executionPayloadBlinded: false, executionPayloadSource, ...response}, - debugLogCtx + debugLogCtx, + builderSelection ); } else { Object.assign(debugLogCtx, {api: "produceBlindedBlock"}); @@ -259,7 +270,8 @@ export class BlockProposingService { return parseProduceBlockResponse( {executionPayloadBlinded: true, executionPayloadSource, ...response}, - debugLogCtx + debugLogCtx, + builderSelection ); } }; @@ -267,15 +279,29 @@ export class BlockProposingService { function parseProduceBlockResponse( response: routes.validator.ProduceFullOrBlindedBlockOrContentsRes, - debugLogCtx: Record + debugLogCtx: Record, + builderSelection: routes.validator.BuilderSelection ): FullOrBlindedBlockWithContents & DebugLogCtx { + const executionPayloadSource = response.executionPayloadSource; + + if ( + (builderSelection === routes.validator.BuilderSelection.BuilderOnly && + executionPayloadSource === ProducedBlockSource.engine) || + (builderSelection === routes.validator.BuilderSelection.ExecutionOnly && + executionPayloadSource === ProducedBlockSource.builder) + ) { + throw Error( + `Block not produced as per desired builderSelection=${builderSelection} executionPayloadSource=${executionPayloadSource}` + ); + } + if (response.executionPayloadBlinded) { return { block: response.data, contents: null, version: response.version, executionPayloadBlinded: true, - executionPayloadSource: response.executionPayloadSource, + executionPayloadSource, debugLogCtx, } as FullOrBlindedBlockWithContents & DebugLogCtx; } else { @@ -285,7 +311,7 @@ function parseProduceBlockResponse( contents: {blobs: response.data.blobs, kzgProofs: response.data.kzgProofs}, version: response.version, executionPayloadBlinded: false, - executionPayloadSource: response.executionPayloadSource, + executionPayloadSource, debugLogCtx, } as FullOrBlindedBlockWithContents & DebugLogCtx; } else { @@ -294,7 +320,7 @@ function parseProduceBlockResponse( contents: null, version: response.version, executionPayloadBlinded: false, - executionPayloadSource: response.executionPayloadSource, + executionPayloadSource, debugLogCtx, } as FullOrBlindedBlockWithContents & DebugLogCtx; } diff --git a/packages/validator/src/services/prepareBeaconProposer.ts b/packages/validator/src/services/prepareBeaconProposer.ts index 7ca939fb0c41..7d7907a4592d 100644 --- a/packages/validator/src/services/prepareBeaconProposer.ts +++ b/packages/validator/src/services/prepareBeaconProposer.ts @@ -86,7 +86,8 @@ export function pollBuilderValidatorRegistration( .filter( (pubkeyHex): pubkeyHex is string => pubkeyHex !== undefined && - validatorStore.getBuilderSelection(pubkeyHex) !== routes.validator.BuilderSelection.ExecutionOnly + validatorStore.getBuilderSelectionParams(pubkeyHex).selection !== + routes.validator.BuilderSelection.ExecutionOnly ); if (pubkeyHexes.length > 0) { diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 8cafaa5b14b6..809ca0c8a7c6 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -69,6 +69,7 @@ type DefaultProposerConfig = { builder: { gasLimit: number; selection: routes.validator.BuilderSelection; + boostFactor: bigint; }; }; @@ -79,6 +80,7 @@ export type ProposerConfig = { builder?: { gasLimit?: number; selection?: routes.validator.BuilderSelection; + boostFactor?: bigint; }; }; @@ -123,6 +125,7 @@ export const defaultOptions = { defaultGasLimit: 30_000_000, builderSelection: routes.validator.BuilderSelection.ExecutionOnly, builderAliasSelection: routes.validator.BuilderSelection.MaxProfit, + builderBoostFactor: BigInt(100), // turn it off by default, turn it back on once other clients support v3 api useProduceBlockV3: false, // spec asks for gossip validation by default @@ -131,6 +134,8 @@ export const defaultOptions = { blindedLocal: false, }; +export const MAX_BUILDER_BOOST_FACTOR = BigInt(2 ** 64 - 1); + /** * Service that sets up and handles validator attester duties. */ @@ -155,6 +160,11 @@ export class ValidatorStore { this.metrics = metrics; const defaultConfig = valProposerConfig.defaultConfig; + const builderBoostFactor = defaultConfig.builder?.boostFactor ?? defaultOptions.builderBoostFactor; + if (builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) { + throw Error(`Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR for defaultConfig`); + } + this.defaultProposerConfig = { graffiti: defaultConfig.graffiti ?? "", strictFeeRecipientCheck: defaultConfig.strictFeeRecipientCheck ?? false, @@ -162,6 +172,7 @@ export class ValidatorStore { builder: { gasLimit: defaultConfig.builder?.gasLimit ?? defaultOptions.defaultGasLimit, selection: defaultConfig.builder?.selection ?? defaultOptions.builderSelection, + boostFactor: builderBoostFactor, }, }; @@ -252,8 +263,27 @@ export class ValidatorStore { delete validatorData["graffiti"]; } - getBuilderSelection(pubkeyHex: PubkeyHex): routes.validator.BuilderSelection { - return (this.validators.get(pubkeyHex)?.builder || {}).selection ?? this.defaultProposerConfig.builder.selection; + getBuilderSelectionParams(pubkeyHex: PubkeyHex): {selection: routes.validator.BuilderSelection; boostFactor: bigint} { + const selection = + (this.validators.get(pubkeyHex)?.builder || {}).selection ?? this.defaultProposerConfig.builder.selection; + + let boostFactor; + switch (selection) { + case routes.validator.BuilderSelection.MaxProfit: + boostFactor = + (this.validators.get(pubkeyHex)?.builder || {}).boostFactor ?? this.defaultProposerConfig.builder.boostFactor; + break; + + case routes.validator.BuilderSelection.BuilderAlways: + case routes.validator.BuilderSelection.BuilderOnly: + boostFactor = MAX_BUILDER_BOOST_FACTOR; + break; + + case routes.validator.BuilderSelection.ExecutionOnly: + boostFactor = BigInt(0); + } + + return {selection, boostFactor}; } strictFeeRecipientCheck(pubkeyHex: PubkeyHex): boolean { @@ -286,6 +316,34 @@ export class ValidatorStore { delete validatorData.builder?.gasLimit; } + getBuilderBoostFactor(pubkeyHex: PubkeyHex): bigint { + const validatorData = this.validators.get(pubkeyHex); + if (validatorData === undefined) { + throw Error(`Validator pubkey ${pubkeyHex} not known`); + } + return validatorData?.builder?.boostFactor ?? this.defaultProposerConfig.builder.boostFactor; + } + + setBuilderBoostFactor(pubkeyHex: PubkeyHex, boostFactor: bigint): void { + if (boostFactor > MAX_BUILDER_BOOST_FACTOR) { + throw Error(`Invalid builderBoostFactor=${boostFactor} > MAX_BUILDER_BOOST_FACTOR`); + } + + const validatorData = this.validators.get(pubkeyHex); + if (validatorData === undefined) { + throw Error(`Validator pubkey ${pubkeyHex} not known`); + } + validatorData.builder = {...validatorData.builder, boostFactor}; + } + + deleteBuilderBoostFactor(pubkeyHex: PubkeyHex): void { + const validatorData = this.validators.get(pubkeyHex); + if (validatorData === undefined) { + throw Error(`Validator pubkey ${pubkeyHex} not known`); + } + delete validatorData.builder?.boostFactor; + } + /** Return true if `index` is active part of this validator client */ hasValidatorIndex(index: ValidatorIndex): boolean { return this.indicesService.index2pubkey.has(index); @@ -315,6 +373,10 @@ export class ValidatorStore { async addSigner(signer: Signer, valProposerConfig?: ValidatorProposerConfig): Promise { const pubkey = getSignerPubkeyHex(signer); const proposerConfig = (valProposerConfig?.proposerConfig ?? {})[pubkey]; + const builderBoostFactor = proposerConfig?.builder?.boostFactor; + if (builderBoostFactor !== undefined && builderBoostFactor > MAX_BUILDER_BOOST_FACTOR) { + throw Error(`Invalid builderBoostFactor=${builderBoostFactor} > MAX_BUILDER_BOOST_FACTOR for pubkey=${pubkey}`); + } if (!this.validators.has(pubkey)) { // Doppelganger registration must be done before adding validator to signers diff --git a/packages/validator/test/unit/services/block.test.ts b/packages/validator/test/unit/services/block.test.ts index f879017c95f1..3677cdac3a7a 100644 --- a/packages/validator/test/unit/services/block.test.ts +++ b/packages/validator/test/unit/services/block.test.ts @@ -59,6 +59,14 @@ describe("BlockDutiesService", function () { const signedBlock = ssz.phase0.SignedBeaconBlock.defaultValue(); validatorStore.signRandao.resolves(signedBlock.message.body.randaoReveal); validatorStore.signBlock.callsFake(async (_, block) => ({message: block, signature: signedBlock.signature})); + validatorStore.getBuilderSelectionParams.returns({ + selection: routes.validator.BuilderSelection.MaxProfit, + boostFactor: BigInt(100), + }); + validatorStore.getGraffiti.returns("aaaa"); + validatorStore.getFeeRecipient.returns("0x00"); + validatorStore.strictFeeRecipientCheck.returns(false); + api.validator.produceBlockV3.resolves({ response: { data: signedBlock.message, @@ -86,6 +94,24 @@ describe("BlockDutiesService", function () { [signedBlock, {broadcastValidation: routes.beacon.BroadcastValidation.consensus}], "wrong publishBlock() args" ); + + // ProduceBlockV3 is called with all correct arguments + expect(api.validator.produceBlockV3.getCall(0).args).to.deep.equal( + [ + 1, + signedBlock.message.body.randaoReveal, + "aaaa", + false, + { + feeRecipient: "0x00", + builderSelection: routes.validator.BuilderSelection.MaxProfit, + strictFeeRecipientCheck: false, + blindedLocal: false, + builderBoostFactor: BigInt(100), + }, + ], + "wrong produceBlockV3() args" + ); }); it("Should produce, sign, and publish a blinded block", async function () { From e6e6a97065200b195e6eb520351c06c773fc3da3 Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 8 Jan 2024 12:53:14 -0800 Subject: [PATCH 04/70] test: allow to pass extra args everywhere (#6249) --- packages/beacon-node/package.json | 2 +- packages/types/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 396dac8c54eb..bab5c982df42 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -79,7 +79,7 @@ "test": "yarn test:unit && yarn test:e2e", "test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/ --coverage", "test:unit:mainnet": "LODESTAR_PRESET=mainnet nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit-mainnet/**/*.test.ts'", - "test:unit": "yarn test:unit:minimal && yarn test:unit:mainnet", + "test:unit": "wrapper() { yarn test:unit:minimal $@ && yarn test:unit:mainnet $@; }; wrapper", "test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --poolOptions.threads.singleThread true --dir test/e2e", "test:sim": "mocha 'test/sim/**/*.test.ts'", "test:sim:merge-interop": "mocha 'test/sim/merge-interop.test.ts'", diff --git a/packages/types/package.json b/packages/types/package.json index 1a6f3ebf1570..29998166f422 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -63,7 +63,7 @@ "lint:fix": "yarn run lint --fix", "test:constants:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/constants/ --coverage", "test:constants:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/constants/ --coverage", - "test:unit": "yarn test:constants:minimal && yarn test:constants:mainnet && vitest --run --dir test/unit/ --coverage", + "test:unit": "wrapper() { yarn test:constants:minimal $@ && yarn test:constants:mainnet $@ && vitest --run --dir test/unit/ --coverage $@; }; wrapper", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", From 5b565326274fd2fc2f20fcecb53f816d248e0b5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 15:56:59 -0500 Subject: [PATCH 05/70] chore(deps): bump axios from 1.3.4 to 1.6.0 (#6104) Bumps [axios](https://github.com/axios/axios) from 1.3.4 to 1.6.0. - [Release notes](https://github.com/axios/axios/releases) - [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md) - [Commits](https://github.com/axios/axios/compare/v1.3.4...v1.6.0) --- updated-dependencies: - dependency-name: axios dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/yarn.lock b/yarn.lock index ccdbf1a57273..f84dcdf28754 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4533,19 +4533,10 @@ aws-sdk@^2.932.0: uuid "3.3.2" xml2js "0.4.19" -axios@^1.0.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.5.tgz#e07209b39a0d11848e3e341fa087acd71dadc542" - integrity sha512-glL/PvG/E+xCWwV8S6nCHcrfg1exGx7vxyUIivIA1iL7BIh6bePylCfVHwp6k13ao7SATxB6imau2kqY+I67kw== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -axios@^1.3.4: - version "1.3.4" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" - integrity sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ== +axios@^1.0.0, axios@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102" + integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -6324,9 +6315,9 @@ dir-glob@^3.0.1: path-type "^4.0.0" dns-over-http-resolver@^2.1.0, dns-over-http-resolver@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-2.1.2.tgz#fb478af244dd4fed5e0f798a3e6426d92730378c" - integrity sha512-Bjbf6aZjr3HMnwGslZnoW3MJVqgbTsh39EZWpikx2yLl9xEjw4eZhlOHCFhkOu89zoWaS4rqe2Go53TXW4Byiw== + version "2.1.3" + resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-2.1.3.tgz#bb7f2e10cc18d960339a6e30e21b8c1d99be7b38" + integrity sha512-zjRYFhq+CsxPAouQWzOsxNMvEN+SHisjzhX8EMxd2Y0EG3thvn6wXQgMJLnTDImkhe4jhLbOQpXtL10nALBOSA== dependencies: debug "^4.3.1" native-fetch "^4.0.2" @@ -7650,12 +7641,7 @@ fn.name@1.x.x: resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== -follow-redirects@^1.0.0: - version "1.15.1" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" - integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== - -follow-redirects@^1.15.0: +follow-redirects@^1.0.0, follow-redirects@^1.15.0: version "1.15.2" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== From 3037bf188f0aaa700673cee54719462ee045b55e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:39:42 -0500 Subject: [PATCH 06/70] chore(deps): bump @babel/traverse from 7.11.0 to 7.23.7 (#6264) Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.11.0 to 7.23.7. - [Release notes](https://github.com/babel/babel/releases) - [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md) - [Commits](https://github.com/babel/babel/commits/v7.23.7/packages/babel-traverse) --- updated-dependencies: - dependency-name: "@babel/traverse" dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 118 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 90 insertions(+), 28 deletions(-) diff --git a/yarn.lock b/yarn.lock index f84dcdf28754..dee0e2742219 100644 --- a/yarn.lock +++ b/yarn.lock @@ -235,6 +235,14 @@ dependencies: "@babel/highlight" "^7.10.4" +"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + "@babel/core@^7.7.5": version "7.11.4" resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz" @@ -257,7 +265,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.11.0", "@babel/generator@^7.11.4": +"@babel/generator@^7.11.4": version "7.15.0" resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz" integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== @@ -266,21 +274,35 @@ jsesc "^2.5.1" source-map "^0.5.0" -"@babel/helper-function-name@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz" - integrity sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ== +"@babel/generator@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== dependencies: - "@babel/helper-get-function-arity" "^7.10.4" - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" -"@babel/helper-get-function-arity@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz" - integrity sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A== +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/types" "^7.10.4" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" "@babel/helper-member-expression-to-functions@^7.10.4": version "7.11.0" @@ -341,6 +363,13 @@ dependencies: "@babel/types" "^7.11.0" +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + "@babel/helper-string-parser@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" @@ -398,11 +427,25 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.4", "@babel/parser@^7.11.0", "@babel/parser@^7.11.4": +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.10.4", "@babel/parser@^7.11.4": version "7.15.3" resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz" integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== +"@babel/parser@^7.22.15", "@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + "@babel/parser@^7.23.3": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" @@ -417,20 +460,30 @@ "@babel/parser" "^7.10.4" "@babel/types" "^7.10.4" -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.0.tgz" - integrity sha512-ZB2V+LskoWKNpMq6E5UUCrjtDUh5IOTAyIl0dTjIEoXum/iKWkoIEKIRDnUucO6f+2FzNkE0oD4RLKoPIufDtg== +"@babel/template@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.0" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.11.0" - "@babel/types" "^7.11.0" - debug "^4.1.0" + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": + version "7.23.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" + integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" globals "^11.1.0" - lodash "^4.17.19" "@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.15.0": version "7.22.5" @@ -441,6 +494,15 @@ "@babel/helper-validator-identifier" "^7.22.5" to-fast-properties "^2.0.0" +"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + "@babel/types@^7.23.3": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602" @@ -1505,7 +1567,7 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jridgewell/gen-mapping@^0.3.0": +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== @@ -5210,7 +5272,7 @@ chalk@4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^2.0.0, chalk@^2.4.1: +chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== From 2aeb0f13d4276cd4d46d69054875362d0172db58 Mon Sep 17 00:00:00 2001 From: Roman Dvorkin <121502696+rdvorkin@users.noreply.github.com> Date: Mon, 8 Jan 2024 23:59:49 +0200 Subject: [PATCH 07/70] fix: increase range for the random value of request id in prover (#6115) fix: increase range for the random value of request id Request id is currently generated by choosing random number 0-10000. This range is too small, and in some scenarios causes duplicate ids in batch. Example: call eth_call to multicall contract, aggregating balanceOf calls of many tokens. If enough tokens are queried, then many eth_getProof requests will be submitted in a batch. for a large amount of tokens there is a large chance of request id collision, failing the check in https://github.com/ChainSafe/lodestar/blob/unstable/packages/prover/src/utils/json_rpc.ts#L84 --- packages/prover/src/utils/rpc.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/prover/src/utils/rpc.ts b/packages/prover/src/utils/rpc.ts index 5feee3332c4a..fcd933675cab 100644 --- a/packages/prover/src/utils/rpc.ts +++ b/packages/prover/src/utils/rpc.ts @@ -100,6 +100,6 @@ export class ELRpc { getRequestId(): string { // TODO: Find better way to generate random id - return (Math.random() * 10000).toFixed(0); + return (Math.random() * 100000000000000000).toFixed(0); } } From 3c6420acb92e31182dee47dc05c1b924a6f76c20 Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Tue, 9 Jan 2024 05:00:44 +0700 Subject: [PATCH 08/70] feat: track prepare next epoch time (#6256) * feat: track prepare next epoch time * Update packages/beacon-node/src/metrics/metrics/lodestar.ts * Align variable name of timer with histogram naming --------- Co-authored-by: Cayman Co-authored-by: Nico Flaig --- packages/beacon-node/src/chain/prepareNextSlot.ts | 5 +++++ packages/beacon-node/src/metrics/metrics/lodestar.ts | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/beacon-node/src/chain/prepareNextSlot.ts b/packages/beacon-node/src/chain/prepareNextSlot.ts index e2bffd5bc8c6..60658b69ca98 100644 --- a/packages/beacon-node/src/chain/prepareNextSlot.ts +++ b/packages/beacon-node/src/chain/prepareNextSlot.ts @@ -97,6 +97,9 @@ export class PrepareNextSlotScheduler { headRoot, isEpochTransition, }); + const precomputeEpochTransitionTimer = isEpochTransition + ? this.metrics?.precomputeNextEpochTransition.duration.startTimer() + : null; // No need to wait for this or the clock drift // Pre Bellatrix: we only do precompute state transition for the last slot of epoch // For Bellatrix, we always do the `processSlots()` to prepare payload for the next slot @@ -133,6 +136,8 @@ export class PrepareNextSlotScheduler { prepareSlot, previousHits, }); + + precomputeEpochTransitionTimer?.(); } if (isExecutionStateType(prepareState)) { diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index ea2251b3dce5..f6b143913346 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1298,6 +1298,11 @@ export function createLodestarMetrics( name: "lodestar_precompute_next_epoch_transition_waste_total", help: "Total number of precomputing next epoch transition wasted", }), + duration: register.histogram({ + name: "lodestar_precompute_next_epoch_transition_duration_seconds", + help: "Duration of precomputeNextEpochTransition, including epoch transition and hashTreeRoot", + buckets: [1, 2, 3, 4, 8], + }), }, // reprocess attestations From 2ae8887cbab8004e40642a267e4d92329edc3018 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:21:38 -0500 Subject: [PATCH 09/70] chore(deps): bump undici from 5.22.1 to 5.28.2 (#6265) Bumps [undici](https://github.com/nodejs/undici) from 5.22.1 to 5.28.2. - [Release notes](https://github.com/nodejs/undici/releases) - [Commits](https://github.com/nodejs/undici/compare/v5.22.1...v5.28.2) --- updated-dependencies: - dependency-name: undici dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/yarn.lock b/yarn.lock index dee0e2742219..7858bf09e10f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1433,6 +1433,11 @@ dependencies: fastify-plugin "^4.0.0" +"@fastify/busboy@^2.0.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@fastify/busboy/-/busboy-2.1.0.tgz#0709e9f4cb252351c609c6e6d8d6779a8d25edff" + integrity sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA== + "@fastify/cors@^8.2.1": version "8.2.1" resolved "https://registry.yarnpkg.com/@fastify/cors/-/cors-8.2.1.tgz#dd348162bcbfb87dff4b492e2bef32d41244006a" @@ -5024,13 +5029,6 @@ bundle-name@^3.0.0: dependencies: run-applescript "^5.0.0" -busboy@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893" - integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA== - dependencies: - streamsearch "^1.1.0" - byline@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" @@ -13907,11 +13905,6 @@ streamroller@^3.1.1: debug "^4.3.4" fs-extra "^8.1.0" -streamsearch@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" - integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== - streamx@^2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" @@ -14868,11 +14861,11 @@ undici-types@~5.26.4: integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== undici@^5.12.0: - version "5.22.1" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.22.1.tgz#877d512effef2ac8be65e695f3586922e1a57d7b" - integrity sha512-Ji2IJhFXZY0x/0tVBXeQwgPlLWw13GVzpsWPQ3rV50IFMMof2I55PZZxtm4P6iNq+L5znYN9nSTAq0ZyE6lSJw== + version "5.28.2" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.2.tgz#fea200eac65fc7ecaff80a023d1a0543423b4c91" + integrity sha512-wh1pHJHnUeQV5Xa8/kyQhO7WFa8M34l026L5P/+2TYiakvGy5Rdc8jWZVyG7ieht/0WgJLEd3kcU5gKx+6GC8w== dependencies: - busboy "^1.6.0" + "@fastify/busboy" "^2.0.0" unique-filename@^1.1.1: version "1.1.1" From 23d09a2de160f66b7a7b1fc5e43aa41f09e7521e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Jan 2024 17:44:44 -0500 Subject: [PATCH 10/70] chore(deps): bump follow-redirects from 1.15.2 to 1.15.4 (#6267) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4. - [Release notes](https://github.com/follow-redirects/follow-redirects/releases) - [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4) --- updated-dependencies: - dependency-name: follow-redirects dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 7858bf09e10f..680b4ef1b8b1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7702,9 +7702,9 @@ fn.name@1.x.x: integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== follow-redirects@^1.0.0, follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + version "1.15.4" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf" + integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw== for-each@^0.3.3: version "0.3.3" From ea49409f51892dec8e1371ee1b27f38337a08d92 Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Tue, 9 Jan 2024 08:17:27 +0700 Subject: [PATCH 11/70] feat: prune BlsToExecutionChange opPool with head state (#6252) * feat: prune BlsToExecutionChange opPool with head state * fix: address PR comment --- packages/beacon-node/src/chain/chain.ts | 13 ++++--- .../beacon-node/src/chain/opPools/opPool.ts | 34 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 5e38cf23f5de..456bfef70b0a 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -904,15 +904,20 @@ export class BeaconChain implements IBeaconChain { this.logger.verbose("Fork choice justified", {epoch: cp.epoch, root: cp.rootHex}); } - private onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): void { + private async onForkChoiceFinalized(this: BeaconChain, cp: CheckpointWithHex): Promise { this.logger.verbose("Fork choice finalized", {epoch: cp.epoch, root: cp.rootHex}); this.seenBlockProposers.prune(computeStartSlotAtEpoch(cp.epoch)); // TODO: Improve using regen here - const headState = this.regen.getStateSync(this.forkChoice.getHead().stateRoot); - const finalizedState = this.regen.getCheckpointStateSync(cp); + const {blockRoot, stateRoot, slot} = this.forkChoice.getHead(); + const headState = this.regen.getStateSync(stateRoot); + const headBlock = await this.db.block.get(fromHexString(blockRoot)); + if (headBlock == null) { + throw Error(`Head block ${slot} ${headBlock} is not available in database`); + } + if (headState) { - this.opPool.pruneAll(headState, finalizedState); + this.opPool.pruneAll(headBlock, headState); } } diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index bb436319cd53..00a2c4e3cc96 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -13,8 +13,9 @@ import { MAX_BLS_TO_EXECUTION_CHANGES, BLS_WITHDRAWAL_PREFIX, MAX_ATTESTER_SLASHINGS, + ForkSeq, } from "@lodestar/params"; -import {Epoch, phase0, capella, ssz, ValidatorIndex} from "@lodestar/types"; +import {Epoch, phase0, capella, ssz, ValidatorIndex, allForks} from "@lodestar/types"; import {IBeaconDb} from "../../db/index.js"; import {SignedBLSToExecutionChangeVersioned} from "../../util/types.js"; import {BlockType} from "../interface.js"; @@ -300,11 +301,11 @@ export class OpPool { /** * Prune all types of transactions given the latest head state */ - pruneAll(headState: CachedBeaconStateAllForks, finalizedState: CachedBeaconStateAllForks | null): void { + pruneAll(headBlock: allForks.SignedBeaconBlock, headState: CachedBeaconStateAllForks): void { this.pruneAttesterSlashings(headState); this.pruneProposerSlashings(headState); this.pruneVoluntaryExits(headState); - this.pruneBlsToExecutionChanges(headState, finalizedState); + this.pruneBlsToExecutionChanges(headBlock, headState); } /** @@ -369,19 +370,28 @@ export class OpPool { } /** - * Call after finalizing - * Prune blsToExecutionChanges for validators which have been set with withdrawal - * credentials + * Prune BLS to execution changes that have been applied to the state more than 1 block ago. + * In the worse case where head block is reorged, the same BlsToExecutionChange message can be re-added + * to opPool once gossipsub seen cache TTL passes. */ private pruneBlsToExecutionChanges( - headState: CachedBeaconStateAllForks, - finalizedState: CachedBeaconStateAllForks | null + headBlock: allForks.SignedBeaconBlock, + headState: CachedBeaconStateAllForks ): void { + const {config} = headState; + const recentBlsToExecutionChanges = + config.getForkSeq(headBlock.message.slot) >= ForkSeq.capella + ? (headBlock as capella.SignedBeaconBlock).message.body.blsToExecutionChanges + : []; + + const recentBlsToExecutionChangeIndexes = new Set( + recentBlsToExecutionChanges.map((blsToExecutionChange) => blsToExecutionChange.message.validatorIndex) + ); + for (const [key, blsToExecutionChange] of this.blsToExecutionChanges.entries()) { - // TODO CAPELLA: We need the finalizedState to safely prune BlsToExecutionChanges. Finalized state may not be - // available in the cache, so it can be null. Once there's a head only prunning strategy, change - if (finalizedState !== null) { - const validator = finalizedState.validators.getReadonly(blsToExecutionChange.data.message.validatorIndex); + const {validatorIndex} = blsToExecutionChange.data.message; + if (!recentBlsToExecutionChangeIndexes.has(validatorIndex)) { + const validator = headState.validators.getReadonly(validatorIndex); if (validator.withdrawalCredentials[0] !== BLS_WITHDRAWAL_PREFIX) { this.blsToExecutionChanges.delete(key); } From 3927ffd6ea8810b2c58020859dec46c1db491c9b Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Tue, 9 Jan 2024 17:31:45 +0700 Subject: [PATCH 12/70] chore: update Grafana panels for gossip validation (#6255) --- dashboards/lodestar_networking.json | 187 +++++++++++----------------- 1 file changed, 76 insertions(+), 111 deletions(-) diff --git a/dashboards/lodestar_networking.json b/dashboards/lodestar_networking.json index 77e4be04048f..e17cabf32048 100644 --- a/dashboards/lodestar_networking.json +++ b/dashboards/lodestar_networking.json @@ -104,6 +104,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -189,6 +190,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -270,6 +272,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -351,6 +354,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -534,9 +538,10 @@ "values": false }, "showUnfilled": true, - "text": {} + "text": {}, + "valueMode": "color" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -588,9 +593,10 @@ "values": false }, "showUnfilled": true, - "text": {} + "text": {}, + "valueMode": "color" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -631,6 +637,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -711,6 +718,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -829,7 +837,7 @@ "reverse": false } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -886,6 +894,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1000,6 +1009,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1138,6 +1148,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -1223,6 +1234,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -1309,6 +1321,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineStyle": { "fill": "solid" @@ -1450,7 +1463,7 @@ "unit": "short" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -1508,6 +1521,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -1648,7 +1662,7 @@ "unit": "short" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -1760,7 +1774,7 @@ "unit": "short" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -1818,6 +1832,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 4, @@ -1931,6 +1946,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2015,6 +2031,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2141,7 +2158,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -2251,7 +2268,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -2347,7 +2364,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "pointradius": 2, "points": false, "renderer": "flot", @@ -2426,6 +2443,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2505,6 +2523,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2635,6 +2654,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2718,6 +2738,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2801,6 +2822,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2886,6 +2908,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2967,6 +2990,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3050,6 +3074,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3135,6 +3160,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3230,6 +3256,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3348,6 +3375,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3476,6 +3504,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3556,6 +3585,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3674,7 +3704,7 @@ "reverse": false } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -3717,6 +3747,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3799,86 +3830,7 @@ "tooltip": false, "viz": false }, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "unit": "percentunit" - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 154 - }, - "id": 540, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "multi", - "sort": "none" - } - }, - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "lodestar_gossip_validation_queue_current_drop_ratio", - "legendFormat": "{{topic}}", - "range": true, - "refId": "A" - } - ], - "title": "Drop Ratio", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3971,6 +3923,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4050,6 +4003,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4159,6 +4113,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4263,6 +4218,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4342,6 +4298,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4450,6 +4407,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4558,6 +4516,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4574,7 +4533,8 @@ "mode": "off" } }, - "mappings": [] + "mappings": [], + "unit": "percentunit" }, "overrides": [] }, @@ -4584,7 +4544,7 @@ "x": 0, "y": 187 }, - "id": 615, + "id": 624, "options": { "legend": { "calcs": [], @@ -4604,25 +4564,14 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(lodestar_gossip_attestation_use_head_block_state_count{caller=\"validateGossipAttestation\"}[$rate_interval])", - "legendFormat": "head_state", + "expr": "rate(lodestar_gossip_attestation_shuffling_cache_hit_count[$rate_interval])\n/\n(\n rate(lodestar_gossip_attestation_shuffling_cache_hit_count[$rate_interval])\n +\n (\n rate(lodestar_gossip_attestation_shuffling_cache_miss_count[$rate_interval])\n or\n vector(0)\n )\n)\nor\nvector(1)\n", + "instant": false, + "legendFormat": "hit_percentage", "range": true, "refId": "A" - }, - { - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "editorMode": "code", - "expr": "rate(lodestar_gossip_attestation_use_head_block_state_dialed_to_target_epoch_count{caller=\"validateGossipAttestation\"}[$rate_interval])", - "hide": false, - "legendFormat": "head_state_dialed_to_target_epoch", - "range": true, - "refId": "B" } ], - "title": "Used States", + "title": "Shuffling Cache Hit", "type": "timeseries" }, { @@ -4649,6 +4598,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4770,6 +4720,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -4886,7 +4837,7 @@ "reverse": false } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -4943,6 +4894,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5071,6 +5023,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5199,6 +5152,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5303,6 +5257,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5409,6 +5364,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5489,6 +5445,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5570,6 +5527,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5651,6 +5609,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5732,6 +5691,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5815,6 +5775,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5898,6 +5859,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5979,6 +5941,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -6060,6 +6023,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -6141,6 +6105,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -6199,7 +6164,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" From 55bc136944b841d45b4d76d6f5dafff0a6b99c2e Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 9 Jan 2024 14:37:14 +0100 Subject: [PATCH 13/70] chore: fix block production step time panels (#6271) --- dashboards/lodestar_block_production.json | 531 +++++++++++----------- 1 file changed, 270 insertions(+), 261 deletions(-) diff --git a/dashboards/lodestar_block_production.json b/dashboards/lodestar_block_production.json index b999e47a33d4..96ab44c6a550 100644 --- a/dashboards/lodestar_block_production.json +++ b/dashboards/lodestar_block_production.json @@ -54,180 +54,206 @@ "liveNow": false, "panels": [ { - "type": "timeseries", - "title": "Full block production avg time with steps", + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "gridPos": { + "h": 1, + "w": 24, "x": 0, - "y": 1, - "w": 12, - "h": 8 + "y": 0 }, + "id": 166, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Block Production", + "type": "row" + }, + { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 30, + "gradientMode": "opacity", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 1 + }, "id": 546, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, "targets": [ { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "refId": "proposerSlashing", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"proposerSlashing\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"proposerSlashing\"}[$rate_interval])", - "range": true, - "instant": false, - "hide": false, "editorMode": "code", + "exemplar": false, + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"proposerSlashing\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"proposerSlashing\"}[$rate_interval])", + "hide": false, + "instant": false, "legendFormat": "{{step}}", - "exemplar": false + "range": true, + "refId": "proposerSlashing" }, { - "refId": "attesterSlashings", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"attesterSlashings\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"attesterSlashings\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"attesterSlashings\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"attesterSlashings\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "attesterSlashings" }, { - "refId": "voluntaryExits", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"voluntaryExits\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"voluntaryExits\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"voluntaryExits\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"voluntaryExits\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "voluntaryExits" }, { - "refId": "blsToExecutionChanges", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"blsToExecutionChanges\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"blsToExecutionChanges\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"blsToExecutionChanges\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"blsToExecutionChanges\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "blsToExecutionChanges" }, { - "refId": "attestations", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"attestations\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"attestations\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"attestations\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"attestations\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "attestations" }, { - "refId": "eth1DataAndDeposits", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"eth1DataAndDeposits\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"eth1DataAndDeposits\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"eth1DataAndDeposits\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"eth1DataAndDeposits\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "eth1DataAndDeposits" }, { - "refId": "syncAggregate", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"syncAggregate\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"syncAggregate\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"syncAggregate\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"syncAggregate\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "syncAggregate" }, { - "refId": "executionPayload", - "expr": "rate(beacon_block_production_execution_steps_seconds{step=\"executionPayload\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds{step=\"executionPayload\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_execution_steps_seconds_sum{step=\"executionPayload\"}[$rate_interval])\n/\nrate(beacon_block_production_execution_steps_seconds_count{step=\"executionPayload\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "executionPayload" } ], - "options": { - "tooltip": { - "mode": "multi", - "sort": "none" - }, - "legend": { - "showLegend": true, - "displayMode": "list", - "placement": "bottom", - "calcs": [] - } - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "lineInterpolation": "linear", - "barAlignment": 0, - "lineWidth": 1, - "fillOpacity": 30, - "gradientMode": "opacity", - "spanNulls": false, - "insertNulls": false, - "showPoints": "auto", - "pointSize": 5, - "stacking": { - "mode": "normal", - "group": "A" - }, - "axisPlacement": "auto", - "axisLabel": "", - "axisColorMode": "text", - "scaleDistribution": { - "type": "linear" - }, - "axisCenteredZero": false, - "hideFrom": { - "tooltip": false, - "viz": false, - "legend": false - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "color": { - "mode": "palette-classic" - }, - "mappings": [], - "unit": "s" - }, - "overrides": [] - }, - "transformations": [] + "title": "Full block production avg time with steps", + "transformations": [], + "type": "timeseries" }, { "datasource": { @@ -236,62 +262,62 @@ }, "fieldConfig": { "defaults": { + "color": { + "mode": "palette-classic" + }, "custom": { - "drawStyle": "line", - "lineInterpolation": "linear", + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", "barAlignment": 0, - "lineWidth": 1, + "drawStyle": "line", "fillOpacity": 30, "gradientMode": "opacity", - "spanNulls": false, + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, "insertNulls": false, - "showPoints": "auto", + "lineInterpolation": "linear", + "lineWidth": 1, "pointSize": 5, - "stacking": { - "mode": "normal", - "group": "A" - }, - "axisPlacement": "auto", - "axisLabel": "", - "axisColorMode": "text", "scaleDistribution": { "type": "linear" }, - "axisCenteredZero": false, - "hideFrom": { - "tooltip": false, - "viz": false, - "legend": false + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" }, "thresholdsStyle": { "mode": "off" } }, - "color": { - "mode": "palette-classic" - }, "mappings": [], "unit": "s" }, "overrides": [] }, "gridPos": { - "x": 12, - "y": 1, + "h": 8, "w": 12, - "h": 8 + "x": 12, + "y": 1 }, "id": 547, "options": { - "tooltip": { - "mode": "multi", - "sort": "none" - }, "legend": { - "showLegend": true, + "calcs": [], "displayMode": "list", "placement": "bottom", - "calcs": [] + "showLegend": true + }, + "tooltip": { + "mode": "multi", + "sort": "none" } }, "targets": [ @@ -300,136 +326,110 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "refId": "proposerSlashing", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"proposerSlashing\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"proposerSlashing\"}[$rate_interval])", - "range": true, - "instant": false, - "hide": false, "editorMode": "code", + "exemplar": false, + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"proposerSlashing\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"proposerSlashing\"}[$rate_interval])", + "hide": false, + "instant": false, "legendFormat": "{{step}}", - "exemplar": false - }, - { - "refId": "attesterSlashings", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"attesterSlashings\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"attesterSlashings\"}[$rate_interval])", "range": true, - "instant": false, - "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" - }, - "hide": false, - "editorMode": "code", - "legendFormat": "{{step}}" + "refId": "proposerSlashing" }, { - "refId": "voluntaryExits", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"voluntaryExits\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"voluntaryExits\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"attesterSlashings\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"attesterSlashings\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "attesterSlashings" }, { - "refId": "blsToExecutionChanges", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"blsToExecutionChanges\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"blsToExecutionChanges\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"voluntaryExits\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"voluntaryExits\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "voluntaryExits" }, { - "refId": "attestations", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"attestations\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"attestations\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"blsToExecutionChanges\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"blsToExecutionChanges\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "blsToExecutionChanges" }, { - "refId": "eth1DataAndDeposits", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"eth1DataAndDeposits\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"eth1DataAndDeposits\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"attestations\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"attestations\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "attestations" }, { - "refId": "syncAggregate", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"syncAggregate\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"syncAggregate\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"eth1DataAndDeposits\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"eth1DataAndDeposits\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "eth1DataAndDeposits" }, { - "refId": "executionPayload", - "expr": "rate(beacon_block_production_builder_steps_seconds{step=\"executionPayload\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds{step=\"executionPayload\"}[$rate_interval])", - "range": true, - "instant": false, "datasource": { - "uid": "${DS_PROMETHEUS}", - "type": "prometheus" + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" }, - "hide": false, "editorMode": "code", - "legendFormat": "{{step}}" - } - ], - "title": "Blinded block production avg time with steps", - "type": "timeseries", - "transformations": [] - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 166, - "panels": [], - "targets": [ + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"syncAggregate\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"syncAggregate\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "syncAggregate" + }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "refId": "A" + "editorMode": "code", + "expr": "rate(beacon_block_production_builder_steps_seconds_sum{step=\"executionPayload\"}[$rate_interval])\n/\nrate(beacon_block_production_builder_steps_seconds_count{step=\"executionPayload\"}[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "{{step}}", + "range": true, + "refId": "executionPayload" } ], - "title": "Block Production", - "type": "row" + "title": "Blinded block production avg time with steps", + "transformations": [], + "type": "timeseries" }, { "datasource": { @@ -455,6 +455,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -540,7 +541,7 @@ "h": 8, "w": 12, "x": 0, - "y": 1 + "y": 9 }, "id": 168, "options": { @@ -611,6 +612,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -636,7 +638,7 @@ "h": 8, "w": 12, "x": 12, - "y": 1 + "y": 9 }, "id": 170, "options": { @@ -657,11 +659,13 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, "expr": "rate(beacon_block_production_seconds_sum[$rate_interval])\n/\nrate(beacon_block_production_seconds_count[$rate_interval])", "format": "heatmap", "interval": "", - "legendFormat": "{{instance}} - {{source}}", + "legendFormat": "{{source}}", + "range": true, "refId": "A" } ], @@ -692,6 +696,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -716,7 +721,7 @@ "h": 8, "w": 12, "x": 0, - "y": 9 + "y": 17 }, "id": 528, "options": { @@ -780,7 +785,7 @@ "h": 8, "w": 12, "x": 12, - "y": 9 + "y": 17 }, "heatmap": {}, "hideZeroBuckets": false, @@ -826,7 +831,7 @@ "unit": "s" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -882,6 +887,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -906,7 +912,7 @@ "h": 8, "w": 12, "x": 0, - "y": 17 + "y": 25 }, "id": 511, "options": { @@ -1036,7 +1042,7 @@ "h": 8, "w": 12, "x": 12, - "y": 17 + "y": 25 }, "hiddenSeries": false, "id": 378, @@ -1056,7 +1062,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "pointradius": 0.5, "points": true, "renderer": "flot", @@ -1131,7 +1137,7 @@ "h": 8, "w": 12, "x": 0, - "y": 25 + "y": 33 }, "hiddenSeries": false, "id": 376, @@ -1153,7 +1159,7 @@ "alertThreshold": true }, "percentage": false, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "pointradius": 0.5, "points": true, "renderer": "flot", @@ -1233,6 +1239,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1257,7 +1264,7 @@ "h": 8, "w": 12, "x": 12, - "y": 25 + "y": 33 }, "id": 532, "options": { @@ -1334,6 +1341,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1358,7 +1366,7 @@ "h": 7, "w": 12, "x": 0, - "y": 33 + "y": 41 }, "id": 531, "options": { @@ -1441,6 +1449,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1465,7 +1474,7 @@ "h": 7, "w": 12, "x": 12, - "y": 33 + "y": 41 }, "id": 534, "options": { @@ -1516,7 +1525,7 @@ "h": 6, "w": 12, "x": 0, - "y": 40 + "y": 48 }, "id": 535, "options": { @@ -1620,7 +1629,7 @@ "h": 8, "w": 12, "x": 12, - "y": 40 + "y": 48 }, "id": 537, "options": { @@ -1669,7 +1678,7 @@ "h": 1, "w": 24, "x": 0, - "y": 48 + "y": 56 }, "id": 541, "panels": [], @@ -1700,7 +1709,7 @@ "h": 8, "w": 12, "x": 0, - "y": 49 + "y": 57 }, "id": 543, "options": { @@ -1778,7 +1787,7 @@ "h": 8, "w": 12, "x": 12, - "y": 49 + "y": 57 }, "id": 545, "options": { @@ -1880,7 +1889,7 @@ "h": 8, "w": 12, "x": 0, - "y": 57 + "y": 65 }, "id": 539, "options": { @@ -1925,7 +1934,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" From 0f377dd75102f82da4612ff267ed751e63b6b210 Mon Sep 17 00:00:00 2001 From: g11tech Date: Tue, 9 Jan 2024 19:57:22 +0530 Subject: [PATCH 14/70] feat: reject builder blocks if engine indicates censorship (#6258) * feat: reject builder blocks if engine indicates censorship * apply feeback * fix tests * small refac and test fixes and selection test extenstion for override combinations * make typing tighter for blindedblock * apply feedbac * Fix typo --------- Co-authored-by: Nico Flaig --- .../src/api/impl/validator/index.ts | 35 ++++++++++--- packages/beacon-node/src/chain/chain.ts | 51 ++++++++++++------- packages/beacon-node/src/chain/interface.ts | 17 ++++--- .../chain/produceBlock/produceBlockBody.ts | 16 ++++-- .../beacon-node/src/execution/engine/http.ts | 7 ++- .../src/execution/engine/interface.ts | 7 ++- .../beacon-node/src/execution/engine/types.ts | 14 ++++- .../api/impl/validator/produceBlockV2.test.ts | 6 ++- .../api/impl/validator/produceBlockV3.test.ts | 44 +++++++++++----- 9 files changed, 143 insertions(+), 54 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 9f98c606d525..839c1df7c463 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -353,7 +353,7 @@ export function getValidatorApi({ strictFeeRecipientCheck, skipHeadChecksAndUpdate, }: Omit & {skipHeadChecksAndUpdate?: boolean} = {} - ): Promise { + ): Promise { const source = ProducedBlockSource.engine; metrics?.blockProductionRequests.inc({source}); @@ -371,7 +371,7 @@ export function getValidatorApi({ let timer; try { timer = metrics?.blockProductionTime.startTimer(); - const {block, executionPayloadValue, consensusBlockValue} = await chain.produceBlock({ + const {block, executionPayloadValue, consensusBlockValue, shouldOverrideBuilder} = await chain.produceBlock({ slot, randaoReveal, graffiti: toGraffitiBuffer(graffiti || ""), @@ -408,9 +408,10 @@ export function getValidatorApi({ version, executionPayloadValue, consensusBlockValue, + shouldOverrideBuilder, }; } else { - return {data: block, version, executionPayloadValue, consensusBlockValue}; + return {data: block, version, executionPayloadValue, consensusBlockValue, shouldOverrideBuilder}; } } finally { if (timer) timer({source}); @@ -504,7 +505,10 @@ export function getValidatorApi({ // reference index of promises in the race const promisesOrder = [ProducedBlockSource.builder, ProducedBlockSource.engine]; [blindedBlock, fullBlock] = await racePromisesWithCutoff< - routes.validator.ProduceBlockOrContentsRes | routes.validator.ProduceBlindedBlockRes | null + | ((routes.validator.ProduceBlockOrContentsRes | routes.validator.ProduceBlindedBlockRes) & { + shouldOverrideBuilder?: boolean; + }) + | null >( [blindedBlockPromise, fullBlockPromise], BLOCK_PRODUCTION_RACE_CUTOFF_MS, @@ -552,8 +556,20 @@ export function getValidatorApi({ const blockValueEngine = enginePayloadValue + gweiToWei(consensusBlockValueEngine); // Total block value is in wei let executionPayloadSource: ProducedBlockSource | null = null; + const shouldOverrideBuilder = fullBlock?.shouldOverrideBuilder ?? false; - if (fullBlock && blindedBlock) { + // handle the builder override case separately + if (shouldOverrideBuilder === true) { + executionPayloadSource = ProducedBlockSource.engine; + logger.info("Selected engine block as censorship suspected in builder blocks", { + // winston logger doesn't like bigint + enginePayloadValue: `${enginePayloadValue}`, + consensusBlockValueEngine: `${consensusBlockValueEngine}`, + blockValueEngine: `${blockValueEngine}`, + shouldOverrideBuilder, + slot, + }); + } else if (fullBlock && blindedBlock) { switch (builderSelection) { case routes.validator.BuilderSelection.MaxProfit: { if ( @@ -579,7 +595,7 @@ export function getValidatorApi({ executionPayloadSource = ProducedBlockSource.builder; } } - logger.verbose(`Selected executionPayloadSource=${executionPayloadSource} block`, { + logger.info(`Selected executionPayloadSource=${executionPayloadSource} block`, { builderSelection, // winston logger doesn't like bigint builderBoostFactor: `${builderBoostFactor}`, @@ -589,24 +605,27 @@ export function getValidatorApi({ consensusBlockValueBuilder: `${consensusBlockValueBuilder}`, blockValueEngine: `${blockValueEngine}`, blockValueBuilder: `${blockValueBuilder}`, + shouldOverrideBuilder, slot, }); } else if (fullBlock && !blindedBlock) { executionPayloadSource = ProducedBlockSource.engine; - logger.verbose("Selected engine block: no builder block produced", { + logger.info("Selected engine block: no builder block produced", { // winston logger doesn't like bigint enginePayloadValue: `${enginePayloadValue}`, consensusBlockValueEngine: `${consensusBlockValueEngine}`, blockValueEngine: `${blockValueEngine}`, + shouldOverrideBuilder, slot, }); } else if (blindedBlock && !fullBlock) { executionPayloadSource = ProducedBlockSource.builder; - logger.verbose("Selected builder block: no engine block produced", { + logger.info("Selected builder block: no engine block produced", { // winston logger doesn't like bigint builderPayloadValue: `${builderPayloadValue}`, consensusBlockValueBuilder: `${consensusBlockValueBuilder}`, blockValueBuilder: `${blockValueBuilder}`, + shouldOverrideBuilder, slot, }); } diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 456bfef70b0a..ac2f97128c16 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -470,22 +470,32 @@ export class BeaconChain implements IBeaconChain { return data && {block: data, executionOptimistic: false}; } - produceBlock( - blockAttributes: BlockAttributes - ): Promise<{block: allForks.BeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei}> { + produceBlock(blockAttributes: BlockAttributes): Promise<{ + block: allForks.BeaconBlock; + executionPayloadValue: Wei; + consensusBlockValue: Gwei; + shouldOverrideBuilder?: boolean; + }> { return this.produceBlockWrapper(BlockType.Full, blockAttributes); } - produceBlindedBlock( - blockAttributes: BlockAttributes - ): Promise<{block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei}> { + produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{ + block: allForks.BlindedBeaconBlock; + executionPayloadValue: Wei; + consensusBlockValue: Gwei; + }> { return this.produceBlockWrapper(BlockType.Blinded, blockAttributes); } async produceBlockWrapper( blockType: T, {randaoReveal, graffiti, slot, feeRecipient}: BlockAttributes - ): Promise<{block: AssembledBlockType; executionPayloadValue: Wei; consensusBlockValue: Gwei}> { + ): Promise<{ + block: AssembledBlockType; + executionPayloadValue: Wei; + consensusBlockValue: Gwei; + shouldOverrideBuilder?: boolean; + }> { const head = this.forkChoice.getHead(); const state = await this.regen.getBlockSlotState( head.blockRoot, @@ -497,16 +507,21 @@ export class BeaconChain implements IBeaconChain { const proposerIndex = state.epochCtx.getBeaconProposer(slot); const proposerPubKey = state.epochCtx.index2pubkey[proposerIndex].toBytes(); - const {body, blobs, executionPayloadValue} = await produceBlockBody.call(this, blockType, state, { - randaoReveal, - graffiti, - slot, - feeRecipient, - parentSlot: slot - 1, - parentBlockRoot, - proposerIndex, - proposerPubKey, - }); + const {body, blobs, executionPayloadValue, shouldOverrideBuilder} = await produceBlockBody.call( + this, + blockType, + state, + { + randaoReveal, + graffiti, + slot, + feeRecipient, + parentSlot: slot - 1, + parentBlockRoot, + proposerIndex, + proposerPubKey, + } + ); // The hashtree root computed here for debug log will get cached and hence won't introduce additional delays const bodyRoot = @@ -557,7 +572,7 @@ export class BeaconChain implements IBeaconChain { this.metrics?.blockProductionCaches.producedContentsCache.set(this.producedContentsCache.size); } - return {block, executionPayloadValue, consensusBlockValue: proposerReward}; + return {block, executionPayloadValue, consensusBlockValue: proposerReward, shouldOverrideBuilder}; } /** diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 880a5e86071a..a2f7fba34093 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -154,12 +154,17 @@ export interface IBeaconChain { getContents(beaconBlock: deneb.BeaconBlock): deneb.Contents; - produceBlock( - blockAttributes: BlockAttributes - ): Promise<{block: allForks.BeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei}>; - produceBlindedBlock( - blockAttributes: BlockAttributes - ): Promise<{block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei}>; + produceBlock(blockAttributes: BlockAttributes): Promise<{ + block: allForks.BeaconBlock; + executionPayloadValue: Wei; + consensusBlockValue: Gwei; + shouldOverrideBuilder?: boolean; + }>; + produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{ + block: allForks.BlindedBeaconBlock; + executionPayloadValue: Wei; + consensusBlockValue: Gwei; + }>; /** Process a block until complete */ processBlock(block: BlockInput, opts?: ImportBlockOpts): Promise; diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 3c2bec223eca..0b6ff7b1316b 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -109,12 +109,20 @@ export async function produceBlockBody( proposerIndex: ValidatorIndex; proposerPubKey: BLSPubkey; } -): Promise<{body: AssembledBodyType; blobs: BlobsResult; executionPayloadValue: Wei}> { +): Promise<{ + body: AssembledBodyType; + blobs: BlobsResult; + executionPayloadValue: Wei; + shouldOverrideBuilder?: boolean; +}> { // Type-safe for blobs variable. Translate 'null' value into 'preDeneb' enum // TODO: Not ideal, but better than just using null. // TODO: Does not guarantee that preDeneb enum goes with a preDeneb block let blobsResult: BlobsResult; let executionPayloadValue: Wei; + // even though shouldOverrideBuilder is relevant for the engine response, for simplicity of typing + // we just return it undefined for the builder which anyway doesn't get consumed downstream + let shouldOverrideBuilder: boolean | undefined; const fork = currentState.config.getForkName(blockSlot); const logMeta: Record = { @@ -295,9 +303,11 @@ export async function produceBlockBody( const engineRes = await this.executionEngine.getPayload(fork, payloadId); const {executionPayload, blobsBundle} = engineRes; + shouldOverrideBuilder = engineRes.shouldOverrideBuilder; + (blockBody as allForks.ExecutionBlockBody).executionPayload = executionPayload; executionPayloadValue = engineRes.executionPayloadValue; - Object.assign(logMeta, {transactions: executionPayload.transactions.length}); + Object.assign(logMeta, {transactions: executionPayload.transactions.length, shouldOverrideBuilder}); const fetchedTime = Date.now() / 1000 - computeTimeAtSlot(this.config, blockSlot, this.genesisTime); this.metrics?.blockPayload.payloadFetchedTime.observe({prepType}, fetchedTime); @@ -380,7 +390,7 @@ export async function produceBlockBody( Object.assign(logMeta, {executionPayloadValue}); this.logger.verbose("Produced beacon block body", logMeta); - return {body: blockBody as AssembledBodyType, blobs: blobsResult, executionPayloadValue}; + return {body: blockBody as AssembledBodyType, blobs: blobsResult, executionPayloadValue, shouldOverrideBuilder}; } /** diff --git a/packages/beacon-node/src/execution/engine/http.ts b/packages/beacon-node/src/execution/engine/http.ts index 70df97ba1e4a..91ceabaf2770 100644 --- a/packages/beacon-node/src/execution/engine/http.ts +++ b/packages/beacon-node/src/execution/engine/http.ts @@ -363,7 +363,12 @@ export class ExecutionEngineHttp implements IExecutionEngine { async getPayload( fork: ForkName, payloadId: PayloadId - ): Promise<{executionPayload: allForks.ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle}> { + ): Promise<{ + executionPayload: allForks.ExecutionPayload; + executionPayloadValue: Wei; + blobsBundle?: BlobsBundle; + shouldOverrideBuilder?: boolean; + }> { const method = ForkSeq[fork] >= ForkSeq.deneb ? "engine_getPayloadV3" diff --git a/packages/beacon-node/src/execution/engine/interface.ts b/packages/beacon-node/src/execution/engine/interface.ts index 9a7ee3963379..e5f612fc0965 100644 --- a/packages/beacon-node/src/execution/engine/interface.ts +++ b/packages/beacon-node/src/execution/engine/interface.ts @@ -136,7 +136,12 @@ export interface IExecutionEngine { getPayload( fork: ForkName, payloadId: PayloadId - ): Promise<{executionPayload: allForks.ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle}>; + ): Promise<{ + executionPayload: allForks.ExecutionPayload; + executionPayloadValue: Wei; + blobsBundle?: BlobsBundle; + shouldOverrideBuilder?: boolean; + }>; getPayloadBodiesByHash(blockHash: DATA[]): Promise<(ExecutionPayloadBody | null)[]>; diff --git a/packages/beacon-node/src/execution/engine/types.ts b/packages/beacon-node/src/execution/engine/types.ts index 4f24480e0b96..72a0100f7a51 100644 --- a/packages/beacon-node/src/execution/engine/types.ts +++ b/packages/beacon-node/src/execution/engine/types.ts @@ -107,6 +107,7 @@ type ExecutionPayloadRpcWithValue = { // even though CL tracks this as executionPayloadValue, EL returns this as blockValue blockValue: QUANTITY; blobsBundle?: BlobsBundleRpc; + shouldOverrideBuilder?: boolean; }; type ExecutionPayloadResponse = ExecutionPayloadRpc | ExecutionPayloadRpcWithValue; @@ -207,19 +208,28 @@ export function hasPayloadValue(response: ExecutionPayloadResponse): response is export function parseExecutionPayload( fork: ForkName, response: ExecutionPayloadResponse -): {executionPayload: allForks.ExecutionPayload; executionPayloadValue: Wei; blobsBundle?: BlobsBundle} { +): { + executionPayload: allForks.ExecutionPayload; + executionPayloadValue: Wei; + blobsBundle?: BlobsBundle; + shouldOverrideBuilder?: boolean; +} { let data: ExecutionPayloadRpc; let executionPayloadValue: Wei; let blobsBundle: BlobsBundle | undefined; + let shouldOverrideBuilder: boolean; + if (hasPayloadValue(response)) { executionPayloadValue = quantityToBigint(response.blockValue); data = response.executionPayload; blobsBundle = response.blobsBundle ? parseBlobsBundle(response.blobsBundle) : undefined; + shouldOverrideBuilder = response.shouldOverrideBuilder ?? false; } else { data = response; // Just set it to zero as default executionPayloadValue = BigInt(0); blobsBundle = undefined; + shouldOverrideBuilder = false; } const executionPayload = { @@ -269,7 +279,7 @@ export function parseExecutionPayload( (executionPayload as deneb.ExecutionPayload).excessBlobGas = quantityToBigint(excessBlobGas); } - return {executionPayload, executionPayloadValue, blobsBundle}; + return {executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder}; } export function serializePayloadAttributes(data: PayloadAttributes): PayloadAttributesRpc { diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index 3e96f3b932c8..9ca426672efe 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -85,7 +85,11 @@ describe("api/validator - produceBlockV2", function () { const feeRecipient = "0xcccccccccccccccccccccccccccccccccccccccc"; const api = getValidatorApi(modules); - server.chainStub.produceBlock.mockResolvedValue({block: fullBlock, executionPayloadValue, consensusBlockValue}); + server.chainStub.produceBlock.mockResolvedValue({ + block: fullBlock, + executionPayloadValue, + consensusBlockValue, + }); // check if expectedFeeRecipient is passed to produceBlock await api.produceBlockV2(slot, randaoReveal, graffiti, {feeRecipient}); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index 83e1e7887510..3a87b709b741 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -41,23 +41,38 @@ describe("api/validator - produceBlockV3", function () { vi.clearAllMocks(); }); - const testCases: [routes.validator.BuilderSelection, number | null, number | null, number, string][] = [ - [routes.validator.BuilderSelection.MaxProfit, 1, 0, 0, "builder"], - [routes.validator.BuilderSelection.MaxProfit, 1, 2, 1, "engine"], - [routes.validator.BuilderSelection.MaxProfit, null, 0, 0, "engine"], - [routes.validator.BuilderSelection.MaxProfit, 0, null, 1, "builder"], - - [routes.validator.BuilderSelection.BuilderAlways, 1, 2, 0, "builder"], - [routes.validator.BuilderSelection.BuilderAlways, 1, 0, 1, "builder"], - [routes.validator.BuilderSelection.BuilderAlways, null, 0, 0, "engine"], - [routes.validator.BuilderSelection.BuilderAlways, 0, null, 1, "builder"], - - [routes.validator.BuilderSelection.BuilderOnly, 0, 2, 0, "builder"], - [routes.validator.BuilderSelection.ExecutionOnly, 2, 0, 1, "execution"], + const testCases: [routes.validator.BuilderSelection, number | null, number | null, number, boolean, string][] = [ + [routes.validator.BuilderSelection.MaxProfit, 1, 0, 0, false, "builder"], + [routes.validator.BuilderSelection.MaxProfit, 1, 2, 1, false, "engine"], + [routes.validator.BuilderSelection.MaxProfit, null, 0, 0, false, "engine"], + [routes.validator.BuilderSelection.MaxProfit, 0, null, 1, false, "builder"], + [routes.validator.BuilderSelection.MaxProfit, 0, null, 1, true, "builder"], + [routes.validator.BuilderSelection.MaxProfit, 1, 1, 1, true, "engine"], + [routes.validator.BuilderSelection.MaxProfit, 2, 1, 1, true, "engine"], + + [routes.validator.BuilderSelection.BuilderAlways, 1, 2, 0, false, "builder"], + [routes.validator.BuilderSelection.BuilderAlways, 1, 0, 1, false, "builder"], + [routes.validator.BuilderSelection.BuilderAlways, null, 0, 0, false, "engine"], + [routes.validator.BuilderSelection.BuilderAlways, 0, null, 1, false, "builder"], + [routes.validator.BuilderSelection.BuilderAlways, 0, 1, 1, true, "engine"], + [routes.validator.BuilderSelection.BuilderAlways, 1, 1, 1, true, "engine"], + [routes.validator.BuilderSelection.BuilderAlways, 1, null, 1, true, "builder"], + + [routes.validator.BuilderSelection.BuilderOnly, 0, 2, 0, false, "builder"], + [routes.validator.BuilderSelection.ExecutionOnly, 2, 0, 1, false, "engine"], + [routes.validator.BuilderSelection.BuilderOnly, 1, 1, 0, true, "builder"], + [routes.validator.BuilderSelection.ExecutionOnly, 1, 1, 1, true, "engine"], ]; testCases.forEach( - ([builderSelection, builderPayloadValue, enginePayloadValue, consensusBlockValue, finalSelection]) => { + ([ + builderSelection, + builderPayloadValue, + enginePayloadValue, + consensusBlockValue, + shouldOverrideBuilder, + finalSelection, + ]) => { it(`produceBlockV3 - ${finalSelection} produces block`, async () => { syncStub = server.syncStub; modules = { @@ -89,6 +104,7 @@ describe("api/validator - produceBlockV3", function () { block: fullBlock, executionPayloadValue: BigInt(enginePayloadValue), consensusBlockValue: BigInt(consensusBlockValue), + shouldOverrideBuilder, }); } else { chainStub.produceBlock.mockRejectedValue(Error("not produced")); From a63a703f11f787554eabce47d56dd672b7401954 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 9 Jan 2024 17:24:02 +0100 Subject: [PATCH 15/70] chore: migrate dashboards to latest grafana version (#6272) --- dashboards/lodestar_debug_gossipsub.json | 18 +- dashboards/lodestar_discv5.json | 8 +- dashboards/lodestar_execution_engine.json | 8 +- dashboards/lodestar_libp2p.json | 8 +- dashboards/lodestar_multinode.json | 89 +++++-- dashboards/lodestar_state_cache_regen.json | 277 ++++++++++++++++++--- dashboards/lodestar_sync.json | 9 +- dashboards/lodestar_validator_client.json | 23 +- dashboards/lodestar_vm_host.json | 8 +- 9 files changed, 380 insertions(+), 68 deletions(-) diff --git a/dashboards/lodestar_debug_gossipsub.json b/dashboards/lodestar_debug_gossipsub.json index eaed0c9842f6..d83c075de7be 100644 --- a/dashboards/lodestar_debug_gossipsub.json +++ b/dashboards/lodestar_debug_gossipsub.json @@ -103,6 +103,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -220,7 +221,7 @@ "text": {}, "textMode": "auto" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -289,7 +290,7 @@ "text": {}, "textMode": "value" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -341,7 +342,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -396,7 +397,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -451,7 +452,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -493,6 +494,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -703,6 +705,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -786,6 +789,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -957,6 +961,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -1037,6 +1042,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -8729,7 +8735,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar", diff --git a/dashboards/lodestar_discv5.json b/dashboards/lodestar_discv5.json index 02c0a3b38956..31f115936df2 100644 --- a/dashboards/lodestar_discv5.json +++ b/dashboards/lodestar_discv5.json @@ -91,6 +91,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -170,6 +171,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -251,6 +253,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -333,6 +336,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -415,6 +419,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -496,6 +501,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -2051,7 +2057,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_execution_engine.json b/dashboards/lodestar_execution_engine.json index cd72b712f9a8..2c4cadc131f1 100644 --- a/dashboards/lodestar_execution_engine.json +++ b/dashboards/lodestar_execution_engine.json @@ -103,6 +103,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -186,6 +187,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -270,6 +272,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 5, @@ -354,6 +357,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 5, @@ -438,6 +442,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 2, "pointSize": 5, @@ -522,6 +527,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -3322,7 +3328,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_libp2p.json b/dashboards/lodestar_libp2p.json index 08f500cf5a40..7c6a76ec7175 100644 --- a/dashboards/lodestar_libp2p.json +++ b/dashboards/lodestar_libp2p.json @@ -103,6 +103,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -183,6 +184,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -289,6 +291,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -368,6 +371,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -447,6 +451,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -544,6 +549,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -945,7 +951,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_multinode.json b/dashboards/lodestar_multinode.json index ac710364985b..9a8fecaf0128 100644 --- a/dashboards/lodestar_multinode.json +++ b/dashboards/lodestar_multinode.json @@ -13,7 +13,10 @@ "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -51,6 +54,10 @@ "liveNow": false, "panels": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -100,7 +107,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.3.1", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -119,12 +126,18 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -136,6 +149,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -167,10 +181,12 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ @@ -190,12 +206,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -207,6 +229,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -238,10 +261,12 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ @@ -261,12 +286,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -278,6 +309,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -310,10 +342,12 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ @@ -334,12 +368,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -351,6 +391,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -383,10 +424,12 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { - "mode": "single" + "mode": "single", + "sort": "none" } }, "targets": [ @@ -407,6 +450,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -441,7 +488,7 @@ }, "textMode": "auto" }, - "pluginVersion": "8.3.1", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -473,6 +520,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -526,6 +577,10 @@ "type": "stat" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -574,7 +629,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single" @@ -598,6 +654,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -647,7 +707,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single" @@ -672,7 +733,7 @@ } ], "refresh": "10s", - "schemaVersion": 33, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_state_cache_regen.json b/dashboards/lodestar_state_cache_regen.json index 0d1360837d7f..62b4f6fc479f 100644 --- a/dashboards/lodestar_state_cache_regen.json +++ b/dashboards/lodestar_state_cache_regen.json @@ -13,7 +13,10 @@ "list": [ { "builtIn": 1, - "datasource": "-- Grafana --", + "datasource": { + "type": "datasource", + "uid": "grafana" + }, "enable": true, "hide": true, "iconColor": "rgba(0, 211, 255, 1)", @@ -33,7 +36,6 @@ "fiscalYearStartMonth": 0, "graphTooltip": 1, "id": null, - "iteration": 1661328981106, "links": [ { "asDropdown": true, @@ -54,6 +56,10 @@ "panels": [ { "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "gridPos": { "h": 1, "w": 24, @@ -62,16 +68,31 @@ }, "id": 22, "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], "title": "stateCache and stateCheckpointCache Stats", "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -83,6 +104,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -131,7 +153,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -167,12 +190,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -184,6 +213,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -232,7 +262,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -268,12 +299,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -285,6 +322,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -316,7 +354,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -325,6 +364,10 @@ }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "exemplar": false, "expr": "lodestar_state_cache_size{}", "interval": "", @@ -336,12 +379,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -353,6 +402,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -384,7 +434,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -393,6 +444,10 @@ }, "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "exemplar": false, "expr": "lodestar_cp_state_cache_size{}", "interval": "", @@ -400,6 +455,10 @@ "refId": "A" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "exemplar": false, "expr": "lodestar_cp_state_epoch_size", "hide": false, @@ -412,12 +471,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -429,6 +494,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -460,7 +526,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -484,12 +551,18 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { "mode": "palette-classic" }, "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", "axisLabel": "", "axisPlacement": "auto", "barAlignment": 0, @@ -501,6 +574,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -532,7 +606,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -557,6 +632,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -651,7 +730,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -700,6 +780,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -794,7 +878,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -843,6 +928,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -938,7 +1027,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -987,6 +1077,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1082,7 +1176,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1132,6 +1227,10 @@ }, { "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "gridPos": { "h": 1, "w": 24, @@ -1140,10 +1239,23 @@ }, "id": 40, "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], "title": "Regen call stats", "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "description": "", "fieldConfig": { "defaults": { @@ -1193,7 +1305,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1217,6 +1330,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1265,7 +1382,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1289,6 +1407,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1338,7 +1460,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1362,6 +1485,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1411,7 +1538,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1435,6 +1563,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1486,7 +1618,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1510,6 +1643,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1561,7 +1698,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1585,6 +1723,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1636,7 +1778,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1660,6 +1803,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1711,7 +1858,8 @@ "legend": { "calcs": [], "displayMode": "list", - "placement": "bottom" + "placement": "bottom", + "showLegend": true }, "tooltip": { "mode": "single", @@ -1736,6 +1884,10 @@ }, { "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "gridPos": { "h": 1, "w": 24, @@ -1744,10 +1896,23 @@ }, "id": 54, "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], "title": "Regen queue", "type": "row" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1798,8 +1963,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -1824,6 +1990,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1874,8 +2044,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -1885,6 +2056,10 @@ "pluginVersion": "7.4.5", "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "expr": "12*rate(lodestar_regen_queue_job_time_seconds_count[$rate_interval])", "interval": "", "legendFormat": "regen_queue", @@ -1895,6 +2070,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -1945,8 +2124,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -1956,6 +2136,10 @@ "pluginVersion": "7.4.5", "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "expr": "rate(lodestar_regen_queue_dropped_jobs_total[$rate_interval])/(rate(lodestar_regen_queue_job_time_seconds_count[$rate_interval])+rate(lodestar_regen_queue_dropped_jobs_total[$rate_interval]))", "interval": "", "legendFormat": "regen_queue", @@ -1966,6 +2150,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -2016,8 +2204,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -2027,6 +2216,10 @@ "pluginVersion": "7.4.5", "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "expr": "rate(lodestar_regen_queue_job_time_seconds_sum[$rate_interval])/rate(lodestar_regen_queue_job_time_seconds_count[$rate_interval])", "interval": "", "legendFormat": "regen_queue", @@ -2037,6 +2230,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -2087,8 +2284,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -2098,6 +2296,10 @@ "pluginVersion": "7.4.5", "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "expr": "rate(lodestar_regen_queue_job_wait_time_seconds_sum[$rate_interval])/rate(lodestar_regen_queue_job_wait_time_seconds_count[$rate_interval])", "interval": "", "legendFormat": "regen_queue", @@ -2108,6 +2310,10 @@ "type": "timeseries" }, { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "fieldConfig": { "defaults": { "color": { @@ -2158,8 +2364,9 @@ "graph": {}, "legend": { "calcs": [], - "displayMode": "hidden", - "placement": "bottom" + "displayMode": "list", + "placement": "bottom", + "showLegend": false }, "tooltip": { "mode": "multi", @@ -2169,6 +2376,10 @@ "pluginVersion": "7.4.5", "targets": [ { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, "expr": "lodestar_regen_queue_length", "interval": "", "legendFormat": "regen_queue", @@ -2180,7 +2391,7 @@ } ], "refresh": "10s", - "schemaVersion": 35, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_sync.json b/dashboards/lodestar_sync.json index 1a17db6da5ff..6cc82bedde47 100644 --- a/dashboards/lodestar_sync.json +++ b/dashboards/lodestar_sync.json @@ -103,6 +103,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -197,6 +198,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineStyle": { "fill": "solid" @@ -305,6 +307,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -384,6 +387,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -463,6 +467,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -542,6 +547,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -621,6 +627,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 1, @@ -1658,7 +1665,7 @@ } ], "refresh": "10s", - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_validator_client.json b/dashboards/lodestar_validator_client.json index 35f7f3ccc458..7cc41cffdb34 100644 --- a/dashboards/lodestar_validator_client.json +++ b/dashboards/lodestar_validator_client.json @@ -84,6 +84,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -213,7 +214,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -269,7 +270,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -323,7 +324,7 @@ "text": {}, "textMode": "name" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -377,7 +378,7 @@ }, "textMode": "auto" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -430,7 +431,7 @@ }, "textMode": "auto" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -483,7 +484,7 @@ }, "textMode": "auto" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -521,7 +522,7 @@ "content": "_Validator metrics =D_", "mode": "markdown" }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "targets": [ { "datasource": { @@ -557,6 +558,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -721,6 +723,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -869,7 +872,7 @@ "unit": "s" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -983,7 +986,7 @@ "unit": "s" } }, - "pluginVersion": "9.3.2", + "pluginVersion": "10.1.1", "reverseYBuckets": false, "targets": [ { @@ -2014,7 +2017,7 @@ ], "refresh": "10s", "revision": 1, - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" diff --git a/dashboards/lodestar_vm_host.json b/dashboards/lodestar_vm_host.json index 1185f7409319..7471defd0e8e 100644 --- a/dashboards/lodestar_vm_host.json +++ b/dashboards/lodestar_vm_host.json @@ -98,6 +98,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -240,6 +241,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -352,6 +354,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -449,6 +452,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -566,6 +570,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -663,6 +668,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -5585,7 +5591,7 @@ ], "refresh": "10s", "revision": 1, - "schemaVersion": 37, + "schemaVersion": 38, "style": "dark", "tags": [ "lodestar" From 810662cbc325cf6928d7433ccc6295acb5635445 Mon Sep 17 00:00:00 2001 From: Enrico Del Fante Date: Tue, 9 Jan 2024 19:48:54 +0100 Subject: [PATCH 16/70] fix: update teku's bootnode (#6273) Update teku's bootnode --- packages/cli/src/networks/mainnet.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/src/networks/mainnet.ts b/packages/cli/src/networks/mainnet.ts index 5fa2477242ed..0972b62f7458 100644 --- a/packages/cli/src/networks/mainnet.ts +++ b/packages/cli/src/networks/mainnet.ts @@ -8,7 +8,7 @@ export const bootnodesFileUrl = export const bootEnrs = [ // Teku team's bootnodes - "enr:-KG4QMOEswP62yzDjSwWS4YEjtTZ5PO6r65CPqYBkgTTkrpaedQ8uEUo1uMALtJIvb2w_WWEVmg5yt1UAuK1ftxUU7QDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaEDfol8oLr6XJ7FsdAYE7lpJhKMls4G_v6qQOGKJUWGb_uDdGNwgiMog3VkcIIjKA", + "enr:-KG4QNTx85fjxABbSq_Rta9wy56nQ1fHK0PewJbGjLm1M4bMGx5-3Qq4ZX2-iFJ0pys_O90sVXNNOxp2E7afBsGsBrgDhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQEnfA2iXNlY3AyNTZrMaECGXWQ-rQ2KZKRH1aOW4IlPDBkY4XDphxg9pxKytFCkayDdGNwgiMog3VkcIIjKA", "enr:-KG4QF4B5WrlFcRhUU6dZETwY5ZzAXnA0vGC__L1Kdw602nDZwXSTs5RFXFIFUnbQJmhNGVU6OIX7KVrCSTODsz1tK4DhGV0aDKQu6TalgMAAAD__________4JpZIJ2NIJpcIQExNYEiXNlY3AyNTZrMaECQmM9vp7KhaXhI-nqL_R0ovULLCFSFTa9CPPSdb1zPX6DdGNwgiMog3VkcIIjKA", // Prylab team's bootnodes "enr:-Ku4QImhMc1z8yCiNJ1TyUxdcfNucje3BGwEHzodEZUan8PherEo4sF7pPHPSIB1NNuSg5fZy7qFsjmUKs2ea1Whi0EBh2F0dG5ldHOIAAAAAAAAAACEZXRoMpD1pf1CAAAAAP__________gmlkgnY0gmlwhBLf22SJc2VjcDI1NmsxoQOVphkDqal4QzPMksc5wnpuC3gvSC8AfbFOnZY_On34wIN1ZHCCIyg", From e51f495887531d676db68955b0b0bce9b2b84f84 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Jan 2024 13:49:55 -0500 Subject: [PATCH 17/70] chore(deps): bump get-func-name from 2.0.0 to 2.0.2 (#6006) Bumps [get-func-name](https://github.com/chaijs/get-func-name) from 2.0.0 to 2.0.2. - [Release notes](https://github.com/chaijs/get-func-name/releases) - [Commits](https://github.com/chaijs/get-func-name/commits/v2.0.2) --- updated-dependencies: - dependency-name: get-func-name dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/yarn.lock b/yarn.lock index 680b4ef1b8b1..6e1a1681d774 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7971,12 +7971,7 @@ get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= - -get-func-name@^2.0.2: +get-func-name@^2.0.0, get-func-name@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== From aca635428423cd2e4a9514febc28ba48ad369f1d Mon Sep 17 00:00:00 2001 From: g11tech Date: Wed, 10 Jan 2024 16:54:02 +0530 Subject: [PATCH 18/70] feat: auto use produceBlockV3 deneb+ unless specified (#6262) * feat: always use produceBlockV3 post deneb * lint * auto enable only if explicity not provided --- packages/cli/src/cmds/validator/options.ts | 3 +-- .../utils/simulation/validator_clients/lodestar.ts | 2 +- packages/validator/src/services/block.ts | 7 ++++--- packages/validator/src/services/validatorStore.ts | 2 -- packages/validator/src/validator.ts | 11 ++++------- 5 files changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index e68e04a4b884..66b356d96311 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -257,8 +257,7 @@ export const validatorOptions: CliCommandOptions = { useProduceBlockV3: { type: "boolean", - description: "Enable/disable usage of produceBlockV3 that might not be supported by all beacon clients yet", - defaultDescription: `${defaultOptions.useProduceBlockV3}`, + description: "Enable/disable usage of produceBlockV3 for block production, is auto enabled on deneb+ blocks", }, broadcastValidation: { diff --git a/packages/cli/test/utils/simulation/validator_clients/lodestar.ts b/packages/cli/test/utils/simulation/validator_clients/lodestar.ts index 7c0c9e3537b1..f7a1e808a778 100644 --- a/packages/cli/test/utils/simulation/validator_clients/lodestar.ts +++ b/packages/cli/test/utils/simulation/validator_clients/lodestar.ts @@ -39,7 +39,7 @@ export const generateLodestarValidatorNode: ValidatorNodeGenerator}; type BlockProposalOpts = { - useProduceBlockV3: boolean; + useProduceBlockV3?: boolean; broadcastValidation: routes.beacon.BroadcastValidation; blindedLocal: boolean; }; @@ -125,6 +125,7 @@ export class BlockProposingService { this.validatorStore.getBuilderSelectionParams(pubkeyHex); const feeRecipient = this.validatorStore.getFeeRecipient(pubkeyHex); const blindedLocal = this.opts.blindedLocal; + const useProduceBlockV3 = this.opts.useProduceBlockV3 ?? this.config.getForkSeq(slot) >= ForkSeq.deneb; this.logger.debug("Producing block", { ...debugLogCtx, @@ -132,12 +133,12 @@ export class BlockProposingService { builderBoostFactor, feeRecipient, strictFeeRecipientCheck, - useProduceBlockV3: this.opts.useProduceBlockV3, + useProduceBlockV3, blindedLocal, }); this.metrics?.proposerStepCallProduceBlock.observe(this.clock.secFromSlot(slot)); - const produceBlockFn = this.opts.useProduceBlockV3 ? this.produceBlockWrapper : this.produceBlockV2Wrapper; + const produceBlockFn = useProduceBlockV3 ? this.produceBlockWrapper : this.produceBlockV2Wrapper; const produceOpts = { feeRecipient, strictFeeRecipientCheck, diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index 809ca0c8a7c6..f8f29f8092f2 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -126,8 +126,6 @@ export const defaultOptions = { builderSelection: routes.validator.BuilderSelection.ExecutionOnly, builderAliasSelection: routes.validator.BuilderSelection.MaxProfit, builderBoostFactor: BigInt(100), - // turn it off by default, turn it back on once other clients support v3 api - useProduceBlockV3: false, // spec asks for gossip validation by default broadcastValidation: routes.beacon.BroadcastValidation.gossip, // should request fetching the locally produced block in blinded format diff --git a/packages/validator/src/validator.ts b/packages/validator/src/validator.ts index f28a9afbaff6..deff99ee93f0 100644 --- a/packages/validator/src/validator.ts +++ b/packages/validator/src/validator.ts @@ -209,7 +209,7 @@ export class Validator { const chainHeaderTracker = new ChainHeaderTracker(logger, api, emitter); const blockProposingService = new BlockProposingService(config, loggerVc, api, clock, validatorStore, metrics, { - useProduceBlockV3: opts.useProduceBlockV3 ?? defaultOptions.useProduceBlockV3, + useProduceBlockV3: opts.useProduceBlockV3, broadcastValidation: opts.broadcastValidation ?? defaultOptions.broadcastValidation, blindedLocal: opts.blindedLocal ?? defaultOptions.blindedLocal, }); @@ -289,18 +289,15 @@ export class Validator { await assertEqualGenesis(opts, genesis); logger.info("Verified connected beacon node and validator have the same genesisValidatorRoot"); - const { - useProduceBlockV3 = defaultOptions.useProduceBlockV3, - broadcastValidation = defaultOptions.broadcastValidation, - valProposerConfig, - } = opts; + const {useProduceBlockV3, broadcastValidation = defaultOptions.broadcastValidation, valProposerConfig} = opts; const defaultBuilderSelection = valProposerConfig?.defaultConfig.builder?.selection ?? defaultOptions.builderSelection; const strictFeeRecipientCheck = valProposerConfig?.defaultConfig.strictFeeRecipientCheck ?? false; const suggestedFeeRecipient = valProposerConfig?.defaultConfig.feeRecipient ?? defaultOptions.suggestedFeeRecipient; logger.info("Initializing validator", { - useProduceBlockV3, + // if no explicit option is provided, useProduceBlockV3 will be auto enabled on/post deneb + useProduceBlockV3: useProduceBlockV3 === undefined ? "deneb+" : useProduceBlockV3, broadcastValidation, defaultBuilderSelection, suggestedFeeRecipient, From fbc5a78fc2286c2b5f2da957719856b1f2b5dd03 Mon Sep 17 00:00:00 2001 From: Lion - dapplion <35266934+dapplion@users.noreply.github.com> Date: Wed, 10 Jan 2024 21:10:00 +0700 Subject: [PATCH 19/70] fix: update voluntary exit block inclusion filter (#6278) * Fix voluntary exit block inclusion filter * lint --------- Co-authored-by: harkamal --- .../beacon-node/src/chain/opPools/opPool.ts | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/beacon-node/src/chain/opPools/opPool.ts b/packages/beacon-node/src/chain/opPools/opPool.ts index 00a2c4e3cc96..1fdee886ff1d 100644 --- a/packages/beacon-node/src/chain/opPools/opPool.ts +++ b/packages/beacon-node/src/chain/opPools/opPool.ts @@ -180,7 +180,7 @@ export class OpPool { ] { const {config} = state; const stateEpoch = computeEpochAtSlot(state.slot); - const stateFork = config.getForkName(state.slot); + const stateFork = config.getForkSeq(state.slot); const toBeSlashedIndices = new Set(); const proposerSlashings: phase0.ProposerSlashing[] = []; @@ -249,7 +249,10 @@ export class OpPool { // Signature validation is skipped in `isValidVoluntaryExit(,,false)` since it was already validated in gossip // However we must make sure that the signature fork is the same, or it will become invalid if included through // a future fork. - stateFork === config.getForkName(computeStartSlotAtEpoch(voluntaryExit.message.epoch)) + isVoluntaryExitSignatureIncludable( + stateFork, + config.getForkSeq(computeStartSlotAtEpoch(voluntaryExit.message.epoch)) + ) ) { voluntaryExits.push(voluntaryExit); if (voluntaryExits.length >= MAX_VOLUNTARY_EXITS) { @@ -400,6 +403,19 @@ export class OpPool { } } +/** + * Returns true if a pre-validated signature is still valid to be included in a specific block's fork + */ +function isVoluntaryExitSignatureIncludable(stateFork: ForkSeq, voluntaryExitFork: ForkSeq): boolean { + if (stateFork >= ForkSeq.deneb) { + // Exists are perpetually valid https://eips.ethereum.org/EIPS/eip-7044 + return true; + } else { + // Can only include exits from the current and previous fork + return voluntaryExitFork === stateFork || voluntaryExitFork === stateFork - 1; + } +} + function isSlashableAtEpoch(validator: phase0.Validator, epoch: Epoch): boolean { return !validator.slashed && validator.activationEpoch <= epoch && epoch < validator.withdrawableEpoch; } From cb1cf63250f099c7cd76a5e94f852813e8ea65c6 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 10 Jan 2024 15:12:00 +0100 Subject: [PATCH 20/70] fix: parse --builder.boostFactor value as bigint instead of number (#6277) --- packages/cli/src/cmds/validator/handler.ts | 2 +- packages/cli/src/cmds/validator/options.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 57b00d78c706..5eca9bc741d9 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -227,7 +227,7 @@ function getProposerConfigFromArgs( selection: parseBuilderSelection( args["builder.selection"] ?? (args["builder"] ? defaultOptions.builderAliasSelection : undefined) ), - boostFactor: args["builder.boostFactor"], + boostFactor: args["builder.boostFactor"] !== undefined ? BigInt(args["builder.boostFactor"]) : undefined, }, }; diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index 66b356d96311..cddb34981ce1 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -248,7 +248,7 @@ export const validatorOptions: CliCommandOptions = { }, "builder.boostFactor": { - type: "number", + type: "string", description: "Percentage multiplier the block producing beacon node must apply to boost (>100) or dampen (<100) builder block value for selection against execution block. The multiplier is ignored if `--builder.selection` is set to anything other than `maxprofit`", defaultDescription: `${defaultOptions.builderBoostFactor}`, From 11fbea55c898135a3a76366b53d5b0ed595b6ea8 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 10 Jan 2024 15:51:02 +0100 Subject: [PATCH 21/70] fix: use bigint to calculate max builder boost factor (#6275) --- packages/validator/src/services/validatorStore.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/validator/src/services/validatorStore.ts b/packages/validator/src/services/validatorStore.ts index f8f29f8092f2..03811062c2ad 100644 --- a/packages/validator/src/services/validatorStore.ts +++ b/packages/validator/src/services/validatorStore.ts @@ -132,7 +132,7 @@ export const defaultOptions = { blindedLocal: false, }; -export const MAX_BUILDER_BOOST_FACTOR = BigInt(2 ** 64 - 1); +export const MAX_BUILDER_BOOST_FACTOR = 2n ** 64n - 1n; /** * Service that sets up and handles validator attester duties. From b95cea11e40c2c88c8098431aa207d81f12e6786 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 10 Jan 2024 17:49:51 +0100 Subject: [PATCH 22/70] chore: update url of goerli bootnodes file and genesis ssz (#6279) --- packages/cli/src/networks/goerli.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/cli/src/networks/goerli.ts b/packages/cli/src/networks/goerli.ts index b076562398a3..c58dcabae6a0 100644 --- a/packages/cli/src/networks/goerli.ts +++ b/packages/cli/src/networks/goerli.ts @@ -1,10 +1,8 @@ export {goerliChainConfig as chainConfig} from "@lodestar/config/networks"; export const depositContractDeployBlock = 4367322; -export const genesisFileUrl = - "https://raw.githubusercontent.com/eth-clients/eth2-networks/master/shared/prater/genesis.ssz"; -export const bootnodesFileUrl = - "https://raw.githubusercontent.com/eth-clients/eth2-networks/master/shared/prater/bootstrap_nodes.txt"; +export const genesisFileUrl = "https://raw.githubusercontent.com/eth-clients/goerli/main/prater/genesis.ssz"; +export const bootnodesFileUrl = "https://raw.githubusercontent.com/eth-clients/goerli/main/prater/bootstrap_nodes.txt"; export const bootEnrs = [ "enr:-LK4QH1xnjotgXwg25IDPjrqRGFnH1ScgNHA3dv1Z8xHCp4uP3N3Jjl_aYv_WIxQRdwZvSukzbwspXZ7JjpldyeVDzMCh2F0dG5ldHOIAAAAAAAAAACEZXRoMpB53wQoAAAQIP__________gmlkgnY0gmlwhIe1te-Jc2VjcDI1NmsxoQOkcGXqbCJYbcClZ3z5f6NWhX_1YPFRYRRWQpJjwSHpVIN0Y3CCIyiDdWRwgiMo", From 2f9daba434db246e84af6d6f7c4c01f440fb646d Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Wed, 10 Jan 2024 12:41:13 -0500 Subject: [PATCH 23/70] docs: update RELEASE.md to include coventional commit titles (#6281) Update RELEASE.md to include coventional commit title --- RELEASE.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 440b1a13fe82..b38a4f8562f6 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -30,7 +30,7 @@ To start a new release, one of the Lodestar developers will communicate this via - This script may alternatively be run on the checked out `HEAD`: - `git checkout 9fceb02` - `yarn release:create-rc 1.1.0` -- Open draft PR from `rc/v1.1.0` to `stable` with title `v1.1.0 release`. +- Open draft PR from `rc/v1.1.0` to `stable` with title `chore: v1.1.0 release`. #### Manual steps (for example version `v1.1.0`, commit `9fceb02`): @@ -42,7 +42,7 @@ To start a new release, one of the Lodestar developers will communicate this via - Commit changes - `git commit -am "v1.1.0"` - `git push origin rc/v1.1.0` -- Open draft PR from `rc/v1.1.0` to `stable` with title `v1.1.0 release`. +- Open draft PR from `rc/v1.1.0` to `stable` with title `chore: v1.1.0 release`. ### 2. Tag release candidate @@ -76,13 +76,13 @@ For example: After 3-5 days of testing, is performance equal to or better than l - **Yes**: Continue to the next release step - **No**: If it a small issue fixable quickly (hot-fix)? - **Yes**: Merge fix(es) to `unstable`, push the fix(es) to `rc/v1.1.0` branch, go to step 2, incrementing the rc version - - **No**: abort the release. Close the `v1.1.0 release` PR, delete the branch, and start the whole release process over. + - **No**: abort the release. Close the `chore: v1.1.0 release` PR, delete the branch, and start the whole release process over. ### 4. Merge release candidate - Ensure step 2 testing is successful and there is sufficient consensus to release `v1.1.0`. -- Approving the `v1.1.0 release` PR means a team member marks the release as safe, after personally reviewing and / or testing it. -- Merge `v1.1.0 release` PR to stable **with "merge commit"** strategy to preserve all history. +- Approving the `chore: v1.1.0 release` PR means a team member marks the release as safe, after personally reviewing and / or testing it. +- Merge `chore: v1.1.0 release` PR to stable **with "merge commit"** strategy to preserve all history. - Merge stable `stable` into `unstable` **with merge commit** strategy. Due to branch protections in `unstable` must open a PR. If there are conflicts, those must be resolved manually. Gitflow may cause changes that conflict between stable and unstable, for example due to a hotfix that is backported. If that happens, disable branch protections in unstable, merge locally fixing conflicts, run lint + tests, push, and re-enable branch protections. ### 5. Tag stable release @@ -130,7 +130,7 @@ A similar process for a stable release is used, with the three differences. - Switch to the hotfix release branch and cherrypick the inclusion(s) from the `unstable` branch to the hotfix release. - `git checkout rc/v1.1.1` - `git cherry-pick {commit}` -- Open draft PR from `rc/v1.1.1` to `stable` with the title `v1.1.1 release`. +- Open draft PR from `rc/v1.1.1` to `stable` with the title `chore: v1.1.1 release`. #### Manual steps (for example version `v1.1.1`, commit `8eb8dce`): @@ -144,7 +144,7 @@ A similar process for a stable release is used, with the three differences. - Commit changes - `git commit -am "v1.1.1"` - `git push origin rc/v1.1.1` - Open draft PR from `rc/v1.1.1` to `stable` with the title `v1.1.1 release`. + Open draft PR from `rc/v1.1.1` to `stable` with the title `chore: v1.1.1 release`. ### 2. Tag release candidate From 0b2d35a928e48d6f3ccd388f553490eabaf29619 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Thu, 11 Jan 2024 12:31:47 +0100 Subject: [PATCH 24/70] ci: disable the node debug task (#6283) * Remove downloading debug-node task * Comment the debug task --- .github/workflows/test.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 43ceee898d85..deaf19329872 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -160,8 +160,8 @@ jobs: check-latest: true cache: yarn - # Remove when finished debugging core dumps - - uses: './.github/actions/setup-debug-node' + # # Remove when finished debugging core dumps + # - uses: './.github/actions/setup-debug-node' - name: Restore build cache id: cache-primes-restore @@ -184,13 +184,14 @@ jobs: key: spec-test-data-${{ hashFiles('packages/validator/test/spec/params.ts') }} - name: Unit tests - id: unit_tests + # id: unit_tests # Rever to "yarn test:unit" when finished debugging core dumps - run: sudo sh -c "ulimit -c unlimited && /usr/bin/node-with-debug $(which yarn) test:unit" + # run: sudo sh -c "ulimit -c unlimited && /usr/bin/node-with-debug $(which yarn) test:unit" + run: yarn test:unit - # Remove when finished debugging core dumps - - uses: './.github/actions/core-dump' - if: ${{ failure() && steps.unit_tests.conclusion == 'failure' }} + # # Remove when finished debugging core dumps + # - uses: './.github/actions/core-dump' + # if: ${{ failure() && steps.unit_tests.conclusion == 'failure' }} - name: Upload coverage data run: yarn coverage From aa87c54285315e503c39d12e9e89a81c786557d3 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Thu, 11 Jan 2024 12:59:06 +0100 Subject: [PATCH 25/70] feat: produce phase0 beacon block body once (#6270) * Update the beacon block production for phase0 * Update the workflow with common body * Fix lint errors * Fix the types * Fix the log message * Fix mutation of the common block body * Fix lint formatting * Fix lint formatting --- .../src/api/impl/validator/index.ts | 29 +++- packages/beacon-node/src/chain/chain.ts | 34 +++- packages/beacon-node/src/chain/interface.ts | 11 +- .../chain/produceBlock/produceBlockBody.ts | 161 +++++++++++------- .../test/__mocks__/mockedBeaconChain.ts | 1 + .../api/impl/validator/produceBlockV3.test.ts | 16 ++ 6 files changed, 174 insertions(+), 78 deletions(-) diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index 839c1df7c463..f0f076c6c13a 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -50,7 +50,7 @@ import {RegenCaller} from "../../../chain/regen/index.js"; import {getValidatorStatus} from "../beacon/state/utils.js"; import {validateGossipFnRetryUnknownRoot} from "../../../network/processor/gossipHandlers.js"; import {SCHEDULER_LOOKAHEAD_FACTOR} from "../../../chain/prepareNextSlot.js"; -import {ChainEvent, CheckpointHex} from "../../../chain/index.js"; +import {ChainEvent, CheckpointHex, CommonBlockBody} from "../../../chain/index.js"; import {computeSubnetForCommitteesAtSlot, getPubkeysForIndices} from "./utils.js"; /** @@ -287,7 +287,11 @@ export function getValidatorApi({ // as of now fee recipient checks can not be performed because builder does not return bid recipient { skipHeadChecksAndUpdate, - }: Omit & {skipHeadChecksAndUpdate?: boolean} = {} + commonBlockBody, + }: Omit & { + skipHeadChecksAndUpdate?: boolean; + commonBlockBody?: CommonBlockBody; + } = {} ): Promise { const version = config.getForkName(slot); if (!isForkExecution(version)) { @@ -323,6 +327,7 @@ export function getValidatorApi({ slot, randaoReveal, graffiti: toGraffitiBuffer(graffiti || ""), + commonBlockBody, }); metrics?.blockProductionSuccess.inc({source}); @@ -352,7 +357,11 @@ export function getValidatorApi({ feeRecipient, strictFeeRecipientCheck, skipHeadChecksAndUpdate, - }: Omit & {skipHeadChecksAndUpdate?: boolean} = {} + commonBlockBody, + }: Omit & { + skipHeadChecksAndUpdate?: boolean; + commonBlockBody?: CommonBlockBody; + } = {} ): Promise { const source = ProducedBlockSource.engine; metrics?.blockProductionRequests.inc({source}); @@ -376,6 +385,7 @@ export function getValidatorApi({ randaoReveal, graffiti: toGraffitiBuffer(graffiti || ""), feeRecipient, + commonBlockBody, }); const version = config.getForkName(block.slot); if (strictFeeRecipientCheck && feeRecipient && isForkExecution(version)) { @@ -456,7 +466,7 @@ export function getValidatorApi({ chain.executionBuilder !== undefined && builderSelection !== routes.validator.BuilderSelection.ExecutionOnly; - logger.verbose("Assembling block with produceEngineOrBuilderBlock ", { + const loggerContext = { fork, builderSelection, slot, @@ -464,7 +474,16 @@ export function getValidatorApi({ strictFeeRecipientCheck, // winston logger doesn't like bigint builderBoostFactor: `${builderBoostFactor}`, + }; + + logger.verbose("Assembling block with produceEngineOrBuilderBlock", loggerContext); + const commonBlockBody = await chain.produceCommonBlockBody({ + slot, + randaoReveal, + graffiti: toGraffitiBuffer(graffiti || ""), }); + logger.debug("Produced common block body", loggerContext); + // Start calls for building execution and builder blocks const blindedBlockPromise = isBuilderEnabled ? // can't do fee recipient checks as builder bid doesn't return feeRecipient as of now @@ -472,6 +491,7 @@ export function getValidatorApi({ feeRecipient, // skip checking and recomputing head in these individual produce calls skipHeadChecksAndUpdate: true, + commonBlockBody, }).catch((e) => { logger.error("produceBuilderBlindedBlock failed to produce block", {slot}, e); return null; @@ -494,6 +514,7 @@ export function getValidatorApi({ strictFeeRecipientCheck, // skip checking and recomputing head in these individual produce calls skipHeadChecksAndUpdate: true, + commonBlockBody, }).catch((e) => { logger.error("produceEngineFullBlockOrContents failed to produce block", {slot}, e); return null; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index ac2f97128c16..520b20b820fc 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -44,7 +44,7 @@ import {ensureDir, writeIfNotExist} from "../util/file.js"; import {isOptimisticBlock} from "../util/forkChoice.js"; import {BlockProcessor, ImportBlockOpts} from "./blocks/index.js"; import {ChainEventEmitter, ChainEvent} from "./emitter.js"; -import {IBeaconChain, ProposerPreparationData, BlockHash, StateGetOpts} from "./interface.js"; +import {IBeaconChain, ProposerPreparationData, BlockHash, StateGetOpts, CommonBlockBody} from "./interface.js"; import {IChainOptions} from "./options.js"; import {QueuedStateRegenerator, RegenCaller} from "./regen/index.js"; import {initializeForkChoice} from "./forkChoice/index.js"; @@ -73,7 +73,7 @@ import {SeenBlockAttesters} from "./seenCache/seenBlockAttesters.js"; import {BeaconProposerCache} from "./beaconProposerCache.js"; import {CheckpointBalancesCache} from "./balancesCache.js"; import {AssembledBlockType, BlobsResultType, BlockType} from "./produceBlock/index.js"; -import {BlockAttributes, produceBlockBody} from "./produceBlock/produceBlockBody.js"; +import {BlockAttributes, produceBlockBody, produceCommonBlockBody} from "./produceBlock/produceBlockBody.js"; import {computeNewStateRoot} from "./produceBlock/computeNewStateRoot.js"; import {BlockInput} from "./blocks/types.js"; import {SeenAttestationDatas} from "./seenCache/seenAttestationData.js"; @@ -463,14 +463,35 @@ export class BeaconChain implements IBeaconChain { return {block: data, executionOptimistic: isOptimisticBlock(block)}; } // If block is not found in hot db, try cold db since there could be an archive cycle happening - // TODO: Add a lock to the archiver to have determinstic behaviour on where are blocks + // TODO: Add a lock to the archiver to have deterministic behavior on where are blocks } const data = await this.db.blockArchive.getByRoot(fromHexString(root)); return data && {block: data, executionOptimistic: false}; } - produceBlock(blockAttributes: BlockAttributes): Promise<{ + async produceCommonBlockBody(blockAttributes: BlockAttributes): Promise { + const {slot} = blockAttributes; + const head = this.forkChoice.getHead(); + const state = await this.regen.getBlockSlotState( + head.blockRoot, + slot, + {dontTransferCache: true}, + RegenCaller.produceBlock + ); + const parentBlockRoot = fromHexString(head.blockRoot); + + // TODO: To avoid breaking changes for metric define this attribute + const blockType = BlockType.Full; + + return produceCommonBlockBody.call(this, blockType, state, { + ...blockAttributes, + parentBlockRoot, + parentSlot: slot - 1, + }); + } + + produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei; @@ -479,7 +500,7 @@ export class BeaconChain implements IBeaconChain { return this.produceBlockWrapper(BlockType.Full, blockAttributes); } - produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{ + produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei; @@ -489,7 +510,7 @@ export class BeaconChain implements IBeaconChain { async produceBlockWrapper( blockType: T, - {randaoReveal, graffiti, slot, feeRecipient}: BlockAttributes + {randaoReveal, graffiti, slot, feeRecipient, commonBlockBody}: BlockAttributes & {commonBlockBody?: CommonBlockBody} ): Promise<{ block: AssembledBlockType; executionPayloadValue: Wei; @@ -520,6 +541,7 @@ export class BeaconChain implements IBeaconChain { parentBlockRoot, proposerIndex, proposerPubKey, + commonBlockBody, } ); diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index a2f7fba34093..6e932b25c50e 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -11,6 +11,8 @@ import { deneb, Wei, Gwei, + capella, + altair, } from "@lodestar/types"; import { BeaconStateAllForks, @@ -154,13 +156,14 @@ export interface IBeaconChain { getContents(beaconBlock: deneb.BeaconBlock): deneb.Contents; - produceBlock(blockAttributes: BlockAttributes): Promise<{ + produceCommonBlockBody(blockAttributes: BlockAttributes): Promise; + produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei; shouldOverrideBuilder?: boolean; }>; - produceBlindedBlock(blockAttributes: BlockAttributes): Promise<{ + produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; consensusBlockValue: Gwei; @@ -204,3 +207,7 @@ export type SSZObjectType = | "signedAggregatedAndProof" | "syncCommittee" | "contributionAndProof"; + +export type CommonBlockBody = phase0.BeaconBlockBody & + Pick & + Pick; diff --git a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts index 0b6ff7b1316b..b25b71514a71 100644 --- a/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts +++ b/packages/beacon-node/src/chain/produceBlock/produceBlockBody.ts @@ -1,8 +1,6 @@ import { Bytes32, - phase0, allForks, - altair, Root, RootHex, Slot, @@ -35,6 +33,7 @@ import {PayloadId, IExecutionEngine, IExecutionBuilder, PayloadAttributes} from import {ZERO_HASH, ZERO_HASH_HEX} from "../../constants/index.js"; import {IEth1ForBlockProduction} from "../../eth1/index.js"; import {numToQuantity} from "../../eth1/provider/utils.js"; +import {CommonBlockBody} from "../interface.js"; import {validateBlobsAndKzgCommitments} from "./validateBlobsAndKzgCommitments.js"; // Time to provide the EL to generate a payload from new payload id @@ -94,20 +93,12 @@ export async function produceBlockBody( this: BeaconChain, blockType: T, currentState: CachedBeaconStateAllForks, - { - randaoReveal, - graffiti, - slot: blockSlot, - feeRecipient: requestedFeeRecipient, - parentSlot, - parentBlockRoot, - proposerIndex, - proposerPubKey, - }: BlockAttributes & { + blockAttr: BlockAttributes & { parentSlot: Slot; parentBlockRoot: Root; proposerIndex: ValidatorIndex; proposerPubKey: BLSPubkey; + commonBlockBody?: CommonBlockBody; } ): Promise<{ body: AssembledBodyType; @@ -115,6 +106,14 @@ export async function produceBlockBody( executionPayloadValue: Wei; shouldOverrideBuilder?: boolean; }> { + const { + slot: blockSlot, + feeRecipient: requestedFeeRecipient, + parentBlockRoot, + proposerIndex, + proposerPubKey, + commonBlockBody, + } = blockAttr; // Type-safe for blobs variable. Translate 'null' value into 'preDeneb' enum // TODO: Not ideal, but better than just using null. // TODO: Does not guarantee that preDeneb enum goes with a preDeneb block @@ -131,63 +130,17 @@ export async function produceBlockBody( slot: blockSlot, }; this.logger.verbose("Producing beacon block body", logMeta); - - // TODO: - // Iterate through the naive aggregation pool and ensure all the attestations from there - // are included in the operation pool. - // for (const attestation of db.attestationPool.getAll()) { - // try { - // opPool.insertAttestation(attestation); - // } catch (e) { - // // Don't stop block production if there's an error, just create a log. - // logger.error("Attestation did not transfer to op pool", {}, e); - // } - // } - const stepsMetrics = blockType === BlockType.Full ? this.metrics?.executionBlockProductionTimeSteps : this.metrics?.builderBlockProductionTimeSteps; - const [attesterSlashings, proposerSlashings, voluntaryExits, blsToExecutionChanges] = - this.opPool.getSlashingsAndExits(currentState, blockType, this.metrics); - - const endAttestations = stepsMetrics?.startTimer(); - const attestations = this.aggregatedAttestationPool.getAttestationsForBlock(this.forkChoice, currentState); - endAttestations?.({ - step: BlockProductionStep.attestations, - }); - - const endEth1DataAndDeposits = stepsMetrics?.startTimer(); - const {eth1Data, deposits} = await this.eth1.getEth1DataAndDeposits(currentState); - endEth1DataAndDeposits?.({ - step: BlockProductionStep.eth1DataAndDeposits, - }); + const blockBody = commonBlockBody + ? Object.assign({}, commonBlockBody) + : await produceCommonBlockBody.call(this, blockType, currentState, blockAttr); - const blockBody: phase0.BeaconBlockBody = { - randaoReveal, - graffiti, - eth1Data, - proposerSlashings, - attesterSlashings, - attestations, - deposits, - voluntaryExits, - }; - - const blockEpoch = computeEpochAtSlot(blockSlot); - - const endSyncAggregate = stepsMetrics?.startTimer(); - if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) { - const syncAggregate = this.syncContributionAndProofPool.getAggregate(parentSlot, parentBlockRoot); - this.metrics?.production.producedSyncAggregateParticipants.observe( - syncAggregate.syncCommitteeBits.getTrueBitIndexes().length - ); - (blockBody as altair.BeaconBlockBody).syncAggregate = syncAggregate; - } - endSyncAggregate?.({ - step: BlockProductionStep.syncAggregate, - }); + const {attestations, deposits, voluntaryExits, attesterSlashings, proposerSlashings, blsToExecutionChanges} = + blockBody; Object.assign(logMeta, { attestations: attestations.length, @@ -317,6 +270,7 @@ export async function produceBlockBody( prepType, payloadId, fetchedTime, + executionHeadBlockHash: toHex(engineRes.executionPayload.blockHash), }); if (executionPayload.transactions.length === 0) { this.metrics?.blockPayload.emptyPayloads.inc({prepType}); @@ -373,8 +327,6 @@ export async function produceBlockBody( }); if (ForkSeq[fork] >= ForkSeq.capella) { - // TODO: blsToExecutionChanges should be passed in the produceBlock call - (blockBody as capella.BeaconBlockBody).blsToExecutionChanges = blsToExecutionChanges; Object.assign(logMeta, { blsToExecutionChanges: blsToExecutionChanges.length, }); @@ -616,4 +568,81 @@ function preparePayloadAttributes( return payloadAttributes; } -/** process_sync_committee_contributions is implemented in syncCommitteeContribution.getSyncAggregate */ +export async function produceCommonBlockBody( + this: BeaconChain, + blockType: T, + currentState: CachedBeaconStateAllForks, + { + randaoReveal, + graffiti, + slot, + parentSlot, + parentBlockRoot, + }: BlockAttributes & { + parentSlot: Slot; + parentBlockRoot: Root; + } +): Promise { + const stepsMetrics = + blockType === BlockType.Full + ? this.metrics?.executionBlockProductionTimeSteps + : this.metrics?.builderBlockProductionTimeSteps; + + const blockEpoch = computeEpochAtSlot(slot); + const fork = currentState.config.getForkName(slot); + + // TODO: + // Iterate through the naive aggregation pool and ensure all the attestations from there + // are included in the operation pool. + // for (const attestation of db.attestationPool.getAll()) { + // try { + // opPool.insertAttestation(attestation); + // } catch (e) { + // // Don't stop block production if there's an error, just create a log. + // logger.error("Attestation did not transfer to op pool", {}, e); + // } + // } + const [attesterSlashings, proposerSlashings, voluntaryExits, blsToExecutionChanges] = + this.opPool.getSlashingsAndExits(currentState, blockType, this.metrics); + + const endAttestations = stepsMetrics?.startTimer(); + const attestations = this.aggregatedAttestationPool.getAttestationsForBlock(this.forkChoice, currentState); + endAttestations?.({ + step: BlockProductionStep.attestations, + }); + + const endEth1DataAndDeposits = stepsMetrics?.startTimer(); + const {eth1Data, deposits} = await this.eth1.getEth1DataAndDeposits(currentState); + endEth1DataAndDeposits?.({ + step: BlockProductionStep.eth1DataAndDeposits, + }); + + const blockBody: Omit = { + randaoReveal, + graffiti, + eth1Data, + proposerSlashings, + attesterSlashings, + attestations, + deposits, + voluntaryExits, + }; + + if (ForkSeq[fork] >= ForkSeq.capella) { + (blockBody as CommonBlockBody).blsToExecutionChanges = blsToExecutionChanges; + } + + const endSyncAggregate = stepsMetrics?.startTimer(); + if (blockEpoch >= this.config.ALTAIR_FORK_EPOCH) { + const syncAggregate = this.syncContributionAndProofPool.getAggregate(parentSlot, parentBlockRoot); + this.metrics?.production.producedSyncAggregateParticipants.observe( + syncAggregate.syncCommitteeBits.getTrueBitIndexes().length + ); + (blockBody as CommonBlockBody).syncAggregate = syncAggregate; + } + endSyncAggregate?.({ + step: BlockProductionStep.syncAggregate, + }); + + return blockBody as CommonBlockBody; +} diff --git a/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts b/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts index 3c5dacc9c971..c72d22471ce8 100644 --- a/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts +++ b/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts @@ -79,6 +79,7 @@ vi.mock("../../src/chain/index.js", async (requireActual) => { // @ts-expect-error beaconProposerCache: new BeaconProposerCache(), shufflingCache: new ShufflingCache(), + produceCommonBlockBody: vi.fn(), produceBlock: vi.fn(), produceBlindedBlock: vi.fn(), getCanonicalBlockAtSlot: vi.fn(), diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index 3a87b709b741..f1aa2cb791df 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -9,6 +9,7 @@ import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; import {testLogger} from "../../../../utils/logger.js"; import {ApiImplTestModules, setupApiImplTestServer} from "../../../../__mocks__/apiMocks.js"; import {ExecutionBuilderHttp} from "../../../../../src/execution/builder/http.js"; +import {CommonBlockBody} from "../../../../../src/chain/interface.js"; /* eslint-disable @typescript-eslint/naming-convention */ describe("api/validator - produceBlockV3", function () { @@ -100,6 +101,21 @@ describe("api/validator - produceBlockV3", function () { const api = getValidatorApi(modules); if (enginePayloadValue !== null) { + const commonBlockBody: CommonBlockBody = { + attestations: fullBlock.body.attestations, + attesterSlashings: fullBlock.body.attesterSlashings, + deposits: fullBlock.body.deposits, + proposerSlashings: fullBlock.body.proposerSlashings, + eth1Data: fullBlock.body.eth1Data, + graffiti: fullBlock.body.graffiti, + randaoReveal: fullBlock.body.randaoReveal, + voluntaryExits: fullBlock.body.voluntaryExits, + blsToExecutionChanges: [], + syncAggregate: fullBlock.body.syncAggregate, + }; + + chainStub.produceCommonBlockBody.mockResolvedValue(commonBlockBody); + chainStub.produceBlock.mockResolvedValue({ block: fullBlock, executionPayloadValue: BigInt(enginePayloadValue), From 5e69423f2807e042990a4016f2ac1828f303b21d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rio=20Havel?= <61149543+taxmeifyoucan@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:03:56 +0100 Subject: [PATCH 26/70] fix: add Ephemery Deneb fork epoch (#6287) * Add Ephemery Deneb fork epoch * Extra new line --------- Co-authored-by: Nico Flaig --- packages/config/src/chainConfig/networks/ephemery.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/config/src/chainConfig/networks/ephemery.ts b/packages/config/src/chainConfig/networks/ephemery.ts index c338c26f2cf3..5557767550bb 100644 --- a/packages/config/src/chainConfig/networks/ephemery.ts +++ b/packages/config/src/chainConfig/networks/ephemery.ts @@ -7,7 +7,7 @@ import {chainConfig as mainnet} from "../presets/mainnet.js"; // https://github.com/ephemery-testnet/ephemery-genesis/blob/master/cl-config.yaml // Ephemery specification: -// https://github.com/taxmeifyoucan/EIPs/blob/d298cdd8eaf47a21e7770e5c6efef870587c924d/EIPS/eip-6916.md +// https://eips.ethereum.org/EIPS/eip-6916 // iteration 0, "base"-genesis const baseChainConfig: ChainConfig = { @@ -37,6 +37,7 @@ const baseChainConfig: ChainConfig = { CAPELLA_FORK_EPOCH: 0, // Deneb DENEB_FORK_VERSION: b("0x5000101b"), + DENEB_FORK_EPOCH: 5, // Deposit contract // --------------------------------------------------------------- From 02370a91e96e38e30c89dcbbb852671413f1914d Mon Sep 17 00:00:00 2001 From: Phil Ngo Date: Fri, 12 Jan 2024 12:51:18 -0500 Subject: [PATCH 27/70] v1.14.0 --- lerna.json | 2 +- packages/api/package.json | 10 +++++----- packages/beacon-node/package.json | 26 +++++++++++++------------- packages/cli/package.json | 26 +++++++++++++------------- packages/config/package.json | 6 +++--- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 +++++++------- packages/fork-choice/package.json | 12 ++++++------ packages/light-client/package.json | 14 +++++++------- packages/logger/package.json | 6 +++--- packages/params/package.json | 4 ++-- packages/prover/package.json | 18 +++++++++--------- packages/reqresp/package.json | 12 ++++++------ packages/spec-test-util/package.json | 4 ++-- packages/state-transition/package.json | 10 +++++----- packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 +++++++++--------- 19 files changed, 101 insertions(+), 101 deletions(-) diff --git a/lerna.json b/lerna.json index bb0c43fed5fe..487caa95b0a2 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.13.0", + "version": "1.14.0", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index 2dfcbc73b65c..b7708ac5aa26 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -71,10 +71,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index bab5c982df42..68ff28c7d9e2 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -119,18 +119,18 @@ "@libp2p/peer-id-factory": "^3.0.4", "@libp2p/prometheus-metrics": "^2.0.7", "@libp2p/tcp": "8.0.8", - "@lodestar/api": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/db": "^1.13.0", - "@lodestar/fork-choice": "^1.13.0", - "@lodestar/light-client": "^1.13.0", - "@lodestar/logger": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/reqresp": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", - "@lodestar/validator": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/db": "^1.14.0", + "@lodestar/fork-choice": "^1.14.0", + "@lodestar/light-client": "^1.14.0", + "@lodestar/logger": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/reqresp": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", + "@lodestar/validator": "^1.14.0", "@multiformats/multiaddr": "^12.1.3", "@types/datastore-level": "^3.0.0", "buffer-xor": "^2.0.2", diff --git a/packages/cli/package.json b/packages/cli/package.json index 047672c18855..df83d79c083c 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.13.0", + "version": "1.14.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -65,17 +65,17 @@ "@libp2p/crypto": "^2.0.4", "@libp2p/peer-id": "^3.0.2", "@libp2p/peer-id-factory": "^3.0.4", - "@lodestar/api": "^1.13.0", - "@lodestar/beacon-node": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/db": "^1.13.0", - "@lodestar/light-client": "^1.13.0", - "@lodestar/logger": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", - "@lodestar/validator": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/beacon-node": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/db": "^1.14.0", + "@lodestar/light-client": "^1.14.0", + "@lodestar/logger": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", + "@lodestar/validator": "^1.14.0", "@multiformats/multiaddr": "^12.1.3", "@types/lockfile": "^1.0.2", "bip39": "^3.1.0", @@ -96,7 +96,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.13.0", + "@lodestar/test-utils": "^1.14.0", "@types/debug": "^4.1.7", "@types/expand-tilde": "^2.0.0", "@types/got": "^9.6.12", diff --git a/packages/config/package.json b/packages/config/package.json index a12cdcb60cb5..ed79bd700cfb 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.13.0", + "version": "1.14.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,7 +65,7 @@ ], "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/params": "^1.13.0", - "@lodestar/types": "^1.13.0" + "@lodestar/params": "^1.14.0", + "@lodestar/types": "^1.14.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index 5d1fef29b6f3..1bccf368c55f 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.13.0", + "version": "1.14.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -38,13 +38,13 @@ }, "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/config": "^1.14.0", + "@lodestar/utils": "^1.14.0", "@types/levelup": "^4.3.3", "it-all": "^3.0.2", "level": "^8.0.0" }, "devDependencies": { - "@lodestar/logger": "^1.13.0" + "@lodestar/logger": "^1.14.0" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 7bbd79d02602..d3849d1b5362 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.13.0", + "version": "1.14.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/bls-keygen": "^0.3.0", - "@lodestar/api": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "source-map-support": "^0.5.21", "yargs": "^17.7.1" }, diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 54fe40063d85..b19fa976bdf4 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -39,11 +39,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0" + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index defe46d10013..3270dc14f088 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -70,12 +70,12 @@ "@chainsafe/bls": "7.1.1", "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/api": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "mitt": "^3.0.0", "strict-event-emitter-types": "^2.0.0" }, diff --git a/packages/logger/package.json b/packages/logger/package.json index 6807fca853a6..e8cc7d5f9622 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.13.0", + "@lodestar/utils": "^1.14.0", "winston": "^3.8.2", "winston-daily-rotate-file": "^4.7.1", "winston-transport": "^4.5.0" }, "devDependencies": { "@chainsafe/threads": "^1.11.1", - "@lodestar/test-utils": "^1.13.0", + "@lodestar/test-utils": "^1.14.0", "@types/triple-beam": "^1.3.2", "rimraf": "^4.4.1", "triple-beam": "^1.3.0" diff --git a/packages/params/package.json b/packages/params/package.json index c65cc4570ffc..7861da84424d 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.13.0", + "version": "1.14.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -52,7 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test": "yarn run check-types", + "test": "yarn run check-types", "test:unit": "vitest --run --dir test/unit/ --coverage", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/prover/package.json b/packages/prover/package.json index b5b72c591771..80a992118202 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -72,13 +72,13 @@ "@ethereumjs/tx": "^4.1.2", "@ethereumjs/util": "^8.0.6", "@ethereumjs/vm": "^6.4.2", - "@lodestar/api": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/light-client": "^1.13.0", - "@lodestar/logger": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/light-client": "^1.14.0", + "@lodestar/logger": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "ethereum-cryptography": "^1.2.0", "find-up": "^6.3.0", "http-proxy": "^1.18.1", @@ -87,7 +87,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.13.0", + "@lodestar/test-utils": "^1.14.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index e4ca57dfc3dd..9d81d082d087 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -56,9 +56,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^0.1.2", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/utils": "^1.14.0", "it-all": "^3.0.2", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -67,8 +67,8 @@ "uint8arraylist": "^2.4.3" }, "devDependencies": { - "@lodestar/logger": "^1.13.0", - "@lodestar/types": "^1.13.0", + "@lodestar/logger": "^1.14.0", + "@lodestar/types": "^1.14.0", "libp2p": "0.46.12" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 5fc59cd76e12..c267e65133c0 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/spec-test-util", - "version": "1.13.0", + "version": "1.14.0", "description": "Spec test suite generator from yaml test files", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -45,7 +45,7 @@ "blockchain" ], "dependencies": { - "@lodestar/utils": "^1.13.0", + "@lodestar/utils": "^1.14.0", "async-retry": "^1.3.3", "axios": "^1.3.4", "chai": "^4.3.7", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index f0f2f150f673..2b49b94179ca 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -63,10 +63,10 @@ "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/config": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "bigint-buffer": "^1.1.5", "buffer-xor": "^2.0.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 6f6152375e1f..61914ba91676 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@lodestar/test-utils", "private": true, - "version": "1.13.0", + "version": "1.14.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -63,8 +63,8 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/bls-keystore": "^3.0.0", - "@lodestar/params": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/params": "^1.14.0", + "@lodestar/utils": "^1.14.0", "axios": "^1.3.4", "chai": "^4.3.7", "mocha": "^10.2.0", diff --git a/packages/types/package.json b/packages/types/package.json index 29998166f422..9d8859ecaf05 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": { ".": { @@ -73,7 +73,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/params": "^1.13.0" + "@lodestar/params": "^1.14.0" }, "keywords": [ "ethereum", diff --git a/packages/utils/package.json b/packages/utils/package.json index 8137cd496a0a..9f526582483e 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.13.0", + "version": "1.14.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index ecd15116169a..54d332455114 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.13.0", + "version": "1.14.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -50,18 +50,18 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/api": "^1.13.0", - "@lodestar/config": "^1.13.0", - "@lodestar/db": "^1.13.0", - "@lodestar/params": "^1.13.0", - "@lodestar/state-transition": "^1.13.0", - "@lodestar/types": "^1.13.0", - "@lodestar/utils": "^1.13.0", + "@lodestar/api": "^1.14.0", + "@lodestar/config": "^1.14.0", + "@lodestar/db": "^1.14.0", + "@lodestar/params": "^1.14.0", + "@lodestar/state-transition": "^1.14.0", + "@lodestar/types": "^1.14.0", + "@lodestar/utils": "^1.14.0", "bigint-buffer": "^1.1.5", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.13.0", + "@lodestar/test-utils": "^1.14.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From 098d35aa0f5afc351a131b8a1e88485907985226 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Sat, 13 Jan 2024 06:50:39 +0100 Subject: [PATCH 28/70] docs: update networking page (#6289) * docs: update networking page * Update wordlist * Update port description * must instead of should * Apply feedback Co-authored-by: Matthew Keil * Why on startup, who cares * Add log exmaple --------- Co-authored-by: Matthew Keil --- .wordlist.txt | 1 + docs/pages/beacon-management/networking.md | 36 +++++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/.wordlist.txt b/.wordlist.txt index 42510b175a07..634ab95ab62e 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -122,6 +122,7 @@ envs ephemery flamegraph flamegraphs +getNetworkIdentity gnosis goerli heapdump diff --git a/docs/pages/beacon-management/networking.md b/docs/pages/beacon-management/networking.md index 993b1cdfda26..1afd80c9cea3 100644 --- a/docs/pages/beacon-management/networking.md +++ b/docs/pages/beacon-management/networking.md @@ -1,6 +1,6 @@ # Networking -Starting up Lodestar will automatically connect it to peers on the network. Peers are found through the discv5 protocol and once peers are established communications happen via gossipsub over libp2p. While not necessary, having a basic understanding of how the various protocols and transport work will help with debugging and troubleshooting as some of the more common challenges come up with [firewalls](#firewall-management) and [NAT traversal](#nat-traversal). +Lodestar will automatically connect to peers on the network. Peers are found through the discv5 protocol and once peers are established communications happen via gossipsub over libp2p. While not necessary, having a basic understanding of how the various protocols and transports work will help with debugging and troubleshooting as some of the more common challenges come up with [firewalls](#firewall-management) and [NAT traversal](#nat-traversal). ## Networking Flags @@ -42,6 +42,16 @@ The primary purpose of ENRs is to facilitate node discovery and connectivity in Note that bootnodes are announced via ENR. +Lodestar prints out its own ENR on startup, the logs will show something similar to the following + +``` +info: discv5 worker started peerId=16Uiu...t9LQ3, initialENR=enr:-Iu4QGE...WRwgiMo, bindAddr4=/ip4/0.0.0.0/udp/9000 +``` + +Alternatively, the ENR can also be retrieved from the beacon node API by querying the [getNetworkIdentity](https://ethereum.github.io/beacon-APIs/#/Node/getNetworkIdentity) endpoint. + +[ENR Viewer](https://enr-viewer.com/) provides a simple and convenient option to decode and inspect ENRs. + ## Peer Communication (gossipsub and ReqResp) Gossipsub and ReqResp are the two mechanisms that beacon nodes use to exchange chain data. Gossipsub is used disseminate the most recent relevant data proactively throughout the network. ReqResp is used to directly ask specific peers for specific information (eg: during syncing). @@ -68,22 +78,20 @@ Libp2p operates at the lower levels of the OSI model, particularly at the Transp If your setup is behind a firewall there are a few ports that will need to be opened to allow for P2P discovery and communication. There are also some ports that need to be protected to prevent unwanted access or DDOS attacks on your node. -Ports that should be opened: +Ports that must be opened: -- 30303/TCP+UDP - Execution layer p2p communication port -- 9000/TCP+UDP - Beacon Node P2P communication port -- 9090/TCP - Lodestar IPv6 P2P communication port -- 13000/TCP - Prysm P2P communication port -- 12000/UDP - Prysm P2P communication port +- 30303/TCP+UDP - Execution layer P2P communication port +- 9000/TCP+UDP - Beacon node IPv4 P2P communication port +- 9090/TCP+UDP - Beacon node IPv6 P2P communication port -Ports that should be inbound protected: +Ports that must be protected: -- 9596/TCP - Lodestar Beacon-Node JSON RPC api calls -- 5062/TCP - Lodestar validator key manager api calls -- 18550/TCP - Lodestar MEV Boost/Builder port -- 8008/TCP - Lodestar Metrics -- 5064/TCP - Validator Metrics -- 8545/TCP - Execution client JSON RPC port api calls +- 9596/TCP - Beacon node REST API port +- 5062/TCP - Validator key manager API port +- 18550/TCP - MEV-Boost/Builder port +- 8008/TCP - Beacon node metrics port +- 5064/TCP - Validator metrics port +- 8545/TCP - Execution client JSON RPC port - 8551/TCP - Execution engine port for Lodestar to communicate with the execution client ## NAT Traversal From 758ed32eee0cbff063145f46062aeac8a6e7859d Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 15 Jan 2024 16:16:11 +0100 Subject: [PATCH 29/70] fix: correct error message if produceBlindedBlock request fails (#6299) --- packages/validator/src/services/block.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index b17b7519b2cf..dec08bf9967c 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -265,7 +265,7 @@ export class BlockProposingService { } else { Object.assign(debugLogCtx, {api: "produceBlindedBlock"}); const res = await this.api.validator.produceBlindedBlock(slot, randaoReveal, graffiti); - ApiError.assert(res, "Failed to produce block: validator.produceBlockV2"); + ApiError.assert(res, "Failed to produce block: validator.produceBlindedBlock"); const {response} = res; const executionPayloadSource = ProducedBlockSource.builder; From edd83cbaf5410dd066e4748ddce9359a5c33d0d0 Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 15 Jan 2024 07:19:46 -0800 Subject: [PATCH 30/70] docs: fix incorrect light-client example (#6297) --- packages/light-client/README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/light-client/README.md b/packages/light-client/README.md index cac2f71c6880..759576334489 100644 --- a/packages/light-client/README.md +++ b/packages/light-client/README.md @@ -51,18 +51,20 @@ lodestar lightclient \ For this example we will assume there is a running beacon node at `https://beacon-node.your-domain.com` ```ts -import {Api} from "@lodestar/api/beacon"; +import type {Api} from "@lodestar/api/beacon"; import {ApiError} from "@lodestar/api"; -import {Bytes32} from "@lodestar/types"; +import type {Bytes32} from "@lodestar/types"; import {createChainForkConfig} from "@lodestar/config"; import {networksChainConfig} from "@lodestar/config/networks"; import { - GenesisData, + type GenesisData, Lightclient, LightclientEvent, - RunStatusCode, - getLcLoggerConsole -} from `@lodestar/lightclient`; + RunStatusCode +} from "@lodestar/light-client"; +import {getClient} from "@lodestar/api"; +import {LightClientRestTransport} from "@lodestar/light-client/transport"; +import {getLcLoggerConsole} from "@lodestar/light-client/utils"; async function getGenesisData(api: Pick): Promise { const res = await api.beacon.getGenesis(); @@ -104,7 +106,7 @@ const lightclient = await Lightclient.initializeFromCheckpointRoot({ await new Promise((resolve) => { const lightclientStarted = (status: RunStatusCode): void => { if (status === RunStatusCode.started) { - this.lightclient?.emitter.off(LightclientEvent.statusChange, lightclientStarted); + lightclient?.emitter.off(LightclientEvent.statusChange, lightclientStarted); resolve(); } }; From bf4969fc54cc0406aa405df1f4f1d36830781ff2 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 15 Jan 2024 16:20:57 +0100 Subject: [PATCH 31/70] chore: add yarn scripts to simplify docs contribution (#6296) --- .github/workflows/docs-check.yml | 4 ++-- .github/workflows/docs.yml | 4 ++-- package.json | 8 +++++--- packages/cli/package.json | 2 +- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml index a3c4363920a1..4dbbcdce5f5c 100644 --- a/.github/workflows/docs-check.yml +++ b/.github/workflows/docs-check.yml @@ -39,12 +39,12 @@ jobs: run: scripts/wordlist_sort_check.sh - name: Build and collect docs - run: yarn build:docs + run: yarn docs:build # Run prettier check with fix after generating the docs. The CLI reference is formatted with prettier for # deployed version so this will fail if not "fixable" - name: Check docs format - run: yarn lint-docs:fix + run: yarn docs:lint:fix # Run spellcheck AFTER building docs, in case the CLI reference has issues - name: Spellcheck diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 6e27a89c3044..a47f236b3470 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -57,10 +57,10 @@ jobs: if: steps.cache-deps.outputs.cache-hit == 'true' - name: Build and collect docs - run: yarn build:docs + run: yarn docs:build - name: Lint built docs - run: yarn lint-docs:fix + run: yarn docs:lint:fix - name: Set up Python uses: actions/setup-python@v1 diff --git a/package.json b/package.json index 8e6dad1fdea2..5d055bd2f4ce 100644 --- a/package.json +++ b/package.json @@ -11,19 +11,21 @@ "clean": "rm -rf ./packages/*/lib ./packages/*/*.tsbuildinfo", "clean:nm": "rm -rf ./packages/*/node_modules ./node_modules", "build": "lerna run build", - "build:docs": "lerna run check-readme && lerna run build:docs && ./scripts/prepare-docs.sh", "build:watch": "lerna exec --parallel -- 'yarn run build:watch'", "build:ifchanged": "lerna exec -- ../../scripts/build_if_changed.sh", "lint": "eslint --color --ext .ts packages/*/src packages/*/test", "lint:fix": "yarn lint --fix", - "lint-docs": "prettier '**/*.md' --check", - "lint-docs:fix": "prettier '**/*.md' --write", "lint-dashboards": "node scripts/lint-grafana-dashboards.mjs ./dashboards", "check-build": "lerna run check-build", "check-readme": "lerna run check-readme", "check-types": "lerna run check-types", "check-spelling": "pyspelling -c .pyspelling.yml -v", "coverage": "lerna run coverage", + "docs:install": "pip install --user -r docs/requirements.txt", + "docs:build": "lerna run check-readme && lerna run docs:build && ./scripts/prepare-docs.sh", + "docs:lint": "prettier '**/*.md' --check", + "docs:lint:fix": "prettier '**/*.md' --write", + "docs:serve": "mkdocs serve --watch docs/pages --config-file docs/mkdocs.yml", "test": "lerna run test --concurrency 1", "test:unit": "lerna run test:unit --concurrency 1", "test:browsers": "lerna run test:browsers", diff --git a/packages/cli/package.json b/packages/cli/package.json index 047672c18855..440a7050a176 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -24,10 +24,10 @@ "build": "tsc -p tsconfig.build.json && yarn write-git-data", "build:release": "yarn clean && yarn run build", "build:watch": "tsc -p tsconfig.build.json --watch", - "build:docs": "node --loader ts-node/esm ./docsgen/index.ts", "write-git-data": "node lib/util/gitData/writeGitData.js", "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\" lodestar --help", "check-types": "tsc", + "docs:build": "node --loader ts-node/esm ./docsgen/index.ts", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", From 88744d8a4877499c8c7aa43aeb4d576b98581faf Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Mon, 15 Jan 2024 22:27:51 +0700 Subject: [PATCH 32/70] fix: do not download known block by root (#6292) * fix: do not download known block by root * fix: handle PreDeneb for SeenGossipBlockInput --- packages/beacon-node/src/chain/chain.ts | 4 ++ packages/beacon-node/src/chain/interface.ts | 2 + .../chain/seenCache/seenGossipBlockInput.ts | 21 +++++++-- .../src/network/processor/gossipHandlers.ts | 43 +++++++------------ .../src/network/processor/index.ts | 9 ++-- 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 520b20b820fc..39f1e49e987c 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -301,6 +301,10 @@ export class BeaconChain implements IBeaconChain { await this.bls.close(); } + seenBlock(blockRoot: RootHex): boolean { + return this.seenGossipBlockInput.hasBlock(blockRoot) || this.forkChoice.hasBlockHex(blockRoot); + } + regenCanAcceptWork(): boolean { return this.regen.canAcceptWork(); } diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 6e932b25c50e..0771a01caf08 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -119,6 +119,8 @@ export interface IBeaconChain { /** Stop beacon chain processing */ close(): Promise; + /** Chain has seen the specified block root or not. The block may not be processed yet, use forkchoice.hasBlock to check it */ + seenBlock(blockRoot: RootHex): boolean; /** Populate in-memory caches with persisted data. Call at least once on startup */ loadFromDisk(): Promise; /** Persist in-memory data to the DB. Call at least once before stopping the process */ diff --git a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts index 8b767975c112..1f23503d3957 100644 --- a/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts +++ b/packages/beacon-node/src/chain/seenCache/seenGossipBlockInput.ts @@ -2,7 +2,7 @@ import {toHexString} from "@chainsafe/ssz"; import {deneb, RootHex, ssz, allForks} from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {pruneSetToMax} from "@lodestar/utils"; -import {BLOBSIDECAR_FIXED_SIZE} from "@lodestar/params"; +import {BLOBSIDECAR_FIXED_SIZE, ForkSeq} from "@lodestar/params"; import { BlockInput, @@ -29,9 +29,11 @@ type BlockInputCacheType = { const MAX_GOSSIPINPUT_CACHE = 5; /** - * SeenGossipBlockInput tracks and caches the live blobs and blocks on the network to solve data availability - * for the blockInput. If no block has been seen yet for some already seen blobs, it responds will null, but - * on the first block or the consequent blobs it responds with blobs promise till all blobs become available. + * For predeneb, SeenGossipBlockInput only tracks and caches block so that we don't need to download known block + * roots. From deneb, it serves same purpose plus tracks and caches the live blobs and blocks on the network to + * solve data availability for the blockInput. If no block has been seen yet for some already seen blobs, it + * responds will null, but on the first block or the consequent blobs it responds with blobs promise till all blobs + * become available. * * One can start processing block on blobs promise blockInput response and can await on the promise before * fully importing the block. The blobs promise is gets resolved as soon as all blobs corresponding to that @@ -44,6 +46,10 @@ export class SeenGossipBlockInput { pruneSetToMax(this.blockInputCache, MAX_GOSSIPINPUT_CACHE); } + hasBlock(blockRoot: RootHex): boolean { + return this.blockInputCache.has(blockRoot); + } + getGossipBlockInput( config: ChainForkConfig, gossipedInput: GossipedBlockInput @@ -83,9 +89,16 @@ export class SeenGossipBlockInput { if (!this.blockInputCache.has(blockHex)) { this.blockInputCache.set(blockHex, blockCache); } + const {block: signedBlock, blockBytes, blobsCache, availabilityPromise, resolveAvailability} = blockCache; if (signedBlock !== undefined) { + if (config.getForkSeq(signedBlock.message.slot) < ForkSeq.deneb) { + return { + blockInput: getBlockInput.preDeneb(config, signedBlock, BlockSource.gossip, blockBytes ?? null), + blockInputMeta: {pending: null, haveBlobs: 0, expectedBlobs: 0}, + }; + } // block is available, check if all blobs have shown up const {slot, body} = signedBlock.message; const {blobKzgCommitments} = body as deneb.BeaconBlockBody; diff --git a/packages/beacon-node/src/network/processor/gossipHandlers.ts b/packages/beacon-node/src/network/processor/gossipHandlers.ts index d31183828b85..9073a204b785 100644 --- a/packages/beacon-node/src/network/processor/gossipHandlers.ts +++ b/packages/beacon-node/src/network/processor/gossipHandlers.ts @@ -45,13 +45,7 @@ import {PeerAction} from "../peers/index.js"; import {validateLightClientFinalityUpdate} from "../../chain/validation/lightClientFinalityUpdate.js"; import {validateLightClientOptimisticUpdate} from "../../chain/validation/lightClientOptimisticUpdate.js"; import {validateGossipBlobSidecar} from "../../chain/validation/blobSidecar.js"; -import { - BlockInput, - BlockSource, - getBlockInput, - GossipedInputType, - BlobSidecarValidation, -} from "../../chain/blocks/types.js"; +import {BlockInput, GossipedInputType, BlobSidecarValidation} from "../../chain/blocks/types.js"; import {sszDeserialize} from "../gossip/topic.js"; import {INetworkCore} from "../core/index.js"; import {INetwork} from "../interface.js"; @@ -123,28 +117,21 @@ function getDefaultHandlers(modules: ValidatorFnsModules, options: GossipHandler const delaySec = chain.clock.secFromSlot(slot, seenTimestampSec); const recvToVal = Date.now() / 1000 - seenTimestampSec; - let blockInput; - let blockInputMeta; - if (config.getForkSeq(signedBlock.message.slot) >= ForkSeq.deneb) { - const blockInputRes = chain.seenGossipBlockInput.getGossipBlockInput(config, { - type: GossipedInputType.block, - signedBlock, - blockBytes, - }); - - blockInput = blockInputRes.blockInput; - blockInputMeta = blockInputRes.blockInputMeta; - - // blockInput can't be returned null, improve by enforcing via return types - if (blockInput === null) { - throw Error( - `Invalid null blockInput returned by getGossipBlockInput for type=${GossipedInputType.block} blockHex=${blockHex} slot=${slot}` - ); - } - } else { - blockInput = getBlockInput.preDeneb(config, signedBlock, BlockSource.gossip, blockBytes); - blockInputMeta = {}; + // always set block to seen cache for all forks so that we don't need to download it + const blockInputRes = chain.seenGossipBlockInput.getGossipBlockInput(config, { + type: GossipedInputType.block, + signedBlock, + blockBytes, + }); + const blockInput = blockInputRes.blockInput; + // blockInput can't be returned null, improve by enforcing via return types + if (blockInput === null) { + throw Error( + `Invalid null blockInput returned by getGossipBlockInput for type=${GossipedInputType.block} blockHex=${blockHex} slot=${slot}` + ); } + const blockInputMeta = + config.getForkSeq(signedBlock.message.slot) >= ForkSeq.deneb ? blockInputRes.blockInputMeta : {}; metrics?.gossipBlock.receivedToGossipValidate.observe(recvToVal); logger.verbose("Received gossip block", { diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index 3d067c626f76..6fd0b235dfb1 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -231,11 +231,12 @@ export class NetworkProcessor { } searchUnknownSlotRoot({slot, root}: SlotRootHex, peer?: PeerIdStr): void { - // Search for the unknown block - if (!this.unknownRootsBySlot.getOrDefault(slot).has(root)) { - this.unknownRootsBySlot.getOrDefault(slot).add(root); - this.events.emit(NetworkEvent.unknownBlock, {rootHex: root, peer}); + if (this.chain.seenBlock(root) || this.unknownRootsBySlot.getOrDefault(slot).has(root)) { + return; } + // Search for the unknown block + this.unknownRootsBySlot.getOrDefault(slot).add(root); + this.events.emit(NetworkEvent.unknownBlock, {rootHex: root, peer}); } private onPendingGossipsubMessage(message: PendingGossipsubMessage): void { From 4996f4d5218994fbbd418be1340a3e816d01eac9 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Mon, 15 Jan 2024 16:58:08 +0100 Subject: [PATCH 33/70] test: migrate spec-test-utils and spec tests to vitest (#6222) * Migrate spec-test-utils and spec tests to vitest * Fix build check * Fix export path * Add config file * Fix spec tests * Fix the duplicate package script * Fix spec tests * Fix lint errors * Update the spec tests runner tasks * Fix the import for a spec test * Fix the import for a spec test * Fix spec tests * Update the task runner * Run spec test in fork not threads * Fix the config file path * Fix validator spec tests * Fix e2e tests * Make the validator spec tests run in parallel * Update the spec test runner options --- .github/workflows/test.yml | 11 +++--- packages/beacon-node/.mocharc.spec.cjs | 7 ---- packages/beacon-node/.mocharc.yml | 9 ----- packages/beacon-node/.nycrc.json | 3 -- packages/beacon-node/package.json | 10 +++--- .../beacon-node/test/spec/bls/index.test.ts | 14 +++++--- .../beacon-node/test/spec/downloadTests.ts | 2 +- .../test/spec/general/ssz_generic.ts | 2 +- .../spec/presets/epoch_processing.test.ts | 2 +- .../test/spec/presets/fork_choice.test.ts | 7 ++-- .../test/spec/presets/genesis.test.ts | 2 +- .../light_client/single_merkle_proof.ts | 2 +- .../test/spec/presets/light_client/sync.ts | 2 +- .../presets/light_client/update_ranking.ts | 2 +- .../test/spec/presets/merkle.test.ts | 2 +- .../test/spec/presets/rewards.test.ts | 2 +- .../test/spec/presets/ssz_static.test.ts | 3 +- .../test/spec/specTestVersioning.ts | 2 +- .../test/spec/utils/expectEqualBeaconState.ts | 2 +- .../test/spec/utils/runValidSszTest.ts | 2 +- .../test/spec/utils/specTestIterator.ts | 1 + packages/beacon-node/vitest.config.spec.ts | 19 +++++++++++ packages/spec-test-util/.mocharc.yaml | 4 --- packages/spec-test-util/.nycrc.json | 3 -- packages/spec-test-util/package.json | 29 ++++++++++++---- packages/spec-test-util/src/single.ts | 10 +++--- .../test/e2e/single/index.test.ts | 5 +-- packages/spec-test-util/test/globalSetup.ts | 2 ++ packages/spec-test-util/vitest.config.ts | 11 ++++++ packages/validator/package.json | 5 ++- packages/validator/test/globalSetup.ts | 2 ++ packages/validator/test/spec/downloadTests.ts | 2 +- packages/validator/test/spec/index.test.ts | 10 +++--- packages/validator/test/spec/spec.test.ts | 34 +++++++++++-------- packages/validator/vitest.config.spec.ts | 19 +++++++++++ packages/validator/vitest.config.ts | 11 ++++++ 36 files changed, 163 insertions(+), 92 deletions(-) delete mode 100644 packages/beacon-node/.mocharc.spec.cjs delete mode 100644 packages/beacon-node/.mocharc.yml delete mode 100644 packages/beacon-node/.nycrc.json create mode 100644 packages/beacon-node/vitest.config.spec.ts delete mode 100644 packages/spec-test-util/.mocharc.yaml delete mode 100644 packages/spec-test-util/.nycrc.json create mode 100644 packages/spec-test-util/test/globalSetup.ts create mode 100644 packages/spec-test-util/vitest.config.ts create mode 100644 packages/validator/test/globalSetup.ts create mode 100644 packages/validator/vitest.config.spec.ts create mode 100644 packages/validator/vitest.config.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index deaf19329872..d865045c4f3a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -321,12 +321,15 @@ jobs: # Run them in different steps to quickly identifying which command failed # Otherwise just doing `yarn test:spec` you can't tell which specific suite failed # many of the suites have identical names for minimal and mainnet - - name: Spec tests bls-general - run: yarn test:spec-bls-general + - name: Spec tests general + run: yarn test:spec:general working-directory: packages/beacon-node + - name: Spec tests bls + run: yarn test:spec:bls + working-directory: packages/beacon-node - name: Spec tests minimal - run: yarn test:spec-minimal + run: yarn test:spec:minimal working-directory: packages/beacon-node - name: Spec tests mainnet - run: NODE_OPTIONS='--max-old-space-size=4096' yarn test:spec-mainnet + run: NODE_OPTIONS='--max-old-space-size=4096' yarn test:spec:mainnet working-directory: packages/beacon-node diff --git a/packages/beacon-node/.mocharc.spec.cjs b/packages/beacon-node/.mocharc.spec.cjs deleted file mode 100644 index 1a160c2d6131..000000000000 --- a/packages/beacon-node/.mocharc.spec.cjs +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - colors: true, - require: ["./test/setupPreset.ts", "./test/setup.ts"], - "node-option": ["loader=ts-node/esm"], - timeout: 60_000, - parallel: true -}; diff --git a/packages/beacon-node/.mocharc.yml b/packages/beacon-node/.mocharc.yml deleted file mode 100644 index 861a30e276e3..000000000000 --- a/packages/beacon-node/.mocharc.yml +++ /dev/null @@ -1,9 +0,0 @@ -colors: true -require: - - ./test/setupPreset.ts - - ./test/setup.ts -timeout: 5000 -exit: true -extension: ["ts"] -node-option: - - "loader=ts-node/esm" diff --git a/packages/beacon-node/.nycrc.json b/packages/beacon-node/.nycrc.json deleted file mode 100644 index 69aa626339a0..000000000000 --- a/packages/beacon-node/.nycrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../.nycrc.json" -} diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index bab5c982df42..c006aed515d4 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -87,11 +87,11 @@ "test:sim:withdrawals": "mocha 'test/sim/withdrawal-interop.test.ts'", "test:sim:blobs": "mocha 'test/sim/4844-interop.test.ts'", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", - "check-spec-tests": "mocha test/spec/checkCoverage.ts", - "test:spec-bls-general": "mocha --config .mocharc.spec.cjs 'test/spec/bls/**/*.test.ts' 'test/spec/general/**/*.test.ts'", - "test:spec-minimal": "LODESTAR_PRESET=minimal mocha --config .mocharc.spec.cjs 'test/spec/presets/**/*.test.ts'", - "test:spec-mainnet": "LODESTAR_PRESET=mainnet mocha --config .mocharc.spec.cjs 'test/spec/presets/**/*.test.ts'", - "test:spec": "yarn test:spec-bls-general && yarn test:spec-minimal && yarn test:spec-mainnet", + "test:spec:bls": "vitest --run --config vitest.config.spec.ts --dir test/spec/bls/", + "test:spec:general": "vitest --run --config vitest.config.spec.ts --dir test/spec/general/", + "test:spec:minimal": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.spec.ts --dir test/spec/presets/", + "test:spec:mainnet": "LODESTAR_PRESET=mainnet vitest --run --config vitest.config.spec.ts --dir test/spec/presets/", + "test:spec": "yarn test:spec:bls && yarn test:spec:general && yarn test:spec:minimal && yarn test:spec:mainnet", "check-readme": "typescript-docs-verifier" }, "dependencies": { diff --git a/packages/beacon-node/test/spec/bls/index.test.ts b/packages/beacon-node/test/spec/bls/index.test.ts index 35b44eec8f9d..b581b8681870 100644 --- a/packages/beacon-node/test/spec/bls/index.test.ts +++ b/packages/beacon-node/test/spec/bls/index.test.ts @@ -1,7 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import jsyaml from "js-yaml"; -import {expect} from "chai"; +import {expect, describe, it} from "vitest"; import {blsSpecTests} from "../specTestVersioning.js"; import {readdirSyncSpec} from "../utils/specTestIterator.js"; import {testFnByType} from "./bls.js"; @@ -35,15 +35,21 @@ for (const fnName of readdirSyncSpec(blsSpecTests.outputDir)) { const fnTestDirpath = path.join(blsSpecTests.outputDir, fnName); for (const testName of readdirSyncSpec(fnTestDirpath)) { - it(`${fnName}/${testName}`, function () { + // TODO: Will be removed when we remove chai/mocha eslint rules + // eslint-disable-next-line mocha/handle-done-callback + it(`${fnName}/${testName}`, function (context) { if (fn === "skip") { - this.skip(); + // TODO: Will be removed when we remove chai/mocha eslint rules + // eslint-disable-next-line mocha/no-nested-tests + context.skip(); return; } // Do not manually skip tests here, do it in the top of the file if (skippedTestNames.includes(testName)) { - this.skip(); + // TODO: Will be removed when we remove chai/mocha eslint rules + // eslint-disable-next-line mocha/no-nested-tests + context.skip(); return; } diff --git a/packages/beacon-node/test/spec/downloadTests.ts b/packages/beacon-node/test/spec/downloadTests.ts index 1c7b6dbb3910..57efd3ca2183 100644 --- a/packages/beacon-node/test/spec/downloadTests.ts +++ b/packages/beacon-node/test/spec/downloadTests.ts @@ -1,4 +1,4 @@ -import {downloadTests} from "@lodestar/spec-test-util"; +import {downloadTests} from "@lodestar/spec-test-util/downloadTests"; import {ethereumConsensusSpecsTests, blsSpecTests} from "./specTestVersioning.js"; /* eslint-disable no-console */ diff --git a/packages/beacon-node/test/spec/general/ssz_generic.ts b/packages/beacon-node/test/spec/general/ssz_generic.ts index cbcd4fc754d9..e791ca62eefe 100644 --- a/packages/beacon-node/test/spec/general/ssz_generic.ts +++ b/packages/beacon-node/test/spec/general/ssz_generic.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import {expect} from "chai"; +import {expect, it} from "vitest"; import {TestRunnerCustom} from "../utils/types.js"; import {parseSszGenericInvalidTestcase, parseSszGenericValidTestcase} from "../utils/sszTestCaseParser.js"; import {runValidSszTest} from "../utils/runValidSszTest.js"; diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index 554001bfbde8..951761b9b743 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {expect} from "vitest"; import { CachedBeaconStateAllForks, EpochTransitionCache, diff --git a/packages/beacon-node/test/spec/presets/fork_choice.test.ts b/packages/beacon-node/test/spec/presets/fork_choice.test.ts index 47d72c1226e1..665e395222f9 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {BeaconStateAllForks, isExecutionStateType, signedBlockToSignedHeader} from "@lodestar/state-transition"; import {InputType} from "@lodestar/spec-test-util"; @@ -8,7 +8,7 @@ import {phase0, allForks, bellatrix, ssz, RootHex, deneb} from "@lodestar/types" import {bnToNum, fromHex} from "@lodestar/utils"; import {createBeaconConfig} from "@lodestar/config"; import {ACTIVE_PRESET, ForkSeq, isForkBlobs} from "@lodestar/params"; -import {BeaconChain} from "../../../src/chain/index.js"; +import {BeaconChain, ChainEvent} from "../../../src/chain/index.js"; import {ClockEvent} from "../../../src/util/clock.js"; import {computeInclusionProof} from "../../../src/util/blobs.js"; import {createCachedBeaconStateTest} from "../../utils/cachedBeaconState.js"; @@ -112,6 +112,9 @@ const forkChoiceTest = } ); + // The handler of `ChainEvent.forkChoiceFinalized` access `db.block` and raise error if not found. + chain.emitter.removeAllListeners(ChainEvent.forkChoiceFinalized); + const stepsLen = steps.length; logger.debug("Fork choice test", {steps: stepsLen}); diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index ef3006bd6221..0b707f509428 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {expect} from "vitest"; import {phase0, Root, ssz, TimeSeconds, allForks, deneb} from "@lodestar/types"; import {InputType} from "@lodestar/spec-test-util"; import { diff --git a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts index b8df2f01a8f0..d230bc926b0d 100644 --- a/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts +++ b/packages/beacon-node/test/spec/presets/light_client/single_merkle_proof.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {Tree} from "@chainsafe/persistent-merkle-tree"; import {TreeViewDU, Type} from "@chainsafe/ssz"; import {RootHex, ssz} from "@lodestar/types"; diff --git a/packages/beacon-node/test/spec/presets/light_client/sync.ts b/packages/beacon-node/test/spec/presets/light_client/sync.ts index 8f4d5dc59056..e48bb0f361a3 100644 --- a/packages/beacon-node/test/spec/presets/light_client/sync.ts +++ b/packages/beacon-node/test/spec/presets/light_client/sync.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {init} from "@chainsafe/bls/switchable"; import {isForkLightClient} from "@lodestar/params"; import {altair, phase0, RootHex, Slot, ssz} from "@lodestar/types"; diff --git a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts index 2a319b88cc7c..c4b5b7623d85 100644 --- a/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts +++ b/packages/beacon-node/test/spec/presets/light_client/update_ranking.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {altair, ssz, allForks} from "@lodestar/types"; import {isForkLightClient} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; diff --git a/packages/beacon-node/test/spec/presets/merkle.test.ts b/packages/beacon-node/test/spec/presets/merkle.test.ts index 089ffcec97b3..a711d9ce66ac 100644 --- a/packages/beacon-node/test/spec/presets/merkle.test.ts +++ b/packages/beacon-node/test/spec/presets/merkle.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {expect} from "vitest"; import {ProofType, SingleProof, Tree} from "@chainsafe/persistent-merkle-tree"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; diff --git a/packages/beacon-node/test/spec/presets/rewards.test.ts b/packages/beacon-node/test/spec/presets/rewards.test.ts index 086dab797c13..635d658857b1 100644 --- a/packages/beacon-node/test/spec/presets/rewards.test.ts +++ b/packages/beacon-node/test/spec/presets/rewards.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {expect} from "vitest"; import {VectorCompositeType} from "@chainsafe/ssz"; import {BeaconStateAllForks, beforeProcessEpoch} from "@lodestar/state-transition"; import {getRewardsAndPenalties} from "@lodestar/state-transition/epoch"; diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index 55587f6e9375..a23a7d388f55 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import path from "node:path"; +import {it, vi} from "vitest"; import {Type} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; import {ACTIVE_PRESET, ForkName, ForkLightClient} from "@lodestar/params"; @@ -58,7 +59,7 @@ const sszStatic = it(testCase, function () { // Mainnet must deal with big full states and hash each one multiple times if (ACTIVE_PRESET === "mainnet") { - this.timeout(30 * 1000); + vi.setConfig({testTimeout: 30 * 1000}); } const testData = parseSszStaticTestcase(path.join(testSuiteDirpath, testCase)); diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index 20125520321d..c8a65357bf02 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -1,6 +1,6 @@ import path from "node:path"; import {fileURLToPath} from "node:url"; -import {DownloadTestsOptions} from "@lodestar/spec-test-util"; +import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; // WARNING! Don't move or rename this file !!! // diff --git a/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts b/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts index 356fcb724125..1f22c1b3d8cc 100644 --- a/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts +++ b/packages/beacon-node/test/spec/utils/expectEqualBeaconState.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {allForks, ssz} from "@lodestar/types"; import {ForkName} from "@lodestar/params"; import {InputType} from "@lodestar/spec-test-util"; diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index 1c7f9cb0eccf..7dedd0983e3b 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {Node} from "@chainsafe/persistent-merkle-tree"; import {Type, CompositeType, fromHexString, toHexString} from "@chainsafe/ssz"; diff --git a/packages/beacon-node/test/spec/utils/specTestIterator.ts b/packages/beacon-node/test/spec/utils/specTestIterator.ts index 084d3d00fd48..6aa683cb6530 100644 --- a/packages/beacon-node/test/spec/utils/specTestIterator.ts +++ b/packages/beacon-node/test/spec/utils/specTestIterator.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import path from "node:path"; +import {describe, it} from "vitest"; import {ForkName} from "@lodestar/params"; import {describeDirectorySpecTest} from "@lodestar/spec-test-util"; import {RunnerType, TestRunner} from "./types.js"; diff --git a/packages/beacon-node/vitest.config.spec.ts b/packages/beacon-node/vitest.config.spec.ts new file mode 100644 index 000000000000..e5f588d17155 --- /dev/null +++ b/packages/beacon-node/vitest.config.spec.ts @@ -0,0 +1,19 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + testTimeout: 60_000, + passWithNoTests: true, + pool: "threads", + poolOptions: { + threads: { + isolate: false, + }, + }, + }, + }) +); diff --git a/packages/spec-test-util/.mocharc.yaml b/packages/spec-test-util/.mocharc.yaml deleted file mode 100644 index 1f15bf5929e0..000000000000 --- a/packages/spec-test-util/.mocharc.yaml +++ /dev/null @@ -1,4 +0,0 @@ -colors: true -extension: ["ts"] -node-option: - - "loader=ts-node/esm" diff --git a/packages/spec-test-util/.nycrc.json b/packages/spec-test-util/.nycrc.json deleted file mode 100644 index 69aa626339a0..000000000000 --- a/packages/spec-test-util/.nycrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../.nycrc.json" -} diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 5fc59cd76e12..b904cb2b6ffc 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -9,8 +9,24 @@ }, "homepage": "https://github.com/ChainSafe/lodestar#readme", "type": "module", - "exports": "./lib/index.js", + "exports": { + ".": { + "import": "./lib/index.js" + }, + "./downloadTests": { + "import": "./lib/downloadTests.js" + } + }, "types": "lib/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "*", + "lib/*", + "lib/*/index" + ] + } + }, "files": [ "lib/**/*.js", "lib/**/*.js.map", @@ -26,12 +42,13 @@ "build": "tsc -p tsconfig.build.json", "build:release": "yarn clean && yarn build", "build:watch": "yarn run build --watch", - "check-build": "node -e \"(async function() { await import('./lib/index.js') })()\"", + "check-build": "node -e \"(async function() { await import('./lib/downloadTests.js') })()\"", "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:e2e": "mocha 'test/e2e/**/*.test.ts'", + "test:unit": "vitest --run --passWithNoTests --dir test/unit/ --coverage", + "test:e2e": "vitest --run --dir test/e2e/", "check-readme": "typescript-docs-verifier" }, "repository": { @@ -48,8 +65,7 @@ "@lodestar/utils": "^1.13.0", "async-retry": "^1.3.3", "axios": "^1.3.4", - "chai": "^4.3.7", - "mocha": "^10.2.0", + "vitest": "^1.0.2", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", "tar": "^6.1.13" @@ -59,7 +75,6 @@ "@types/tar": "^6.1.4" }, "peerDependencies": { - "chai": "^4.3.7", - "mocha": "^10.2.0" + "vitest": "^1.0.2" } } diff --git a/packages/spec-test-util/src/single.ts b/packages/spec-test-util/src/single.ts index 7951cd61a87d..101fc296bd42 100644 --- a/packages/spec-test-util/src/single.ts +++ b/packages/spec-test-util/src/single.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import path from "node:path"; -import {expect} from "chai"; +import {describe, it, vi, expect} from "vitest"; import {uncompress} from "snappyjs"; import {loadYaml} from "@lodestar/utils"; @@ -103,7 +103,7 @@ export function describeDirectorySpecTest describe(name, function () { if (options.timeout !== undefined) { - this.timeout(options.timeout || "10 min"); + vi.setConfig({testTimeout: options.timeout ?? 10 * 60 * 1000}); } for (const testSubDirname of fs.readdirSync(testCaseDirectoryPath)) { @@ -112,9 +112,9 @@ export function describeDirectorySpecTest continue; } - // Use full path here, not just `testSubDirname` to allow usage of `mocha --grep` + // Use full path here, not just `testSubDirname` to allow usage of `vitest --grep` const testName = `${name}/${testSubDirname}`; - it(testName, async function () { + it(testName, async function (context) { // some tests require to load meta.yaml first in order to know respective ssz types. const metaFilePath = path.join(testSubDirPath, "meta.yaml"); const meta: TestCase["meta"] = fs.existsSync(metaFilePath) @@ -124,7 +124,7 @@ export function describeDirectorySpecTest let testCase = loadInputFiles(testSubDirPath, options, meta); if (options.mapToTestCase) testCase = options.mapToTestCase(testCase); if (options.shouldSkip && options.shouldSkip(testCase, testName, 0)) { - this.skip(); + context.skip(); return; } diff --git a/packages/spec-test-util/test/e2e/single/index.test.ts b/packages/spec-test-util/test/e2e/single/index.test.ts index b851eab24d7f..a20b783f4370 100644 --- a/packages/spec-test-util/test/e2e/single/index.test.ts +++ b/packages/spec-test-util/test/e2e/single/index.test.ts @@ -1,6 +1,7 @@ import fs from "node:fs"; import path from "node:path"; import {fileURLToPath} from "node:url"; +import {beforeAll, afterAll} from "vitest"; import {ContainerType, Type} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; import {describeDirectorySpecTest, InputType, loadYamlFile} from "../../../src/single.js"; @@ -31,14 +32,14 @@ const sampleContainerType = new ContainerType({ number: ssz.UintNum64, }); -before(() => { +beforeAll(() => { yamlToSSZ(path.join(__dirname, "../_test_files/single/case0/input.yaml"), sampleContainerType); yamlToSSZ(path.join(__dirname, "../_test_files/single/case0/output.yaml"), ssz.UintNum64); yamlToSSZ(path.join(__dirname, "../_test_files/single/case1/input.yaml"), sampleContainerType); yamlToSSZ(path.join(__dirname, "../_test_files/single/case1/output.yaml"), ssz.UintNum64); }); -after(() => { +afterAll(() => { fs.unlinkSync(path.join(__dirname, "../_test_files/single/case0/input.ssz")); fs.unlinkSync(path.join(__dirname, "../_test_files/single/case0/output.ssz")); fs.unlinkSync(path.join(__dirname, "../_test_files/single/case1/input.ssz")); diff --git a/packages/spec-test-util/test/globalSetup.ts b/packages/spec-test-util/test/globalSetup.ts new file mode 100644 index 000000000000..0ab57c057472 --- /dev/null +++ b/packages/spec-test-util/test/globalSetup.ts @@ -0,0 +1,2 @@ +export async function setup(): Promise {} +export async function teardown(): Promise {} diff --git a/packages/spec-test-util/vitest.config.ts b/packages/spec-test-util/vitest.config.ts new file mode 100644 index 000000000000..1df0de848936 --- /dev/null +++ b/packages/spec-test-util/vitest.config.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/validator/package.json b/packages/validator/package.json index ecd15116169a..1c8c1923e049 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -30,9 +30,8 @@ "pretest": "yarn run check-types", "test:unit": "nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit/**/*.test.ts'", "test": "yarn test:unit", - "test:e2e:only": "mocha 'test/e2e/**/*.test.ts'", - "test:spec": "mocha 'test/spec/**/*.test.ts'", - "test:e2e": "LODESTAR_PRESET=minimal yarn run download-spec-tests && yarn test:spec && yarn test:e2e:only", + "test:spec": "vitest --run --config vitest.config.spec.ts --dir test/spec/", + "test:e2e": "mocha 'test/e2e/**/*.test.ts'", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", "coverage": "codecov -F lodestar-validator", "check-readme": "typescript-docs-verifier" diff --git a/packages/validator/test/globalSetup.ts b/packages/validator/test/globalSetup.ts new file mode 100644 index 000000000000..0ab57c057472 --- /dev/null +++ b/packages/validator/test/globalSetup.ts @@ -0,0 +1,2 @@ +export async function setup(): Promise {} +export async function teardown(): Promise {} diff --git a/packages/validator/test/spec/downloadTests.ts b/packages/validator/test/spec/downloadTests.ts index 4666f0d4a826..7aede8425b19 100644 --- a/packages/validator/test/spec/downloadTests.ts +++ b/packages/validator/test/spec/downloadTests.ts @@ -1,4 +1,4 @@ -import {downloadGenericSpecTests} from "@lodestar/spec-test-util"; +import {downloadGenericSpecTests} from "@lodestar/spec-test-util/downloadTests"; import {SPEC_TEST_LOCATION, SPEC_TEST_VERSION, SPEC_TEST_REPO_URL, TESTS_TO_DOWNLOAD} from "./params.js"; /* eslint-disable no-console */ diff --git a/packages/validator/test/spec/index.test.ts b/packages/validator/test/spec/index.test.ts index 02a585163b72..bd6ff947ca41 100644 --- a/packages/validator/test/spec/index.test.ts +++ b/packages/validator/test/spec/index.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect, describe, it, beforeAll, afterAll} from "vitest"; import {rimraf} from "rimraf"; import {LevelDbController} from "@lodestar/db"; import { @@ -15,11 +15,11 @@ describe("slashing-protection custom tests", () => { const pubkey = Buffer.alloc(96, 1); let db: LevelDbController; - before(async () => { + beforeAll(async () => { db = await LevelDbController.create({name: dbLocation}, {logger: testLogger()}); }); - after(async () => { + afterAll(async () => { await db.clear(); await db.close(); rimraf.sync(dbLocation); @@ -31,7 +31,7 @@ describe("slashing-protection custom tests", () => { const block2: SlashingProtectionBlock = {slot: block1.slot, signingRoot: Buffer.alloc(32, 2)}; await slashingProtection.checkAndInsertBlockProposal(pubkey, block1); - await expect(slashingProtection.checkAndInsertBlockProposal(pubkey, block2)).to.be.rejectedWith(InvalidBlockError); + await expect(slashingProtection.checkAndInsertBlockProposal(pubkey, block2)).rejects.toThrow(InvalidBlockError); }); it("Should reject same attestation", async () => { @@ -48,7 +48,7 @@ describe("slashing-protection custom tests", () => { }; await slashingProtection.checkAndInsertAttestation(pubkey, attestation1); - await expect(slashingProtection.checkAndInsertAttestation(pubkey, attestation2)).to.be.rejectedWith( + await expect(slashingProtection.checkAndInsertAttestation(pubkey, attestation2)).rejects.toThrow( InvalidAttestationError ); }); diff --git a/packages/validator/test/spec/spec.test.ts b/packages/validator/test/spec/spec.test.ts index 99ef80ca4bfc..41b094473c66 100644 --- a/packages/validator/test/spec/spec.test.ts +++ b/packages/validator/test/spec/spec.test.ts @@ -1,5 +1,5 @@ import path from "node:path"; -import {expect} from "chai"; +import {describe, it, beforeAll, beforeEach, afterAll, expect} from "vitest"; import {rimraf} from "rimraf"; import {fromHexString} from "@chainsafe/ssz"; import {LevelDbController} from "@lodestar/db"; @@ -22,12 +22,12 @@ describe("slashing-protection-interchange-tests", () => { let db: LevelDbController; let slashingProtection: SlashingProtection; - before(async () => { + beforeAll(async () => { db = await LevelDbController.create({name: dbLocation}, {logger: testLogger()}); slashingProtection = new SlashingProtection(db); }); - after(async () => { + afterAll(async () => { await db.close(); rimraf.sync(dbLocation); }); @@ -35,29 +35,31 @@ describe("slashing-protection-interchange-tests", () => { for (const testCase of testCases) { describe(testCase.name, () => { for (const step of testCase.steps) { - beforeEach(async () => { - await db.clear(); - }); + // If there is no `it` block then we should skip to avoid running `beforeEach` hooks + if (step.blocks.length === 0 && step.attestations.length === 0) { + continue; + } // Import - beforeEach("Import interchange", async () => { - expect(await db.keys()).lengthOf(0, "DB is not empty"); + beforeEach(async () => { + await db.clear(); + expect(await db.keys()).toHaveLength(0); const genesisValidatorsRoot = fromHexString(testCase.genesis_validators_root); if (step.should_succeed) { if (step.contains_slashable_data) { await expect( slashingProtection.importInterchange(step.interchange, genesisValidatorsRoot) - ).to.be.rejectedWith(InterchangeError); + ).rejects.toThrow(InterchangeError); } else { await expect( slashingProtection.importInterchange(step.interchange, genesisValidatorsRoot) - ).to.not.be.rejectedWith(InterchangeError); + ).resolves.toBeUndefined(); } } else { await expect( slashingProtection.importInterchange(step.interchange, genesisValidatorsRoot) - ).to.not.be.rejectedWith(InterchangeError); + ).resolves.toBeUndefined(); } }); @@ -71,9 +73,9 @@ describe("slashing-protection-interchange-tests", () => { signingRoot: blockRaw.signing_root ? fromHexString(blockRaw.signing_root) : ZERO_HASH, }; if (blockRaw.should_succeed) { - await slashingProtection.checkAndInsertBlockProposal(pubkey, block); + await expect(slashingProtection.checkAndInsertBlockProposal(pubkey, block)).resolves.toBeUndefined(); } else { - await expect(slashingProtection.checkAndInsertBlockProposal(pubkey, block)).to.be.rejectedWith( + await expect(slashingProtection.checkAndInsertBlockProposal(pubkey, block)).rejects.toThrow( InvalidBlockError ); } @@ -90,9 +92,11 @@ describe("slashing-protection-interchange-tests", () => { signingRoot: attestationRaw.signing_root ? fromHexString(attestationRaw.signing_root) : ZERO_HASH, }; if (attestationRaw.should_succeed) { - await slashingProtection.checkAndInsertAttestation(pubkey, attestation); + await expect( + slashingProtection.checkAndInsertAttestation(pubkey, attestation) + ).resolves.toBeUndefined(); } else { - await expect(slashingProtection.checkAndInsertAttestation(pubkey, attestation)).to.be.rejectedWith( + await expect(slashingProtection.checkAndInsertAttestation(pubkey, attestation)).rejects.toThrow( InvalidAttestationError ); } diff --git a/packages/validator/vitest.config.spec.ts b/packages/validator/vitest.config.spec.ts new file mode 100644 index 000000000000..e5f588d17155 --- /dev/null +++ b/packages/validator/vitest.config.spec.ts @@ -0,0 +1,19 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + testTimeout: 60_000, + passWithNoTests: true, + pool: "threads", + poolOptions: { + threads: { + isolate: false, + }, + }, + }, + }) +); diff --git a/packages/validator/vitest.config.ts b/packages/validator/vitest.config.ts new file mode 100644 index 000000000000..1df0de848936 --- /dev/null +++ b/packages/validator/vitest.config.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); From fc95bf64b052f2708f33d12c9c174a51c97a1974 Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Mon, 15 Jan 2024 20:37:49 -0500 Subject: [PATCH 34/70] docs: re-implement validator config page with builder.boostFactor notes (#6295) * Change docs nav titles and include vc config * Rename and re-include config with builder boost * refactor builderboostFactor from comments * add clarification to maxprofit * clarification on intro Co-authored-by: Nico Flaig * address additional comments * Remove redundancies in navigation menu * Just formatting changes * Update wordlist * Use term "beacon node", more consistent with text above * Apply some feedback from Gajinder * fix builder boost factor math example * Use integer value in Example 1 * Update executiononly description --------- Co-authored-by: Nico Flaig --- .wordlist.txt | 1 + docs/mkdocs.yml | 9 +++-- ...ator-management.md => vc-configuration.md} | 38 ++++++++++++++++--- 3 files changed, 38 insertions(+), 10 deletions(-) rename docs/pages/validator-management/{validator-management.md => vc-configuration.md} (67%) diff --git a/.wordlist.txt b/.wordlist.txt index 634ab95ab62e..5982de7b50dc 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -14,6 +14,7 @@ Chai ChainSafe Customizations DPoS +DVs Discv DockerHub Dockerized diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 270a01b311de..c26b849e98b9 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -81,20 +81,21 @@ nav: - Starting a Node: getting-started/starting-a-node.md - Data Retention: data-retention.md - Beacon Node: - - Configuration: beacon-management/beacon-cli.md + - CLI Reference: beacon-management/beacon-cli.md - Networking: beacon-management/networking.md - MEV and Builder Integration: beacon-management/mev-and-builder-integration.md - Syncing: beacon-management/syncing.md - Validator: - - Configuration: validator-management/validator-cli.md + - Configuration: validator-management/vc-configuration.md + - CLI Reference: validator-management/validator-cli.md # - Key Management: validator-management/key-management.md # - Withdrawals: validator-management/withdrawals.md # - Multiple and Fall-Back Validation: validator-management/multiple-and-fallback-validation.md - Bootnode: - - Configuration: bootnode/bootnode-cli.md + - CLI Reference: bootnode/bootnode-cli.md - Light Client and Prover: - Light Client: lightclient-prover/lightclient.md - - Light Client Configuration: lightclient-prover/lightclient-cli.md + - Light Client CLI Reference: lightclient-prover/lightclient-cli.md - Prover: lightclient-prover/prover.md # - Prover Configuration: lightclient-prover/prover-cli.md - Logging and Metrics: diff --git a/docs/pages/validator-management/validator-management.md b/docs/pages/validator-management/vc-configuration.md similarity index 67% rename from docs/pages/validator-management/validator-management.md rename to docs/pages/validator-management/vc-configuration.md index 7bd0b719ee61..cf8f3acae060 100644 --- a/docs/pages/validator-management/validator-management.md +++ b/docs/pages/validator-management/vc-configuration.md @@ -1,6 +1,6 @@ -# Validator management +# Validator Configuration -The following instructions are required for stakers utilizing Lodestar. +The following instructions are for stakers utilizing the Lodestar validator client. [TOC] @@ -17,7 +17,7 @@ The mnemonic is randomly generated during wallet creation and printed out to the ### Create a wallet -Lodestar is deprecating its functionality to create wallets. +Lodestar has removed its functionality to create wallets. To create a wallet, we recommend using the official [`staking-deposit-cli`](https://github.com/ethereum/staking-deposit-cli/releases) from the Ethereum Foundation for users comfortable with command line interfaces. @@ -88,11 +88,37 @@ Configure your validator client's fee recipient address by using the `--suggeste You may choose to use the `--strictFeeRecipientCheck` flag to enable a strict check of the fee recipient address with the one returned by the beacon node for added reassurance. +### Configure your builder selection and/or builder boost factor + +If you are running a beacon node with connected builder relays, you may use these validator configurations to signal which block (builder vs. local execution) the beacon node should produce. + +With produceBlockV3 (enabled automatically after the Deneb hard fork), the `--builder.boostFactor` is a percentage multiplier the block producing beacon node must apply to boost (>100) or dampen (<100) builder block value for selection against execution block. The multiplier is ignored if `--builder.selection` is set to anything other than `maxprofit`. Even though this is set on the validator client, the calculation is requested and applied on the beacon node itself. For more information, see the [produceBlockV3 Beacon API](https://ethereum.github.io/beacon-APIs/#/ValidatorRequiredApi/produceBlockV3). + +With Lodestar's `--builder.selection` validator options, you can select: + +- `maxprofit`: Default setting for Lodestar set at `--builder.boostFactor=100`. This default setting will always choose the more profitable block. Using this option, you may customize your `--builder.boostFactor` to your preference. Examples of its usage are below. +- `executiononly`: Beacon node will be requested to produce local execution block even if builder relays are configured. This option will always select the local execution block and will error if it couldn't produce one. +- `builderalways`: An alias of `--builder.boostFactor=18446744073709551615` (2**64 - 1), which will select the builder block, unless the builder block fails to produce. The builder block may fail to produce if it's not available, not timely or there is an indication of censorship via `shouldOverrideBuilder` from the execution payload response. +- `builderonly`: Generally used for distributed validators (DVs). No execution block production will be triggered. Therefore, if a builder block is not produced, the API will fail and _no block will be produced_. + +#### Calculating builder boost factor with examples + +To calculate the builder boost factor setting, you need to know what percentage you will accept a builder block for against a local execution block using the following formula: `100*100/(100+percentage)`. + +Example 1: I will only accept a builder block with 25% more value than the local execution block. +``` +10000/(100+25) = 80 +``` +Therefore, `--builder.boostFactor=80`. + +Example 2: Setting a `--builder.boostFactor=0` will always prefer the local execution block, but will produce an available builder block if the local execution block fails. + +Example 3: Setting a `--builder.boostFactor=100` is the same as signaling `--builder.selection maxprofit` where the validator will always select the most profitable block between the local execution engine and the builder block from the relay. + ### Submit a validator deposit -Please use the official tools to perform your deposits +Please use the official Ethereum Launchpad to perform your deposits -- `staking-deposit-cli`: - Ethereum Foundation launchpad: ## Run the validator @@ -105,7 +131,7 @@ To start a Lodestar validator run the command: You should see confirmation that modules have started. -```bash +``` Nov-29 10:47:13.647[] info: Lodestar network=sepolia, version=v1.2.2/f093b46, commit=f093b468ec3ab0dbbe8e2d2c8175f52ad88aa35f Nov-29 10:47:13.649[] info: Connecting to LevelDB database path=/home/user/.local/share/lodestar/sepolia/validator-db Nov-29 10:47:51.732[] info: 3 local keystores From 9940478fb5b2e5a6bdfca82f0aa18a8a6d6dc172 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 16 Jan 2024 16:20:58 +0100 Subject: [PATCH 35/70] chore: install same vitest version across packages (#6306) --- packages/spec-test-util/package.json | 4 ++-- packages/spec-test-util/src/single.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 4a3ca612527e..ab427e2d0a41 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -65,7 +65,7 @@ "@lodestar/utils": "^1.14.0", "async-retry": "^1.3.3", "axios": "^1.3.4", - "vitest": "^1.0.2", + "vitest": "^1.1.0", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", "tar": "^6.1.13" @@ -75,6 +75,6 @@ "@types/tar": "^6.1.4" }, "peerDependencies": { - "vitest": "^1.0.2" + "vitest": "^1.1.0" } } diff --git a/packages/spec-test-util/src/single.ts b/packages/spec-test-util/src/single.ts index 101fc296bd42..47bf8d0a0742 100644 --- a/packages/spec-test-util/src/single.ts +++ b/packages/spec-test-util/src/single.ts @@ -112,7 +112,7 @@ export function describeDirectorySpecTest continue; } - // Use full path here, not just `testSubDirname` to allow usage of `vitest --grep` + // Use full path here, not just `testSubDirname` to allow usage of `vitest -t` const testName = `${name}/${testSubDirname}`; it(testName, async function (context) { // some tests require to load meta.yaml first in order to know respective ssz types. From b082a4891457e47b524820e86f91cb34e7ddd83f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 16 Jan 2024 16:22:00 +0100 Subject: [PATCH 36/70] refactor: use for...of instead of forEach (#6307) --- packages/beacon-node/src/chain/chain.ts | 4 ++-- packages/beacon-node/src/network/processor/index.ts | 4 +++- packages/fork-choice/src/forkChoice/forkChoice.ts | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 39f1e49e987c..14fef75c8ad8 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -963,9 +963,9 @@ export class BeaconChain implements IBeaconChain { } async updateBeaconProposerData(epoch: Epoch, proposers: ProposerPreparationData[]): Promise { - proposers.forEach((proposer) => { + for (const proposer of proposers) { this.beaconProposerCache.add(epoch, proposer); - }); + } } updateBuilderStatus(clockSlot: Slot): void { diff --git a/packages/beacon-node/src/network/processor/index.ts b/packages/beacon-node/src/network/processor/index.ts index 6fd0b235dfb1..ba84c9b12a60 100644 --- a/packages/beacon-node/src/network/processor/index.ts +++ b/packages/beacon-node/src/network/processor/index.ts @@ -433,7 +433,9 @@ export class NetworkProcessor { ]; if (Array.isArray(messageOrArray)) { - messageOrArray.forEach((msg) => this.trackJobTime(msg, messageOrArray.length)); + for (const msg of messageOrArray) { + this.trackJobTime(msg, messageOrArray.length); + } } else { this.trackJobTime(messageOrArray, 1); } diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 396146b193c7..32732e45fb6e 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -547,7 +547,9 @@ export class ForkChoice implements IForkChoice { onAttesterSlashing(attesterSlashing: phase0.AttesterSlashing): void { // TODO: we already call in in state-transition, find a way not to recompute it again const intersectingIndices = getAttesterSlashableIndices(attesterSlashing); - intersectingIndices.forEach((validatorIndex) => this.fcStore.equivocatingIndices.add(validatorIndex)); + for (const validatorIndex of intersectingIndices) { + this.fcStore.equivocatingIndices.add(validatorIndex); + } } getLatestMessage(validatorIndex: ValidatorIndex): LatestMessage | undefined { From e4cd53a77f20f2dd135b3d7c598e33b9714cd1a8 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 16 Jan 2024 16:24:31 +0100 Subject: [PATCH 37/70] test: migrate validator tests to vitest (#6301) * Migrate validator tests to vitest * Increase hook timeout for e2e test --- packages/validator/.mocharc.yaml | 6 - packages/validator/.nycrc.json | 3 - packages/validator/package.json | 4 +- .../validator/test/e2e/web3signer.test.ts | 13 +- .../test/unit/services/attestation.test.ts | 97 +++++------- .../unit/services/attestationDuties.test.ts | 103 ++++++------- .../test/unit/services/block.test.ts | 104 ++++++------- .../test/unit/services/blockDuties.test.ts | 69 +++------ .../test/unit/services/doppelganger.test.ts | 6 +- .../test/unit/services/indicesService.test.ts | 28 ++-- .../unit/services/syncCommitteDuties.test.ts | 141 ++++++++---------- .../test/unit/services/syncCommittee.test.ts | 90 +++++------ .../test/unit/services/utils.test.ts | 8 +- .../interchange/index.test.ts | 4 +- .../minMaxSurround/surroundTests.test.ts | 4 +- .../minMaxSurround/updateSpans.test.ts | 4 +- .../unit/slashingProtection/utils.test.ts | 10 +- .../validator/test/unit/utils/batch.test.ts | 4 +- .../validator/test/unit/utils/clock.test.ts | 59 ++++---- .../test/unit/utils/difference.test.ts | 6 +- .../validator/test/unit/utils/format.test.ts | 4 +- .../validator/test/unit/utils/metrics.test.ts | 6 +- .../validator/test/unit/utils/params.test.ts | 4 +- .../test/unit/validatorStore.test.ts | 53 +++---- packages/validator/test/utils/apiStub.ts | 47 +++--- packages/validator/test/utils/types.ts | 5 - 26 files changed, 383 insertions(+), 499 deletions(-) delete mode 100644 packages/validator/.mocharc.yaml delete mode 100644 packages/validator/.nycrc.json diff --git a/packages/validator/.mocharc.yaml b/packages/validator/.mocharc.yaml deleted file mode 100644 index d4114a3f2397..000000000000 --- a/packages/validator/.mocharc.yaml +++ /dev/null @@ -1,6 +0,0 @@ -colors: true -extension: ["ts"] -require: - - ./test/setup.ts -node-option: - - "loader=ts-node/esm" diff --git a/packages/validator/.nycrc.json b/packages/validator/.nycrc.json deleted file mode 100644 index 69aa626339a0..000000000000 --- a/packages/validator/.nycrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../.nycrc.json" -} diff --git a/packages/validator/package.json b/packages/validator/package.json index f46b11332938..14ee1002b214 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -28,10 +28,10 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit/**/*.test.ts'", + "test:unit": "vitest --run --dir test/unit --coverage", "test": "yarn test:unit", "test:spec": "vitest --run --config vitest.config.spec.ts --dir test/spec/", - "test:e2e": "mocha 'test/e2e/**/*.test.ts'", + "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --poolOptions.threads.singleThread true --dir test/e2e", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", "coverage": "codecov -F lodestar-validator", "check-readme": "typescript-docs-verifier" diff --git a/packages/validator/test/e2e/web3signer.test.ts b/packages/validator/test/e2e/web3signer.test.ts index 933e59d800ad..c93f1786dfb4 100644 --- a/packages/validator/test/e2e/web3signer.test.ts +++ b/packages/validator/test/e2e/web3signer.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect, describe, it, vi, beforeAll, afterAll} from "vitest"; import {fromHex, toHex} from "@lodestar/utils"; import {config} from "@lodestar/config/default"; import {computeStartSlotAtEpoch, interopSecretKey, interopSecretKeys} from "@lodestar/state-transition"; @@ -13,7 +13,7 @@ import {IndicesService} from "../../src/services/indices.js"; import {testLogger} from "../utils/logger.js"; describe("web3signer signature test", function () { - this.timeout("60s"); + vi.setConfig({testTimeout: 60_000, hookTimeout: 60_000}); const altairSlot = 2375711; const epoch = 0; @@ -39,7 +39,7 @@ describe("web3signer signature test", function () { pubkey: pubkeyBytes, }; - before("set up validator stores", async () => { + beforeAll(async () => { validatorStoreLocal = await getValidatorStore({type: SignerType.Local, secretKey: secretKey}); const password = "password"; @@ -57,15 +57,16 @@ describe("web3signer signature test", function () { }); }); - after("stop external signer container", async () => { + afterAll(async () => { await externalSigner.container.stop(); }); for (const fork of config.forksAscendingEpochOrder) { - it(`signBlock ${fork.name}`, async function () { + it(`signBlock ${fork.name}`, async ({skip}) => { // Only test till the fork the signer version supports if (ForkSeq[fork.name] > externalSigner.supportedForkSeq) { - this.skip(); + skip(); + return; } const block = ssz[fork.name].BeaconBlock.defaultValue(); diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index 754b9a133ff7..c8010fe1bdf0 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; @@ -14,32 +14,36 @@ import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; import {ZERO_HASH, ZERO_HASH_HEX} from "../../utils/types.js"; +vi.mock("../../../src/services/validatorStore.js"); +vi.mock("../../../src/services/emitter.js"); +vi.mock("../../../src/services/chainHeaderTracker.js"); + describe("AttestationService", function () { - const sandbox = sinon.createSandbox(); - - const api = getApiClientStub(sandbox); - const validatorStore = sinon.createStubInstance(ValidatorStore) as ValidatorStore & - sinon.SinonStubbedInstance; - const emitter = sinon.createStubInstance(ValidatorEventEmitter) as ValidatorEventEmitter & - sinon.SinonStubbedInstance; - const chainHeadTracker = sinon.createStubInstance(ChainHeaderTracker) as ChainHeaderTracker & - sinon.SinonStubbedInstance; + const api = getApiClientStub(); + // @ts-expect-error - Mocked class don't need parameters + const validatorStore = vi.mocked(new ValidatorStore()); + const emitter = vi.mocked(new ValidatorEventEmitter()); + // @ts-expect-error - Mocked class don't need parameters + const chainHeadTracker = vi.mocked(new ChainHeaderTracker()); + let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized - before(() => { + beforeAll(() => { const secretKeys = Array.from({length: 1}, (_, i) => bls.SecretKey.fromBytes(Buffer.alloc(32, i + 1))); pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); - validatorStore.votingPubkeys.returns(pubkeys.map(toHexString)); - validatorStore.hasVotingPubkey.returns(true); - validatorStore.hasSomeValidators.returns(true); - validatorStore.signAttestationSelectionProof.resolves(ZERO_HASH); + validatorStore.votingPubkeys.mockReturnValue(pubkeys.map(toHexString)); + validatorStore.hasVotingPubkey.mockReturnValue(true); + validatorStore.hasSomeValidators.mockReturnValue(true); + validatorStore.signAttestationSelectionProof.mockResolvedValue(ZERO_HASH); }); let controller: AbortController; // To stop clock - beforeEach(() => (controller = new AbortController())); + beforeEach(() => { + controller = new AbortController(); + }); afterEach(() => { controller.abort(); - sandbox.resetHistory(); + vi.resetAllMocks(); }); const testContexts: [string, AttestationServiceOpts][] = [ @@ -49,7 +53,7 @@ describe("AttestationService", function () { ]; for (const [title, opts] of testContexts) { - context(title, () => { + describe(title, () => { it("Should produce, sign, and publish an attestation + aggregate", async () => { const clock = new ClockMock(); const attestationService = new AttestationService( @@ -82,12 +86,12 @@ describe("AttestationService", function () { ]; // Return empty replies to duties service - api.beacon.getStateValidators.resolves({ + api.beacon.getStateValidators.mockResolvedValue({ response: {executionOptimistic: false, data: []}, ok: true, status: HttpStatusCode.OK, }); - api.validator.getAttesterDuties.resolves({ + api.validator.getAttesterDuties.mockResolvedValue({ response: {dependentRoot: ZERO_HASH_HEX, executionOptimistic: false, data: []}, ok: true, status: HttpStatusCode.OK, @@ -98,22 +102,22 @@ describe("AttestationService", function () { // Mock beacon's attestation and aggregates endpoints - api.validator.produceAttestationData.resolves({ + api.validator.produceAttestationData.mockResolvedValue({ response: {data: attestation.data}, ok: true, status: HttpStatusCode.OK, }); - api.validator.getAggregatedAttestation.resolves({ + api.validator.getAggregatedAttestation.mockResolvedValue({ response: {data: attestation}, ok: true, status: HttpStatusCode.OK, }); - api.beacon.submitPoolAttestations.resolves({ + api.beacon.submitPoolAttestations.mockResolvedValue({ response: undefined, ok: true, status: HttpStatusCode.OK, }); - api.validator.publishAggregateAndProofs.resolves({ + api.validator.publishAggregateAndProofs.mockResolvedValue({ response: undefined, ok: true, status: HttpStatusCode.OK, @@ -122,13 +126,13 @@ describe("AttestationService", function () { if (opts.distributedAggregationSelection) { // Mock distributed validator middleware client selections endpoint // and return a selection proof that passes `is_aggregator` test - api.validator.submitBeaconCommitteeSelections.resolves({ + api.validator.submitBeaconCommitteeSelections.mockResolvedValue({ response: {data: [{validatorIndex: 0, slot: 0, selectionProof: Buffer.alloc(1, 0x10)}]}, ok: true, status: HttpStatusCode.OK, }); // Accept all subscriptions - api.validator.prepareBeaconCommitteeSubnet.resolves({ + api.validator.prepareBeaconCommitteeSubnet.mockResolvedValue({ response: undefined, ok: true, status: HttpStatusCode.OK, @@ -136,8 +140,8 @@ describe("AttestationService", function () { } // Mock signing service - validatorStore.signAttestation.resolves(attestation); - validatorStore.signAggregateAndProof.resolves(aggregate); + validatorStore.signAttestation.mockResolvedValue(attestation); + validatorStore.signAggregateAndProof.mockResolvedValue(aggregate); // Trigger clock onSlot for slot 0 await clock.tickSlotFns(0, controller.signal); @@ -149,14 +153,8 @@ describe("AttestationService", function () { slot: 0, selectionProof: ZERO_HASH, }; - expect(api.validator.submitBeaconCommitteeSelections.callCount).to.equal( - 1, - "submitBeaconCommitteeSelections() must be called once" - ); - expect(api.validator.submitBeaconCommitteeSelections.getCall(0).args).to.deep.equal( - [[selection]], // 1 arg, = selection[] - "wrong submitBeaconCommitteeSelections() args" - ); + expect(api.validator.submitBeaconCommitteeSelections).toHaveBeenCalledOnce(); + expect(api.validator.submitBeaconCommitteeSelections).toHaveBeenCalledWith([selection]); // Must resubscribe validator as aggregator on beacon committee subnet const subscription: routes.validator.BeaconCommitteeSubscription = { @@ -166,32 +164,17 @@ describe("AttestationService", function () { slot: 0, isAggregator: true, }; - expect(api.validator.prepareBeaconCommitteeSubnet.callCount).to.equal( - 1, - "prepareBeaconCommitteeSubnet() must be called once" - ); - expect(api.validator.prepareBeaconCommitteeSubnet.getCall(0).args).to.deep.equal( - [[subscription]], // 1 arg, = subscription[] - "wrong prepareBeaconCommitteeSubnet() args" - ); + expect(api.validator.prepareBeaconCommitteeSubnet).toHaveBeenCalledOnce(); + expect(api.validator.prepareBeaconCommitteeSubnet).toHaveBeenCalledWith([subscription]); } // Must submit the attestation received through produceAttestationData() - expect(api.beacon.submitPoolAttestations.callCount).to.equal(1, "submitAttestations() must be called once"); - expect(api.beacon.submitPoolAttestations.getCall(0).args).to.deep.equal( - [[attestation]], // 1 arg, = attestation[] - "wrong submitAttestations() args" - ); + expect(api.beacon.submitPoolAttestations).toHaveBeenCalledOnce(); + expect(api.beacon.submitPoolAttestations).toHaveBeenCalledWith([attestation]); // Must submit the aggregate received through getAggregatedAttestation() then createAndSignAggregateAndProof() - expect(api.validator.publishAggregateAndProofs.callCount).to.equal( - 1, - "publishAggregateAndProofs() must be called once" - ); - expect(api.validator.publishAggregateAndProofs.getCall(0).args).to.deep.equal( - [[aggregate]], // 1 arg, = aggregate[] - "wrong publishAggregateAndProofs() args" - ); + expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledOnce(); + expect(api.validator.publishAggregateAndProofs).toHaveBeenCalledWith([aggregate]); }); }); } diff --git a/packages/validator/test/unit/services/attestationDuties.test.ts b/packages/validator/test/unit/services/attestationDuties.test.ts index 0a4a1b2c2fe9..3edd091d3fcd 100644 --- a/packages/validator/test/unit/services/attestationDuties.test.ts +++ b/packages/validator/test/unit/services/attestationDuties.test.ts @@ -1,6 +1,5 @@ +import {describe, it, expect, beforeAll, vi, Mocked, beforeEach, afterEach} from "vitest"; import {toBufferBE} from "bigint-buffer"; -import {expect} from "chai"; -import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {chainConfig} from "@lodestar/config/default"; @@ -16,14 +15,15 @@ import {initValidatorStore} from "../../utils/validatorStore.js"; import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; +vi.mock("../../../src/services/chainHeaderTracker.js"); + describe("AttestationDutiesService", function () { - const sandbox = sinon.createSandbox(); - const api = getApiClientStub(sandbox); + const api = getApiClientStub(); let validatorStore: ValidatorStore; - const chainHeadTracker = sinon.createStubInstance(ChainHeaderTracker) as ChainHeaderTracker & - sinon.SinonStubbedInstance; + // @ts-expect-error - Mocked class don't need parameters + const chainHeadTracker = new ChainHeaderTracker() as Mocked; let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized // Sample validator @@ -36,14 +36,16 @@ describe("AttestationDutiesService", function () { validator: ssz.phase0.Validator.defaultValue(), }; - before(async () => { + beforeAll(async () => { const secretKeys = [bls.SecretKey.fromBytes(toBufferBE(BigInt(98), 32))]; pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); validatorStore = await initValidatorStore(secretKeys, api, chainConfig); }); let controller: AbortController; // To stop clock - beforeEach(() => (controller = new AbortController())); + beforeEach(() => { + controller = new AbortController(); + }); afterEach(() => controller.abort()); it("Should fetch indexes and duties", async function () { @@ -53,7 +55,7 @@ describe("AttestationDutiesService", function () { index, validator: {...defaultValidator.validator, pubkey: pubkeys[0]}, }; - api.beacon.getStateValidators.resolves({ + api.beacon.getStateValidators.mockResolvedValue({ response: {data: [validatorResponse], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, @@ -71,14 +73,18 @@ describe("AttestationDutiesService", function () { validatorIndex: index, pubkey: pubkeys[0], }; - api.validator.getAttesterDuties.resolves({ + api.validator.getAttesterDuties.mockResolvedValue({ response: {dependentRoot: ZERO_HASH_HEX, data: [duty], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); // Accept all subscriptions - api.validator.prepareBeaconCommitteeSubnet.resolves(); + api.validator.prepareBeaconCommitteeSubnet.mockResolvedValue({ + response: undefined, + ok: true, + status: HttpStatusCode.OK, + }); // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -88,38 +94,24 @@ describe("AttestationDutiesService", function () { await clock.tickEpochFns(0, controller.signal); // Validator index should be persisted - expect(validatorStore.getAllLocalIndices()).to.deep.equal([index], "Wrong local indices"); - expect(validatorStore.getPubkeyOfIndex(index)).equals(toHexString(pubkeys[0]), "Wrong pubkey"); + expect(validatorStore.getAllLocalIndices()).toEqual([index]); + expect(validatorStore.getPubkeyOfIndex(index)).toBe(toHexString(pubkeys[0])); // Duties for this and next epoch should be persisted - expect( - Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(epoch)?.dutiesByIndex || new Map()) - ).to.deep.equal( - { - // Since the ZERO_HASH won't pass the isAggregator test, selectionProof is null - [index]: {duty, selectionProof: null}, - }, - "Wrong dutiesService.attesters Map at current epoch" - ); + expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(epoch)?.dutiesByIndex || new Map())).toEqual({ + // Since the ZERO_HASH won't pass the isAggregator test, selectionProof is null + [index]: {duty, selectionProof: null}, + }); expect( Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(epoch + 1)?.dutiesByIndex || new Map()) - ).to.deep.equal( - { - // Since the ZERO_HASH won't pass the isAggregator test, selectionProof is null - [index]: {duty, selectionProof: null}, - }, - "Wrong dutiesService.attesters Map at next epoch" - ); - - expect(dutiesService.getDutiesAtSlot(slot)).to.deep.equal( - [{duty, selectionProof: null}], - "Wrong getAttestersAtSlot()" - ); - - expect(api.validator.prepareBeaconCommitteeSubnet.callCount).to.equal( - 1, - "prepareBeaconCommitteeSubnet() must be called once after getting the duties" - ); + ).toEqual({ + // Since the ZERO_HASH won't pass the isAggregator test, selectionProof is null + [index]: {duty, selectionProof: null}, + }); + + expect(dutiesService.getDutiesAtSlot(slot)).toEqual([{duty, selectionProof: null}]); + + expect(api.validator.prepareBeaconCommitteeSubnet).toHaveBeenCalledOnce(); }); it("Should remove signer from attestation duties", async function () { @@ -129,7 +121,7 @@ describe("AttestationDutiesService", function () { index, validator: {...defaultValidator.validator, pubkey: pubkeys[0]}, }; - api.beacon.getStateValidators.resolves({ + api.beacon.getStateValidators.mockResolvedValue({ response: {data: [validatorResponse], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, @@ -146,14 +138,18 @@ describe("AttestationDutiesService", function () { validatorIndex: index, pubkey: pubkeys[0], }; - api.validator.getAttesterDuties.resolves({ + api.validator.getAttesterDuties.mockResolvedValue({ response: {data: [duty], dependentRoot: ZERO_HASH_HEX, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); // Accept all subscriptions - api.validator.prepareBeaconCommitteeSubnet.resolves(); + api.validator.prepareBeaconCommitteeSubnet.mockResolvedValue({ + ok: true, + status: HttpStatusCode.OK, + response: undefined, + }); // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -163,23 +159,14 @@ describe("AttestationDutiesService", function () { await clock.tickEpochFns(0, controller.signal); // first confirm duties for this and next epoch should be persisted - expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(0)?.dutiesByIndex || new Map())).to.deep.equal( - { - 4: {duty: duty, selectionProof: null}, - }, - "Wrong dutiesService.attesters Map at current epoch" - ); - expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(1)?.dutiesByIndex || new Map())).to.deep.equal( - { - 4: {duty: duty, selectionProof: null}, - }, - "Wrong dutiesService.attesters Map at current epoch" - ); + expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(0)?.dutiesByIndex || new Map())).toEqual({ + 4: {duty: duty, selectionProof: null}, + }); + expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"].get(1)?.dutiesByIndex || new Map())).toEqual({ + 4: {duty: duty, selectionProof: null}, + }); // then remove dutiesService.removeDutiesForKey(toHexString(pubkeys[0])); - expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"])).to.deep.equal( - {}, - "Wrong dutiesService.attesters Map at current epoch after removal" - ); + expect(Object.fromEntries(dutiesService["dutiesByIndexByEpoch"])).toEqual({}); }); }); diff --git a/packages/validator/test/unit/services/block.test.ts b/packages/validator/test/unit/services/block.test.ts index 3677cdac3a7a..bcfc57eb8674 100644 --- a/packages/validator/test/unit/services/block.test.ts +++ b/packages/validator/test/unit/services/block.test.ts @@ -1,5 +1,4 @@ -import {expect} from "chai"; -import sinon from "sinon"; +import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {createChainForkConfig} from "@lodestar/config"; @@ -15,30 +14,32 @@ import {loggerVc} from "../../utils/logger.js"; import {ClockMock} from "../../utils/clock.js"; import {ZERO_HASH_HEX} from "../../utils/types.js"; -describe("BlockDutiesService", function () { - const sandbox = sinon.createSandbox(); +vi.mock("../../../src/services/validatorStore.js"); - const api = getApiClientStub(sandbox); - const validatorStore = sinon.createStubInstance(ValidatorStore) as ValidatorStore & - sinon.SinonStubbedInstance; +describe("BlockDutiesService", function () { + const api = getApiClientStub(); + // @ts-expect-error - Mocked class don't need parameters + const validatorStore = vi.mocked(new ValidatorStore()); let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized const config = createChainForkConfig(mainnetConfig); - before(() => { + beforeAll(() => { const secretKeys = Array.from({length: 2}, (_, i) => bls.SecretKey.fromBytes(Buffer.alloc(32, i + 1))); pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); - validatorStore.votingPubkeys.returns(pubkeys.map(toHexString)); + validatorStore.votingPubkeys.mockReturnValue(pubkeys.map(toHexString)); }); let controller: AbortController; // To stop clock - beforeEach(() => (controller = new AbortController())); + beforeEach(() => { + controller = new AbortController(); + }); afterEach(() => controller.abort()); it("Should produce, sign, and publish a block", async function () { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: { dependentRoot: ZERO_HASH_HEX, executionOptimistic: false, @@ -57,17 +58,20 @@ describe("BlockDutiesService", function () { }); const signedBlock = ssz.phase0.SignedBeaconBlock.defaultValue(); - validatorStore.signRandao.resolves(signedBlock.message.body.randaoReveal); - validatorStore.signBlock.callsFake(async (_, block) => ({message: block, signature: signedBlock.signature})); - validatorStore.getBuilderSelectionParams.returns({ + validatorStore.signRandao.mockResolvedValue(signedBlock.message.body.randaoReveal); + validatorStore.signBlock.mockImplementation(async (_, block) => ({ + message: block, + signature: signedBlock.signature, + })); + validatorStore.getBuilderSelectionParams.mockReturnValue({ selection: routes.validator.BuilderSelection.MaxProfit, boostFactor: BigInt(100), }); - validatorStore.getGraffiti.returns("aaaa"); - validatorStore.getFeeRecipient.returns("0x00"); - validatorStore.strictFeeRecipientCheck.returns(false); + validatorStore.getGraffiti.mockReturnValue("aaaa"); + validatorStore.getFeeRecipient.mockReturnValue("0x00"); + validatorStore.strictFeeRecipientCheck.mockReturnValue(false); - api.validator.produceBlockV3.resolves({ + api.validator.produceBlockV3.mockResolvedValue({ response: { data: signedBlock.message, version: ForkName.bellatrix, @@ -79,7 +83,7 @@ describe("BlockDutiesService", function () { ok: true, status: HttpStatusCode.OK, }); - api.beacon.publishBlockV2.resolves(); + api.beacon.publishBlockV2.mockResolvedValue({ok: true, status: HttpStatusCode.OK, response: undefined}); // Trigger block production for slot 1 const notifyBlockProductionFn = blockService["dutiesService"]["notifyBlockProductionFn"]; @@ -89,35 +93,32 @@ describe("BlockDutiesService", function () { await sleep(20, controller.signal); // Must have submitted the block received on signBlock() - expect(api.beacon.publishBlockV2.callCount).to.equal(1, "publishBlock() must be called once"); - expect(api.beacon.publishBlockV2.getCall(0).args).to.deep.equal( - [signedBlock, {broadcastValidation: routes.beacon.BroadcastValidation.consensus}], - "wrong publishBlock() args" - ); + expect(api.beacon.publishBlockV2).toHaveBeenCalledOnce(); + expect(api.beacon.publishBlockV2.mock.calls[0]).toEqual([ + signedBlock, + {broadcastValidation: routes.beacon.BroadcastValidation.consensus}, + ]); // ProduceBlockV3 is called with all correct arguments - expect(api.validator.produceBlockV3.getCall(0).args).to.deep.equal( - [ - 1, - signedBlock.message.body.randaoReveal, - "aaaa", - false, - { - feeRecipient: "0x00", - builderSelection: routes.validator.BuilderSelection.MaxProfit, - strictFeeRecipientCheck: false, - blindedLocal: false, - builderBoostFactor: BigInt(100), - }, - ], - "wrong produceBlockV3() args" - ); + expect(api.validator.produceBlockV3.mock.calls[0]).toEqual([ + 1, + signedBlock.message.body.randaoReveal, + "aaaa", + false, + { + feeRecipient: "0x00", + builderSelection: routes.validator.BuilderSelection.MaxProfit, + strictFeeRecipientCheck: false, + blindedLocal: false, + builderBoostFactor: BigInt(100), + }, + ]); }); it("Should produce, sign, and publish a blinded block", async function () { // Reply with some duties const slot = 0; // genesisTime is right now, so test with slot = currentSlot - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: { dependentRoot: ZERO_HASH_HEX, executionOptimistic: false, @@ -136,9 +137,12 @@ describe("BlockDutiesService", function () { }); const signedBlock = ssz.bellatrix.SignedBlindedBeaconBlock.defaultValue(); - validatorStore.signRandao.resolves(signedBlock.message.body.randaoReveal); - validatorStore.signBlock.callsFake(async (_, block) => ({message: block, signature: signedBlock.signature})); - api.validator.produceBlockV3.resolves({ + validatorStore.signRandao.mockResolvedValue(signedBlock.message.body.randaoReveal); + validatorStore.signBlock.mockImplementation(async (_, block) => ({ + message: block, + signature: signedBlock.signature, + })); + api.validator.produceBlockV3.mockResolvedValue({ response: { data: signedBlock.message, version: ForkName.bellatrix, @@ -150,7 +154,7 @@ describe("BlockDutiesService", function () { ok: true, status: HttpStatusCode.OK, }); - api.beacon.publishBlindedBlockV2.resolves(); + api.beacon.publishBlindedBlockV2.mockResolvedValue({ok: true, status: HttpStatusCode.OK, response: undefined}); // Trigger block production for slot 1 const notifyBlockProductionFn = blockService["dutiesService"]["notifyBlockProductionFn"]; @@ -160,10 +164,10 @@ describe("BlockDutiesService", function () { await sleep(20, controller.signal); // Must have submitted the block received on signBlock() - expect(api.beacon.publishBlindedBlockV2.callCount).to.equal(1, "publishBlindedBlockV2() must be called once"); - expect(api.beacon.publishBlindedBlockV2.getCall(0).args).to.deep.equal( - [signedBlock, {broadcastValidation: routes.beacon.BroadcastValidation.consensus}], - "wrong publishBlock() args" - ); + expect(api.beacon.publishBlindedBlockV2).toHaveBeenCalledOnce(); + expect(api.beacon.publishBlindedBlockV2.mock.calls[0]).toEqual([ + signedBlock, + {broadcastValidation: routes.beacon.BroadcastValidation.consensus}, + ]); }); }); diff --git a/packages/validator/test/unit/services/blockDuties.test.ts b/packages/validator/test/unit/services/blockDuties.test.ts index 93540b0c2794..45dd99a80e77 100644 --- a/packages/validator/test/unit/services/blockDuties.test.ts +++ b/packages/validator/test/unit/services/blockDuties.test.ts @@ -1,5 +1,4 @@ -import {expect} from "chai"; -import sinon from "sinon"; +import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; import {toBufferBE} from "bigint-buffer"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; @@ -18,20 +17,20 @@ import {ZERO_HASH_HEX} from "../../utils/types.js"; type ProposerDutiesRes = {dependentRoot: RootHex; data: routes.validator.ProposerDuty[]}; describe("BlockDutiesService", function () { - const sandbox = sinon.createSandbox(); - - const api = getApiClientStub(sandbox); + const api = getApiClientStub(); let validatorStore: ValidatorStore; let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized - before(async () => { + beforeAll(async () => { const secretKeys = Array.from({length: 3}, (_, i) => bls.SecretKey.fromBytes(toBufferBE(BigInt(i + 1), 32))); pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); validatorStore = await initValidatorStore(secretKeys, api); }); let controller: AbortController; // To stop clock - beforeEach(() => (controller = new AbortController())); + beforeEach(() => { + controller = new AbortController(); + }); afterEach(() => controller.abort()); it("Should fetch and persist block duties", async function () { @@ -41,13 +40,13 @@ describe("BlockDutiesService", function () { dependentRoot: ZERO_HASH_HEX, data: [{slot: slot, validatorIndex: 0, pubkey: pubkeys[0]}], }; - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: {...duties, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); - const notifyBlockProductionFn = sinon.stub(); // Returns void + const notifyBlockProductionFn = vi.fn(); // Returns void const clock = new ClockMock(); const dutiesService = new BlockDutiesService( @@ -64,17 +63,11 @@ describe("BlockDutiesService", function () { await clock.tickSlotFns(0, controller.signal); // Duties for this epoch should be persisted - expect(Object.fromEntries(dutiesService["proposers"])).to.deep.equal( - {0: duties}, - "Wrong dutiesService.proposers Map" - ); + expect(Object.fromEntries(dutiesService["proposers"])).toEqual({0: duties}); - expect(dutiesService.getblockProposersAtSlot(slot)).to.deep.equal([pubkeys[0]], "Wrong getblockProposersAtSlot()"); + expect(dutiesService.getblockProposersAtSlot(slot)).toEqual([pubkeys[0]]); - expect(notifyBlockProductionFn.callCount).to.equal( - 1, - "notifyBlockProductionFn() must be called once after getting the duties" - ); + expect(notifyBlockProductionFn).toHaveBeenCalledOnce(); }); it("Should call notifyBlockProductionFn again on duties re-org", async () => { @@ -89,7 +82,7 @@ describe("BlockDutiesService", function () { data: [{slot: 1, validatorIndex: 1, pubkey: pubkeys[1]}], }; - const notifyBlockProductionFn = sinon.stub(); // Returns void + const notifyBlockProductionFn = vi.fn(); // Returns void // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -104,7 +97,7 @@ describe("BlockDutiesService", function () { ); // Trigger clock onSlot for slot 0 - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: {...dutiesBeforeReorg, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, @@ -112,7 +105,7 @@ describe("BlockDutiesService", function () { await clock.tickSlotFns(0, controller.signal); // Trigger clock onSlot for slot 1 - Return different duties for slot 1 - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: {...dutiesAfterReorg, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, @@ -120,24 +113,12 @@ describe("BlockDutiesService", function () { await clock.tickSlotFns(1, controller.signal); // Should persist the dutiesAfterReorg - expect(Object.fromEntries(dutiesService["proposers"])).to.deep.equal( - {0: dutiesAfterReorg}, - "dutiesService.proposers must persist dutiesAfterReorg" - ); + expect(Object.fromEntries(dutiesService["proposers"])).toEqual({0: dutiesAfterReorg}); - expect(notifyBlockProductionFn.callCount).to.equal( - 2, - "Must call notifyBlockProductionFn twice, before and after the re-org" - ); + expect(notifyBlockProductionFn).toBeCalledTimes(2); - expect(notifyBlockProductionFn.getCall(0).args).to.deep.equal( - [1, [pubkeys[0]]], - "First call to notifyBlockProductionFn() before the re-org with pubkey[0]" - ); - expect(notifyBlockProductionFn.getCall(1).args).to.deep.equal( - [1, [pubkeys[1]]], - "Second call to notifyBlockProductionFn() after the re-org with pubkey[1]" - ); + expect(notifyBlockProductionFn.mock.calls[0]).toEqual([1, [pubkeys[0]]]); + expect(notifyBlockProductionFn.mock.calls[1]).toEqual([1, [pubkeys[1]]]); }); it("Should remove signer from duty", async function () { @@ -159,13 +140,13 @@ describe("BlockDutiesService", function () { {slot: 33, validatorIndex: 2, pubkey: pubkeys[2]}, ], }; - api.validator.getProposerDuties.resolves({ + api.validator.getProposerDuties.mockResolvedValue({ response: {...duties, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); - const notifyBlockProductionFn = sinon.stub(); // Returns void + const notifyBlockProductionFn = vi.fn(); // Returns void const clock = new ClockMock(); const dutiesService = new BlockDutiesService( @@ -183,18 +164,12 @@ describe("BlockDutiesService", function () { await clock.tickSlotFns(32, controller.signal); // first confirm the duties for the epochs was persisted - expect(Object.fromEntries(dutiesService["proposers"])).to.deep.equal( - {0: duties, 1: duties}, - "Wrong dutiesService.proposers Map" - ); + expect(Object.fromEntries(dutiesService["proposers"])).toEqual({0: duties, 1: duties}); // then remove a signers public key dutiesService.removeDutiesForKey(toHexString(pubkeys[0])); // confirm that the duties no longer contain the signers public key - expect(Object.fromEntries(dutiesService["proposers"])).to.deep.equal( - {0: dutiesRemoved, 1: dutiesRemoved}, - "Wrong dutiesService.proposers Map" - ); + expect(Object.fromEntries(dutiesService["proposers"])).toEqual({0: dutiesRemoved, 1: dutiesRemoved}); }); }); diff --git a/packages/validator/test/unit/services/doppelganger.test.ts b/packages/validator/test/unit/services/doppelganger.test.ts index f3507be690f6..b3943f619494 100644 --- a/packages/validator/test/unit/services/doppelganger.test.ts +++ b/packages/validator/test/unit/services/doppelganger.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {Epoch, Slot, ValidatorIndex} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; @@ -130,7 +130,7 @@ describe("doppelganger service", () => { // Assert doppelganger status const status = doppelganger.getStatus(pubkeyHex); - expect(status).equal(expectedStatus, `Wrong status at step ${step}`); + expect(status).toBe(expectedStatus); } }); } @@ -172,7 +172,7 @@ describe("doppelganger service", () => { // Assert doppelganger status right away const status = doppelganger.getStatus(pubkeyHex); - expect(status).equal(DoppelgangerStatus.VerifiedSafe); + expect(status).toBe(DoppelgangerStatus.VerifiedSafe); }); }); diff --git a/packages/validator/test/unit/services/indicesService.test.ts b/packages/validator/test/unit/services/indicesService.test.ts index 45ee665eb941..b94ec6fa398a 100644 --- a/packages/validator/test/unit/services/indicesService.test.ts +++ b/packages/validator/test/unit/services/indicesService.test.ts @@ -1,6 +1,5 @@ +import {describe, it, expect, beforeAll} from "vitest"; import {toBufferBE} from "bigint-buffer"; -import {expect} from "chai"; -import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {getApiClientStub} from "../../utils/apiStub.js"; @@ -8,13 +7,12 @@ import {testLogger} from "../../utils/logger.js"; import {IndicesService} from "../../../src/services/indices.js"; describe("IndicesService", function () { - const sandbox = sinon.createSandbox(); const logger = testLogger(); - const api = getApiClientStub(sandbox); + const api = getApiClientStub(); let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized - before(() => { + beforeAll(() => { const secretKeys = [ bls.SecretKey.fromBytes(toBufferBE(BigInt(98), 32)), bls.SecretKey.fromBytes(toBufferBE(BigInt(99), 32)), @@ -39,18 +37,12 @@ describe("IndicesService", function () { // remove pubkey2 indicesService.removeForKey(pubkey2); - expect(Object.fromEntries(indicesService.index2pubkey)).to.deep.equal( - { - "0": `${pubkey1}`, - }, - "Wrong indicesService.index2pubkey Map" - ); - - expect(Object.fromEntries(indicesService.pubkey2index)).to.deep.equal( - { - [`${pubkey1}`]: 0, - }, - "Wrong indicesService.pubkey2index Map" - ); + expect(Object.fromEntries(indicesService.index2pubkey)).toEqual({ + "0": `${pubkey1}`, + }); + + expect(Object.fromEntries(indicesService.pubkey2index)).toEqual({ + [`${pubkey1}`]: 0, + }); }); }); diff --git a/packages/validator/test/unit/services/syncCommitteDuties.test.ts b/packages/validator/test/unit/services/syncCommitteDuties.test.ts index af5734ffdcca..bca0dd67cdc9 100644 --- a/packages/validator/test/unit/services/syncCommitteDuties.test.ts +++ b/packages/validator/test/unit/services/syncCommitteDuties.test.ts @@ -1,6 +1,6 @@ +import {describe, it, expect, beforeAll, beforeEach, afterEach} from "vitest"; +import {when} from "vitest-when"; import {toBufferBE} from "bigint-buffer"; -import {expect} from "chai"; -import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {createChainForkConfig} from "@lodestar/config"; @@ -22,9 +22,7 @@ import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; /* eslint-disable @typescript-eslint/naming-convention */ describe("SyncCommitteeDutiesService", function () { - const sandbox = sinon.createSandbox(); - - const api = getApiClientStub(sandbox); + const api = getApiClientStub(); let validatorStore: ValidatorStore; let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized @@ -43,7 +41,7 @@ describe("SyncCommitteeDutiesService", function () { validator: ssz.phase0.Validator.defaultValue(), }; - before(async () => { + beforeAll(async () => { const secretKeys = [ bls.SecretKey.fromBytes(toBufferBE(BigInt(98), 32)), bls.SecretKey.fromBytes(toBufferBE(BigInt(99), 32)), @@ -61,7 +59,7 @@ describe("SyncCommitteeDutiesService", function () { index: indices[i], validator: {...defaultValidator.validator, pubkey: pubkeys[i]}, })); - api.beacon.getStateValidators.resolves({ + api.beacon.getStateValidators.mockResolvedValue({ response: {data: validatorResponses, executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, @@ -77,14 +75,18 @@ describe("SyncCommitteeDutiesService", function () { validatorIndex: indices[0], validatorSyncCommitteeIndices: [7], }; - api.validator.getSyncCommitteeDuties.resolves({ + api.validator.getSyncCommitteeDuties.mockResolvedValue({ response: {data: [duty], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); // Accept all subscriptions - api.validator.prepareSyncCommitteeSubnets.resolves(); + api.validator.prepareSyncCommitteeSubnets.mockResolvedValue({ + ok: true, + status: HttpStatusCode.OK, + response: undefined, + }); // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -95,9 +97,9 @@ describe("SyncCommitteeDutiesService", function () { // Validator index should be persisted // Validator index should be persisted - expect(validatorStore.getAllLocalIndices()).to.deep.equal(indices, "Wrong local indices"); + expect(validatorStore.getAllLocalIndices()).toEqual(indices); for (let i = 0; i < indices.length; i++) { - expect(validatorStore.getPubkeyOfIndex(indices[i])).equals(toHexString(pubkeys[i]), `Wrong pubkey[${i}]`); + expect(validatorStore.getPubkeyOfIndex(indices[i])).toBe(toHexString(pubkeys[i])); } // Duties for this and next epoch should be persisted @@ -108,25 +110,16 @@ describe("SyncCommitteeDutiesService", function () { ]) ); - expect(dutiesByIndexByPeriodObj).to.deep.equal( - { - 0: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, - 1: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, - } as typeof dutiesByIndexByPeriodObj, - "Wrong dutiesService.dutiesByIndexByPeriod Map" - ); + expect(dutiesByIndexByPeriodObj).toEqual({ + 0: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, + 1: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, + } as typeof dutiesByIndexByPeriodObj); - expect(await dutiesService.getDutiesAtSlot(slot)).to.deep.equal( - [ - {duty: toSyncDutySubnet(duty), selectionProofs: [{selectionProof: null, subcommitteeIndex: 0}]}, - ] as SyncDutyAndProofs[], - "Wrong getAttestersAtSlot()" - ); + expect(await dutiesService.getDutiesAtSlot(slot)).toEqual([ + {duty: toSyncDutySubnet(duty), selectionProofs: [{selectionProof: null, subcommitteeIndex: 0}]}, + ] as SyncDutyAndProofs[]); - expect(api.validator.prepareSyncCommitteeSubnets.callCount).to.equal( - 1, - "prepareSyncCommitteeSubnets() must be called once after getting the duties" - ); + expect(api.validator.prepareSyncCommitteeSubnets).toHaveBeenCalledOnce(); }); /** @@ -139,24 +132,24 @@ describe("SyncCommitteeDutiesService", function () { validatorIndex: indices[0], validatorSyncCommitteeIndices: [7], }; - api.validator.getSyncCommitteeDuties - .withArgs(0, sinon.match.any) - .resolves({response: {data: [duty], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); + when(api.validator.getSyncCommitteeDuties) + .calledWith(0, expect.any(Array)) + .thenResolve({response: {data: [duty], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); // sync period 1 should all return empty - api.validator.getSyncCommitteeDuties - .withArgs(256, sinon.match.any) - .resolves({response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); - api.validator.getSyncCommitteeDuties - .withArgs(257, sinon.match.any) - .resolves({response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); + when(api.validator.getSyncCommitteeDuties) + .calledWith(256, expect.any(Array)) + .thenResolve({response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); + when(api.validator.getSyncCommitteeDuties) + .calledWith(257, expect.any(Array)) + .thenResolve({response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); const duty2: routes.validator.SyncDuty = { pubkey: pubkeys[1], validatorIndex: indices[1], validatorSyncCommitteeIndices: [5], }; - api.validator.getSyncCommitteeDuties - .withArgs(1, sinon.match.any) - .resolves({response: {data: [duty2], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); + when(api.validator.getSyncCommitteeDuties) + .calledWith(1, expect.any(Array)) + .thenResolve({response: {data: [duty2], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -172,13 +165,10 @@ describe("SyncCommitteeDutiesService", function () { Object.fromEntries(dutiesByIndex), ]) ); - expect(dutiesByIndexByPeriodObj).to.deep.equal( - { - 0: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, - 1: {}, - } as typeof dutiesByIndexByPeriodObj, - "Wrong dutiesService.dutiesByIndexByPeriod Map" - ); + expect(dutiesByIndexByPeriodObj).toEqual({ + 0: {[indices[0]]: {duty: toSyncDutySubnet(duty)}}, + 1: {}, + } as typeof dutiesByIndexByPeriodObj); await clock.tickEpochFns(1, controller.signal); @@ -188,13 +178,10 @@ describe("SyncCommitteeDutiesService", function () { Object.fromEntries(dutiesByIndex), ]) ); - expect(dutiesByIndexByPeriodObj).to.deep.equal( - { - 0: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, - 1: {}, - } as typeof dutiesByIndexByPeriodObj, - "Wrong dutiesService.dutiesByIndexByPeriod Map" - ); + expect(dutiesByIndexByPeriodObj).toEqual({ + 0: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, + 1: {}, + } as typeof dutiesByIndexByPeriodObj); }); it("Should remove signer from sync committee duties", async function () { @@ -209,12 +196,16 @@ describe("SyncCommitteeDutiesService", function () { validatorIndex: indices[1], validatorSyncCommitteeIndices: [7], }; - api.validator.getSyncCommitteeDuties - .withArgs(sinon.match.any, sinon.match.any) - .resolves({response: {data: [duty1, duty2], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); + when(api.validator.getSyncCommitteeDuties) + .calledWith(expect.any(Number), expect.any(Array)) + .thenResolve({response: {data: [duty1, duty2], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK}); // Accept all subscriptions - api.validator.prepareSyncCommitteeSubnets.resolves(); + api.validator.prepareSyncCommitteeSubnets.mockResolvedValue({ + ok: true, + status: HttpStatusCode.OK, + response: undefined, + }); // Clock will call runAttesterDutiesTasks() immediately const clock = new ClockMock(); @@ -231,19 +222,16 @@ describe("SyncCommitteeDutiesService", function () { ]) ); - expect(dutiesByIndexByPeriodObj).to.deep.equal( - { - 0: { - [indices[0]]: {duty: toSyncDutySubnet(duty1)}, - [indices[1]]: {duty: toSyncDutySubnet(duty2)}, - }, - 1: { - [indices[0]]: {duty: toSyncDutySubnet(duty1)}, - [indices[1]]: {duty: toSyncDutySubnet(duty2)}, - }, - } as typeof dutiesByIndexByPeriodObj, - "Wrong dutiesService.dutiesByIndexByPeriod Map" - ); + expect(dutiesByIndexByPeriodObj).toEqual({ + 0: { + [indices[0]]: {duty: toSyncDutySubnet(duty1)}, + [indices[1]]: {duty: toSyncDutySubnet(duty2)}, + }, + 1: { + [indices[0]]: {duty: toSyncDutySubnet(duty1)}, + [indices[1]]: {duty: toSyncDutySubnet(duty2)}, + }, + } as typeof dutiesByIndexByPeriodObj); // then remove signer with pubkeys[0] dutiesService.removeDutiesForKey(toHexString(pubkeys[0])); @@ -254,13 +242,10 @@ describe("SyncCommitteeDutiesService", function () { Object.fromEntries(dutiesByIndex), ]) ); - expect(dutiesByIndexByPeriodObjAfterRemoval).to.deep.equal( - { - 0: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, - 1: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, - } as typeof dutiesByIndexByPeriodObjAfterRemoval, - "Wrong dutiesService.dutiesByIndexByPeriod Map" - ); + expect(dutiesByIndexByPeriodObjAfterRemoval).toEqual({ + 0: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, + 1: {[indices[1]]: {duty: toSyncDutySubnet(duty2)}}, + } as typeof dutiesByIndexByPeriodObjAfterRemoval); }); }); diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 9316f11eb483..20697f651ca9 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -1,5 +1,4 @@ -import {expect} from "chai"; -import sinon from "sinon"; +import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {createChainForkConfig} from "@lodestar/config"; @@ -16,18 +15,19 @@ import {ChainHeaderTracker} from "../../../src/services/chainHeaderTracker.js"; import {ZERO_HASH} from "../../utils/types.js"; import {ValidatorEventEmitter} from "../../../src/services/emitter.js"; +vi.mock("../../../src/services/validatorStore.js"); +vi.mock("../../../src/services/emitter.js"); +vi.mock("../../../src/services/chainHeaderTracker.js"); + /* eslint-disable @typescript-eslint/naming-convention */ describe("SyncCommitteeService", function () { - const sandbox = sinon.createSandbox(); - - const api = getApiClientStub(sandbox); - const validatorStore = sinon.createStubInstance(ValidatorStore) as ValidatorStore & - sinon.SinonStubbedInstance; - const emitter = sinon.createStubInstance(ValidatorEventEmitter) as ValidatorEventEmitter & - sinon.SinonStubbedInstance; - const chainHeaderTracker = sinon.createStubInstance(ChainHeaderTracker) as ChainHeaderTracker & - sinon.SinonStubbedInstance; + const api = getApiClientStub(); + // @ts-expect-error - Mocked class don't need parameters + const validatorStore = vi.mocked(new ValidatorStore()); + const emitter = vi.mocked(new ValidatorEventEmitter()); + // @ts-expect-error - Mocked class don't need parameters + const chainHeaderTracker = vi.mocked(new ChainHeaderTracker()); let pubkeys: Uint8Array[]; // Initialize pubkeys in before() so bls is already initialized const config = createChainForkConfig({ @@ -36,20 +36,22 @@ describe("SyncCommitteeService", function () { ALTAIR_FORK_EPOCH: 0, // Activate Altair immediately }); - before(() => { + beforeAll(() => { const secretKeys = Array.from({length: 1}, (_, i) => bls.SecretKey.fromBytes(Buffer.alloc(32, i + 1))); pubkeys = secretKeys.map((sk) => sk.toPublicKey().toBytes()); - validatorStore.votingPubkeys.returns(pubkeys.map(toHexString)); - validatorStore.hasVotingPubkey.returns(true); - validatorStore.hasSomeValidators.returns(true); - validatorStore.signAttestationSelectionProof.resolves(ZERO_HASH); + validatorStore.votingPubkeys.mockReturnValue(pubkeys.map(toHexString)); + validatorStore.hasVotingPubkey.mockReturnValue(true); + validatorStore.hasSomeValidators.mockReturnValue(true); + validatorStore.signAttestationSelectionProof.mockResolvedValue(ZERO_HASH); }); let controller: AbortController; // To stop clock - beforeEach(() => (controller = new AbortController())); + beforeEach(() => { + controller = new AbortController(); + }); afterEach(() => { controller.abort(); - sandbox.resetHistory(); + vi.resetAllMocks(); }); const testContexts: [string, SyncCommitteeServiceOpts][] = [ @@ -58,7 +60,7 @@ describe("SyncCommitteeService", function () { ]; for (const [title, opts] of testContexts) { - context(title, () => { + describe(title, () => { it("Should produce, sign, and publish a sync committee + contribution", async () => { const clock = new ClockMock(); const syncCommitteeService = new SyncCommitteeService( @@ -95,34 +97,34 @@ describe("SyncCommitteeService", function () { ]; // Return empty replies to duties service - api.beacon.getStateValidators.resolves({ + api.beacon.getStateValidators.mockResolvedValue({ response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); - api.validator.getSyncCommitteeDuties.resolves({ + api.validator.getSyncCommitteeDuties.mockResolvedValue({ response: {data: [], executionOptimistic: false}, ok: true, status: HttpStatusCode.OK, }); // Mock duties service to return some duties directly - syncCommitteeService["dutiesService"].getDutiesAtSlot = sinon.stub().returns(duties); + syncCommitteeService["dutiesService"].getDutiesAtSlot = vi.fn().mockReturnValue(duties); // Mock beacon's sync committee and contribution routes - chainHeaderTracker.getCurrentChainHead.returns(beaconBlockRoot); - api.beacon.submitPoolSyncCommitteeSignatures.resolves({ + chainHeaderTracker.getCurrentChainHead.mockReturnValue(beaconBlockRoot); + api.beacon.submitPoolSyncCommitteeSignatures.mockResolvedValue({ response: undefined, ok: true, status: HttpStatusCode.OK, }); - api.validator.produceSyncCommitteeContribution.resolves({ + api.validator.produceSyncCommitteeContribution.mockResolvedValue({ response: {data: contribution}, ok: true, status: HttpStatusCode.OK, }); - api.validator.publishContributionAndProofs.resolves({ + api.validator.publishContributionAndProofs.mockResolvedValue({ response: undefined, ok: true, status: HttpStatusCode.OK, @@ -131,7 +133,7 @@ describe("SyncCommitteeService", function () { if (opts.distributedAggregationSelection) { // Mock distributed validator middleware client selections endpoint // and return a selection proof that passes `is_sync_committee_aggregator` test - api.validator.submitSyncCommitteeSelections.resolves({ + api.validator.submitSyncCommitteeSelections.mockResolvedValue({ response: { data: [{validatorIndex: 0, slot: 0, subcommitteeIndex: 0, selectionProof: Buffer.alloc(1, 0x19)}], }, @@ -141,8 +143,8 @@ describe("SyncCommitteeService", function () { } // Mock signing service - validatorStore.signSyncCommitteeSignature.resolves(syncCommitteeSignature); - validatorStore.signContributionAndProof.resolves(contributionAndProof); + validatorStore.signSyncCommitteeSignature.mockResolvedValue(syncCommitteeSignature); + validatorStore.signContributionAndProof.mockResolvedValue(contributionAndProof); // Trigger clock onSlot for slot 0 await clock.tickSlotFns(0, controller.signal); @@ -155,35 +157,17 @@ describe("SyncCommitteeService", function () { subcommitteeIndex: 0, selectionProof: ZERO_HASH, }; - expect(api.validator.submitSyncCommitteeSelections.callCount).to.equal( - 1, - "submitSyncCommitteeSelections() must be called once" - ); - expect(api.validator.submitSyncCommitteeSelections.getCall(0).args).to.deep.equal( - [[selection]], // 1 arg, = selection[] - "wrong submitSyncCommitteeSelections() args" - ); + expect(api.validator.submitSyncCommitteeSelections).toHaveBeenCalledOnce(); + expect(api.validator.submitSyncCommitteeSelections).toHaveBeenCalledWith([selection]); } // Must submit the signature received through signSyncCommitteeSignature() - expect(api.beacon.submitPoolSyncCommitteeSignatures.callCount).to.equal( - 1, - "submitPoolSyncCommitteeSignatures() must be called once" - ); - expect(api.beacon.submitPoolSyncCommitteeSignatures.getCall(0).args).to.deep.equal( - [[syncCommitteeSignature]], // 1 arg, = syncCommitteeSignature[] - "wrong submitPoolSyncCommitteeSignatures() args" - ); + expect(api.beacon.submitPoolSyncCommitteeSignatures).toHaveBeenCalledOnce(); + expect(api.beacon.submitPoolSyncCommitteeSignatures).toHaveBeenCalledWith([syncCommitteeSignature]); // Must submit the aggregate received through produceSyncCommitteeContribution() then signContributionAndProof() - expect(api.validator.publishContributionAndProofs.callCount).to.equal( - 1, - "publishContributionAndProofs() must be called once" - ); - expect(api.validator.publishContributionAndProofs.getCall(0).args).to.deep.equal( - [[contributionAndProof]], // 1 arg, = contributionAndProof[] - "wrong publishContributionAndProofs() args" - ); + expect(api.validator.publishContributionAndProofs).toHaveBeenCalledOnce(); + expect(api.validator.publishContributionAndProofs).toHaveBeenCalledWith([contributionAndProof]); }); }); } diff --git a/packages/validator/test/unit/services/utils.test.ts b/packages/validator/test/unit/services/utils.test.ts index 43f160ab226d..f4bb9e57cd04 100644 --- a/packages/validator/test/unit/services/utils.test.ts +++ b/packages/validator/test/unit/services/utils.test.ts @@ -1,10 +1,10 @@ -import {expect} from "chai"; +import {describe, it, expect, beforeAll} from "vitest"; import {SYNC_COMMITTEE_SUBNET_SIZE} from "@lodestar/params"; import {syncCommitteeIndicesToSubnets} from "../../../src/services/utils.js"; describe("services / utils / syncCommitteeIndicesToSubnets", () => { - before("Check SYNC_COMMITTEE_SUBNET_SIZE", () => { - expect(SYNC_COMMITTEE_SUBNET_SIZE).equals(128); + beforeAll(() => { + expect(SYNC_COMMITTEE_SUBNET_SIZE).toBe(128); }); const testCases: {indexes: number[]; subnets: number[]}[] = [ @@ -19,7 +19,7 @@ describe("services / utils / syncCommitteeIndicesToSubnets", () => { for (const {indexes, subnets} of testCases) { it(indexes.join(","), () => { - expect(syncCommitteeIndicesToSubnets(indexes)).deep.equals(subnets); + expect(syncCommitteeIndicesToSubnets(indexes)).toEqual(subnets); }); } }); diff --git a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts index 95137e7d0b71..af2694458368 100644 --- a/packages/validator/test/unit/slashingProtection/interchange/index.test.ts +++ b/packages/validator/test/unit/slashingProtection/interchange/index.test.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {toHexString} from "@chainsafe/ssz"; import {Root, ssz} from "@lodestar/types"; import { @@ -29,6 +29,6 @@ describe("interchange", () => { const interchangeLodestar = parseInterchange(interchange, expectedGenesisValidatorsRoot); const serializedInterchange = serializeInterchange(interchangeLodestar, {format: "complete", version: "4"}); // Stringify and parse to simulate writing and reading. It ignores undefined values - expect(JSON.parse(JSON.stringify(serializedInterchange))).to.deep.equal(interchange); + expect(JSON.parse(JSON.stringify(serializedInterchange))).toEqual(interchange); }); }); diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts index 280404c7f913..6bdc49fb7f0c 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/surroundTests.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import { MinMaxSurround, MinMaxSurroundAttestation, @@ -204,7 +204,7 @@ describe("surroundTests", () => { } catch (e) { if (e instanceof SurroundAttestationError) { if (slashableEpoch !== undefined) { - expect(e.type.attestation2Target).to.equal(slashableEpoch, "Wrong slashableEpoch"); + expect(e.type.attestation2Target).toBe(slashableEpoch); } } else { throw Error(`Wrong error type: ${(e as Error).stack}`); diff --git a/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts b/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts index dd370325a101..62f1ea5e1b4f 100644 --- a/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts +++ b/packages/validator/test/unit/slashingProtection/minMaxSurround/updateSpans.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {MinMaxSurroundAttestation, MinMaxSurround} from "../../../../src/slashingProtection/minMaxSurround/index.js"; import {DistanceStoreMemory, storeToSpansPerEpoch, emptyPubkey} from "./utils.js"; @@ -39,7 +39,7 @@ describe("Update spans test", () => { await minMaxSurround.insertAttestation(emptyPubkey, att); const spansByEpochResult = await storeToSpansPerEpoch(store); - expect(spansByEpochResult).to.deep.equal(spansByEpoch); + expect(spansByEpochResult).toEqual(spansByEpoch); }); } }); diff --git a/packages/validator/test/unit/slashingProtection/utils.test.ts b/packages/validator/test/unit/slashingProtection/utils.test.ts index a77f2961f219..2e0e4859436d 100644 --- a/packages/validator/test/unit/slashingProtection/utils.test.ts +++ b/packages/validator/test/unit/slashingProtection/utils.test.ts @@ -1,20 +1,20 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {minEpoch} from "../../../src/slashingProtection/utils.js"; describe("slashingProtection / utils / minEpoch", () => { it("should return the minimum epoch from an array of epochs", () => { - expect(minEpoch([15, 10, 20, 30, 5, 1, 50])).to.equal(1); + expect(minEpoch([15, 10, 20, 30, 5, 1, 50])).toBe(1); }); it("should return the only epoch if epochs array only contains one element", () => { - expect(minEpoch([10])).to.equal(10); + expect(minEpoch([10])).toBe(10); }); it("should return null if epochs array is empty", () => { - expect(minEpoch([])).to.equal(null); + expect(minEpoch([])).toBe(null); }); it("should not throw 'RangeError: Maximum call stack size exceeded' for huge epoch arrays", () => { - expect(() => minEpoch(Array.from({length: 1e6}, (_, index) => index))).to.not.throw(RangeError); + expect(() => minEpoch(Array.from({length: 1e6}, (_, index) => index))).not.toThrow(RangeError); }); }); diff --git a/packages/validator/test/unit/utils/batch.test.ts b/packages/validator/test/unit/utils/batch.test.ts index c34486a17a27..821d27c1a43a 100644 --- a/packages/validator/test/unit/utils/batch.test.ts +++ b/packages/validator/test/unit/utils/batch.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {batchItems} from "../../../src/util/index.js"; describe("util / batch", function () { @@ -36,7 +36,7 @@ describe("util / batch", function () { for (const {items: pubkeys, expected} of testCases) { it(`Batch ${pubkeys.length} items`, () => { - expect(batchItems(pubkeys, {batchSize: 2, maxBatches: 3})).to.deep.equal(expected); + expect(batchItems(pubkeys, {batchSize: 2, maxBatches: 3})).toEqual(expected); }); } }); diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts index 5194a5e4f942..8bb12e6ef8ae 100644 --- a/packages/validator/test/unit/utils/clock.test.ts +++ b/packages/validator/test/unit/utils/clock.test.ts @@ -1,5 +1,4 @@ -import sinon from "sinon"; -import {expect} from "chai"; +import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {config} from "@lodestar/config/default"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; @@ -9,54 +8,54 @@ import {testLogger} from "../../utils/logger.js"; describe("util / Clock", function () { const logger = testLogger(); let controller: AbortController; - let fakeClock: sinon.SinonFakeTimers; beforeEach(() => { controller = new AbortController(); - fakeClock = sinon.useFakeTimers(); + vi.useFakeTimers(); }); + afterEach(() => { controller.abort(); - fakeClock.restore(); + vi.useRealTimers(); }); it("Should call on slot", async () => { const genesisTime = Math.floor(Date.now() / 1000) - config.SECONDS_PER_SLOT / 2; const clock = new Clock(config, logger, {genesisTime}); - const onSlot = sinon.stub().resolves(); + const onSlot = vi.fn().mockResolvedValue(undefined); clock.runEverySlot(onSlot); clock.start(controller.signal); // Must run once immediately - expect(onSlot.callCount).to.equal(1, "runEverySlot(cb) must be called immediately"); - expect(onSlot.getCall(0).args[0]).to.equal(0, "Wrong arg on runEverySlot(cb) call 0"); + expect(onSlot).toHaveBeenCalledOnce(); + expect(onSlot).toHaveBeenNthCalledWith(1, 0, expect.any(AbortSignal)); - await fakeClock.tickAsync(config.SECONDS_PER_SLOT * 1000); - expect(onSlot.callCount).to.equal(2, "runEverySlot(cb) must be called after after slot 1"); - expect(onSlot.getCall(1).args[0]).to.equal(1, "Wrong arg on runEverySlot(cb) call 1"); + await vi.advanceTimersByTimeAsync(config.SECONDS_PER_SLOT * 1000); + expect(onSlot).toHaveBeenCalledTimes(2); + expect(onSlot).toHaveBeenNthCalledWith(2, 1, expect.any(AbortSignal)); - await fakeClock.tickAsync(config.SECONDS_PER_SLOT * 1000); - expect(onSlot.callCount).to.equal(3, "runEverySlot(cb) must be called again after slot 2"); - expect(onSlot.getCall(2).args[0]).to.equal(2, "Wrong arg on runEverySlot(cb) call 2"); + await vi.advanceTimersByTimeAsync(config.SECONDS_PER_SLOT * 1000); + expect(onSlot).toHaveBeenCalledTimes(3); + expect(onSlot).toHaveBeenNthCalledWith(3, 2, expect.any(AbortSignal)); }); it("Should stop calling on slot after stop()", async () => { const genesisTime = Math.floor(Date.now() / 1000) - config.SECONDS_PER_SLOT / 2; const clock = new Clock(config, logger, {genesisTime}); - const onSlot = sinon.stub().resolves(); + const onSlot = vi.fn().mockResolvedValue(undefined); clock.runEverySlot(onSlot); clock.start(controller.signal); - await fakeClock.tickAsync(config.SECONDS_PER_SLOT * 1000); - expect(onSlot.callCount).to.equal(2, "runEverySlot(cb) must be called after after slot 1"); - expect(onSlot.getCall(1).args[0]).to.equal(1, "Wrong arg on runEverySlot(cb) call 1"); + await vi.advanceTimersByTimeAsync(config.SECONDS_PER_SLOT * 1000); + expect(onSlot).toBeCalledTimes(2); + expect(onSlot).toHaveBeenNthCalledWith(2, 1, expect.any(AbortSignal)); // Stop clock controller.abort(); - await fakeClock.tickAsync(config.SECONDS_PER_SLOT * 1000); - expect(onSlot.callCount).to.equal(2, "runEverySlot(cb) should not be called again"); + await vi.advanceTimersByTimeAsync(config.SECONDS_PER_SLOT * 1000); + expect(onSlot).toBeCalledTimes(2); }); it("Should call on epoch", async () => { @@ -65,20 +64,20 @@ describe("util / Clock", function () { const clock = new Clock(config, logger, {genesisTime}); - const onEpoch = sinon.stub().resolves(); + const onEpoch = vi.fn().mockResolvedValue(undefined); clock.runEveryEpoch(onEpoch); clock.start(controller.signal); // Must run once immediately - expect(onEpoch.callCount).to.equal(1, "runEverySlot(cb) must be called immediately"); - expect(onEpoch.getCall(0).args[0]).to.equal(0, "Wrong arg on runEverySlot(cb) call 0"); + expect(onEpoch).toHaveBeenCalledOnce(); + expect(onEpoch).toHaveBeenCalledWith(0, expect.any(AbortSignal)); - await fakeClock.tickAsync(config.SECONDS_PER_SLOT * 1000); - expect(onEpoch.callCount).to.equal(1, "runEverySlot(cb) must not be called again after a slot"); + await vi.advanceTimersByTimeAsync(config.SECONDS_PER_SLOT * 1000); + expect(onEpoch).toHaveBeenCalledOnce(); - await fakeClock.tickAsync(SLOTS_PER_EPOCH * config.SECONDS_PER_SLOT * 1000); - expect(onEpoch.callCount).to.equal(2, "runEverySlot(cb) must be called again after an epoch"); - expect(onEpoch.getCall(1).args[0]).to.equal(1, "Wrong arg on runEverySlot(cb) call 1"); + await vi.advanceTimersByTimeAsync(SLOTS_PER_EPOCH * config.SECONDS_PER_SLOT * 1000); + expect(onEpoch).toHaveBeenCalledTimes(2); + expect(onEpoch).toHaveBeenNthCalledWith(2, 1, expect.any(AbortSignal)); }); describe("getCurrentSlot", function () { @@ -93,8 +92,8 @@ describe("util / Clock", function () { for (const {name, delta} of testCase) { it(name, async function () { const currentSlot = getCurrentSlotAround(testConfig, genesisTime); - fakeClock.tick(delta * 1000); - expect(getCurrentSlotAround(testConfig, genesisTime)).to.be.equal(currentSlot + 1, name); + vi.advanceTimersByTime(delta * 1000); + expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1); }); } }); diff --git a/packages/validator/test/unit/utils/difference.test.ts b/packages/validator/test/unit/utils/difference.test.ts index 9d35a39b1fdf..023a6144877a 100644 --- a/packages/validator/test/unit/utils/difference.test.ts +++ b/packages/validator/test/unit/utils/difference.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {differenceHex} from "../../../src/util/difference.js"; describe("utils / differenceHex", () => { @@ -9,11 +9,11 @@ describe("utils / differenceHex", () => { it("Return new hex items", () => { const additionalRoots = differenceHex([root0, root1a], [root1b, root2]); - expect(additionalRoots).to.deep.equal([root2]); + expect(additionalRoots).toEqual([root2]); }); it("Return no new hex items", () => { const additionalRoots = differenceHex([root0, root1a], [root1b]); - expect(additionalRoots).to.deep.equal([]); + expect(additionalRoots).toEqual([]); }); }); diff --git a/packages/validator/test/unit/utils/format.test.ts b/packages/validator/test/unit/utils/format.test.ts index 84139f5fd51e..ab75c8fa1b72 100644 --- a/packages/validator/test/unit/utils/format.test.ts +++ b/packages/validator/test/unit/utils/format.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {formatBigDecimal} from "../../../src/util/format.js"; describe("util / formatBigDecimal", function () { @@ -15,7 +15,7 @@ describe("util / formatBigDecimal", function () { ]; for (const [numerator, denominator, decimalFactor, expectedString] of testCases) { it(`format ${numerator} / ${denominator} correctly to ${expectedString}`, () => { - expect(formatBigDecimal(numerator, denominator, decimalFactor)).to.be.equal(expectedString); + expect(formatBigDecimal(numerator, denominator, decimalFactor)).toBe(expectedString); }); } }); diff --git a/packages/validator/test/unit/utils/metrics.test.ts b/packages/validator/test/unit/utils/metrics.test.ts index cf3ebc960ad5..695e8731b7f6 100644 --- a/packages/validator/test/unit/utils/metrics.test.ts +++ b/packages/validator/test/unit/utils/metrics.test.ts @@ -1,10 +1,8 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {BeaconHealth, renderEnumNumeric} from "../../../src/metrics.js"; describe("renderEnumNumeric", () => { it("BeaconHealth", () => { - expect(renderEnumNumeric(BeaconHealth)).equals( - "READY=0, SYNCING=1, NOT_INITIALIZED_OR_ISSUES=2, UNKNOWN=3, ERROR=4" - ); + expect(renderEnumNumeric(BeaconHealth)).toBe("READY=0, SYNCING=1, NOT_INITIALIZED_OR_ISSUES=2, UNKNOWN=3, ERROR=4"); }); }); diff --git a/packages/validator/test/unit/utils/params.test.ts b/packages/validator/test/unit/utils/params.test.ts index 10e814e4d501..47b743e0ce5e 100644 --- a/packages/validator/test/unit/utils/params.test.ts +++ b/packages/validator/test/unit/utils/params.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {chainConfigToJson, ChainConfig} from "@lodestar/config"; import {chainConfig} from "@lodestar/config/default"; import {networksChainConfig} from "@lodestar/config/networks"; @@ -28,7 +28,7 @@ describe("utils / params / assertEqualParams", () => { // Force ALTAIR_FORK_EPOCH value to be different const otherConfig = {...chainConfigJson, ALTAIR_FORK_EPOCH: String(ALTAIR_FORK_EPOCH + 1)}; - expect(() => assertEqualParams(localConfig, otherConfig)).to.throw(NotEqualParamsError); + expect(() => assertEqualParams(localConfig, otherConfig)).toThrow(NotEqualParamsError); }); it("should fill missing remote values with default and be equal", () => { diff --git a/packages/validator/test/unit/validatorStore.test.ts b/packages/validator/test/unit/validatorStore.test.ts index 37cae9c2b558..3f7f0792f378 100644 --- a/packages/validator/test/unit/validatorStore.test.ts +++ b/packages/validator/test/unit/validatorStore.test.ts @@ -1,6 +1,5 @@ +import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {toBufferBE} from "bigint-buffer"; -import {expect} from "chai"; -import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString, fromHexString} from "@chainsafe/ssz"; import {chainConfig} from "@lodestar/config/default"; @@ -11,18 +10,15 @@ import {ValidatorStore} from "../../src/services/validatorStore.js"; import {getApiClientStub} from "../utils/apiStub.js"; import {initValidatorStore} from "../utils/validatorStore.js"; import {ValidatorProposerConfig} from "../../src/services/validatorStore.js"; -import {SinonStubFn} from "..//utils/types.js"; describe("ValidatorStore", function () { - const sandbox = sinon.createSandbox(); - const api = getApiClientStub(sandbox); + const api = getApiClientStub(); let validatorStore: ValidatorStore; let valProposerConfig: ValidatorProposerConfig; - let signValidatorStub: SinonStubFn; - before(async () => { + beforeEach(async () => { valProposerConfig = { proposerConfig: { [toHexString(pubkeys[0])]: { @@ -46,43 +42,37 @@ describe("ValidatorStore", function () { }; validatorStore = await initValidatorStore(secretKeys, api, chainConfig, valProposerConfig); - signValidatorStub = sinon.stub(validatorStore, "signValidatorRegistration"); }); - after(() => { - sandbox.restore(); + afterEach(() => { + vi.resetAllMocks(); }); it("Should validate graffiti,feeRecipient etc. from valProposerConfig and ValidatorStore", async function () { //pubkeys[0] values - expect(validatorStore.getGraffiti(toHexString(pubkeys[0]))).to.be.equal( + expect(validatorStore.getGraffiti(toHexString(pubkeys[0]))).toBe( valProposerConfig.proposerConfig[toHexString(pubkeys[0])].graffiti ); - expect(validatorStore.getFeeRecipient(toHexString(pubkeys[0]))).to.be.equal( + expect(validatorStore.getFeeRecipient(toHexString(pubkeys[0]))).toBe( valProposerConfig.proposerConfig[toHexString(pubkeys[0])].feeRecipient ); - expect(validatorStore.strictFeeRecipientCheck(toHexString(pubkeys[0]))).to.be.equal( + expect(validatorStore.strictFeeRecipientCheck(toHexString(pubkeys[0]))).toBe( valProposerConfig.proposerConfig[toHexString(pubkeys[0])].strictFeeRecipientCheck ); - expect(validatorStore.getGasLimit(toHexString(pubkeys[0]))).to.be.equal( + expect(validatorStore.getGasLimit(toHexString(pubkeys[0]))).toBe( valProposerConfig.proposerConfig[toHexString(pubkeys[0])].builder?.gasLimit ); // default values - expect(validatorStore.getGraffiti(toHexString(pubkeys[1]))).to.be.equal(valProposerConfig.defaultConfig.graffiti); - expect(validatorStore.getFeeRecipient(toHexString(pubkeys[1]))).to.be.equal( - valProposerConfig.defaultConfig.feeRecipient - ); - expect(validatorStore.strictFeeRecipientCheck(toHexString(pubkeys[1]))).to.be.equal( + expect(validatorStore.getGraffiti(toHexString(pubkeys[1]))).toBe(valProposerConfig.defaultConfig.graffiti); + expect(validatorStore.getFeeRecipient(toHexString(pubkeys[1]))).toBe(valProposerConfig.defaultConfig.feeRecipient); + expect(validatorStore.strictFeeRecipientCheck(toHexString(pubkeys[1]))).toBe( valProposerConfig.defaultConfig.strictFeeRecipientCheck ); - expect(validatorStore.getGasLimit(toHexString(pubkeys[1]))).to.be.equal( - valProposerConfig.defaultConfig.builder?.gasLimit - ); + expect(validatorStore.getGasLimit(toHexString(pubkeys[1]))).toBe(valProposerConfig.defaultConfig.builder?.gasLimit); }); it("Should create/update builder data and return from cache next time", async () => { - let signCallCount = 0; let slot = 0; const testCases: [bellatrix.SignedValidatorRegistrationV1, string, number][] = [ [valRegF00G100, "0x00", 100], @@ -90,19 +80,14 @@ describe("ValidatorStore", function () { [valRegF10G200, "0x10", 200], ]; for (const [valReg, feeRecipient, gasLimit] of testCases) { - signValidatorStub.resolves(valReg); + vi.spyOn(validatorStore, "signValidatorRegistration").mockResolvedValue(valReg); + const val1 = await validatorStore.getValidatorRegistration(pubkeys[0], {feeRecipient, gasLimit}, slot++); - expect(JSON.stringify(val1)).to.be.eql(JSON.stringify(valReg)); - expect(signValidatorStub.callCount).to.equal( - ++signCallCount, - `signValidatorRegistration() must be updated for new feeRecipient=${feeRecipient} gasLimit=${gasLimit} combo ` - ); + expect(JSON.stringify(val1)).toEqual(JSON.stringify(valReg)); + expect(validatorStore.signValidatorRegistration).toHaveBeenCalledOnce(); const val2 = await validatorStore.getValidatorRegistration(pubkeys[0], {feeRecipient, gasLimit}, slot++); - expect(JSON.stringify(val2)).to.be.eql(JSON.stringify(valReg)); - expect(signValidatorStub.callCount).to.equal( - signCallCount, - `signValidatorRegistration() must be updated for same feeRecipient=${feeRecipient} gasLimit=${gasLimit} combo ` - ); + expect(JSON.stringify(val2)).toEqual(JSON.stringify(valReg)); + expect(validatorStore.signValidatorRegistration).toHaveBeenCalledOnce(); } }); }); diff --git a/packages/validator/test/utils/apiStub.ts b/packages/validator/test/utils/apiStub.ts index 55b4a370569c..521abfae171d 100644 --- a/packages/validator/test/utils/apiStub.ts +++ b/packages/validator/test/utils/apiStub.ts @@ -1,24 +1,29 @@ -import sinon, {SinonSandbox} from "sinon"; -import {getClient, Api} from "@lodestar/api"; -import {config} from "@lodestar/config/default"; - -export function getApiClientStub( - sandbox: SinonSandbox = sinon -): Api & {[K in keyof Api]: sinon.SinonStubbedInstance} { - const api = getClient({baseUrl: "http://localhost:9596"}, {config}); +import {vi, Mocked} from "vitest"; +import {Api} from "@lodestar/api"; +export function getApiClientStub(): {[K in keyof Api]: Mocked} { return { - beacon: sandbox.stub(api.beacon), - config: sandbox.stub(api.config), - // Typescript errors due to the multiple return types of debug.getState() - // Since the return type of this function is typed, casting to any to patch the error quickly - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - debug: sandbox.stub(api.debug) as any, - events: sandbox.stub(api.events), - lightclient: sandbox.stub(api.lightclient), - lodestar: sandbox.stub(api.lodestar), - node: sandbox.stub(api.node), - proof: sandbox.stub(api.proof), - validator: sandbox.stub(api.validator), - }; + beacon: { + getStateValidators: vi.fn(), + publishBlindedBlockV2: vi.fn(), + publishBlockV2: vi.fn(), + submitPoolSyncCommitteeSignatures: vi.fn(), + submitPoolAttestations: vi.fn(), + }, + validator: { + getProposerDuties: vi.fn(), + getAttesterDuties: vi.fn(), + prepareBeaconCommitteeSubnet: vi.fn(), + produceBlockV3: vi.fn(), + getSyncCommitteeDuties: vi.fn(), + prepareSyncCommitteeSubnets: vi.fn(), + produceSyncCommitteeContribution: vi.fn(), + publishContributionAndProofs: vi.fn(), + submitSyncCommitteeSelections: vi.fn(), + produceAttestationData: vi.fn(), + getAggregatedAttestation: vi.fn(), + publishAggregateAndProofs: vi.fn(), + submitBeaconCommitteeSelections: vi.fn(), + }, + } as unknown as {[K in keyof Api]: Mocked}; } diff --git a/packages/validator/test/utils/types.ts b/packages/validator/test/utils/types.ts index 3ccba6c69918..4704a8142dfc 100644 --- a/packages/validator/test/utils/types.ts +++ b/packages/validator/test/utils/types.ts @@ -1,9 +1,4 @@ -import {SinonStub} from "sinon"; import {toHex} from "@lodestar/utils"; export const ZERO_HASH = Buffer.alloc(32, 0); export const ZERO_HASH_HEX = toHex(ZERO_HASH); - -export type SinonStubFn any> = T extends (...args: infer TArgs) => infer TReturnValue - ? SinonStub - : never; From 4ec413c68b8dbc8223eeeffecb34539db6d988ba Mon Sep 17 00:00:00 2001 From: NC Date: Tue, 16 Jan 2024 23:24:53 +0800 Subject: [PATCH 38/70] fix: block value in `produceBlockV3` should be in wei (#6286) This is the Wei --- packages/api/src/beacon/routes/validator.ts | 5 ++--- packages/api/src/utils/types.ts | 2 +- packages/api/test/unit/beacon/testData/validator.ts | 6 +++--- packages/beacon-node/src/api/impl/validator/index.ts | 6 +++--- packages/beacon-node/src/chain/chain.ts | 11 +++++------ packages/beacon-node/src/chain/interface.ts | 5 ++--- .../unit/api/impl/validator/produceBlockV2.test.ts | 2 +- packages/state-transition/src/cache/rewardCache.ts | 1 + packages/validator/src/services/block.ts | 4 ++-- 9 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/api/src/beacon/routes/validator.ts b/packages/api/src/beacon/routes/validator.ts index 0746797cbf0e..09fbd9de3162 100644 --- a/packages/api/src/beacon/routes/validator.ts +++ b/packages/api/src/beacon/routes/validator.ts @@ -19,7 +19,6 @@ import { StringType, SubcommitteeIndex, Wei, - Gwei, ProducedBlockSource, } from "@lodestar/types"; import {ApiClientResponse} from "../../interfaces.js"; @@ -59,11 +58,11 @@ export type ExtraProduceBlockOps = { blindedLocal?: boolean; }; -export type ProduceBlockOrContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Gwei} & ( +export type ProduceBlockOrContentsRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & ( | {data: allForks.BeaconBlock; version: ForkPreBlobs} | {data: allForks.BlockContents; version: ForkBlobs} ); -export type ProduceBlindedBlockRes = {executionPayloadValue: Wei; consensusBlockValue: Gwei} & { +export type ProduceBlindedBlockRes = {executionPayloadValue: Wei; consensusBlockValue: Wei} & { data: allForks.BlindedBeaconBlock; version: ForkExecution; }; diff --git a/packages/api/src/utils/types.ts b/packages/api/src/utils/types.ts index b01649a0ef38..e218a71e3033 100644 --- a/packages/api/src/utils/types.ts +++ b/packages/api/src/utils/types.ts @@ -179,7 +179,7 @@ export function WithExecutionOptimistic( } /** - * SSZ factory helper to wrap an existing type with `{executionPayloadValue: Wei, consensusBlockValue: GWei}` + * SSZ factory helper to wrap an existing type with `{executionPayloadValue: Wei, consensusBlockValue: Wei}` */ export function WithBlockValues( type: TypeJson diff --git a/packages/api/test/unit/beacon/testData/validator.ts b/packages/api/test/unit/beacon/testData/validator.ts index 2688f2080eba..0769fbc47d9b 100644 --- a/packages/api/test/unit/beacon/testData/validator.ts +++ b/packages/api/test/unit/beacon/testData/validator.ts @@ -78,7 +78,7 @@ export const testData: GenericServerTestCases = { data: ssz.altair.BeaconBlock.defaultValue(), version: ForkName.altair, executionPayloadValue: ssz.Wei.defaultValue(), - consensusBlockValue: ssz.Gwei.defaultValue(), + consensusBlockValue: ssz.Wei.defaultValue(), }, }, produceBlockV3: { @@ -99,7 +99,7 @@ export const testData: GenericServerTestCases = { data: ssz.altair.BeaconBlock.defaultValue(), version: ForkName.altair, executionPayloadValue: ssz.Wei.defaultValue(), - consensusBlockValue: ssz.Gwei.defaultValue(), + consensusBlockValue: ssz.Wei.defaultValue(), executionPayloadBlinded: false, executionPayloadSource: ProducedBlockSource.engine, }, @@ -122,7 +122,7 @@ export const testData: GenericServerTestCases = { data: ssz.bellatrix.BlindedBeaconBlock.defaultValue(), version: ForkName.bellatrix, executionPayloadValue: ssz.Wei.defaultValue(), - consensusBlockValue: ssz.Gwei.defaultValue(), + consensusBlockValue: ssz.Wei.defaultValue(), }, }, produceAttestationData: { diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index f0f076c6c13a..fc5cf953018d 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -35,7 +35,7 @@ import { phase0, } from "@lodestar/types"; import {ExecutionStatus} from "@lodestar/fork-choice"; -import {toHex, racePromisesWithCutoff, RaceEvent, gweiToWei} from "@lodestar/utils"; +import {toHex, racePromisesWithCutoff, RaceEvent} from "@lodestar/utils"; import {AttestationError, AttestationErrorCode, GossipAction, SyncCommitteeError} from "../../../chain/errors/index.js"; import {validateApiAggregateAndProof} from "../../../chain/validation/index.js"; import {ZERO_HASH} from "../../../constants/index.js"; @@ -573,8 +573,8 @@ export function getValidatorApi({ const consensusBlockValueBuilder = blindedBlock?.consensusBlockValue ?? BigInt(0); const consensusBlockValueEngine = fullBlock?.consensusBlockValue ?? BigInt(0); - const blockValueBuilder = builderPayloadValue + gweiToWei(consensusBlockValueBuilder); // Total block value is in wei - const blockValueEngine = enginePayloadValue + gweiToWei(consensusBlockValueEngine); // Total block value is in wei + const blockValueBuilder = builderPayloadValue + consensusBlockValueBuilder; // Total block value is in wei + const blockValueEngine = enginePayloadValue + consensusBlockValueEngine; // Total block value is in wei let executionPayloadSource: ProducedBlockSource | null = null; const shouldOverrideBuilder = fullBlock?.shouldOverrideBuilder ?? false; diff --git a/packages/beacon-node/src/chain/chain.ts b/packages/beacon-node/src/chain/chain.ts index 14fef75c8ad8..f20bc0dbffa2 100644 --- a/packages/beacon-node/src/chain/chain.ts +++ b/packages/beacon-node/src/chain/chain.ts @@ -27,11 +27,10 @@ import { Wei, bellatrix, isBlindedBeaconBlock, - Gwei, } from "@lodestar/types"; import {CheckpointWithHex, ExecutionStatus, IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {ProcessShutdownCallback} from "@lodestar/validator"; -import {Logger, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils"; +import {Logger, gweiToWei, isErrorAborted, pruneSetToMax, sleep, toHex} from "@lodestar/utils"; import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {GENESIS_EPOCH, ZERO_HASH} from "../constants/index.js"; @@ -498,7 +497,7 @@ export class BeaconChain implements IBeaconChain { produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BeaconBlock; executionPayloadValue: Wei; - consensusBlockValue: Gwei; + consensusBlockValue: Wei; shouldOverrideBuilder?: boolean; }> { return this.produceBlockWrapper(BlockType.Full, blockAttributes); @@ -507,7 +506,7 @@ export class BeaconChain implements IBeaconChain { produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; - consensusBlockValue: Gwei; + consensusBlockValue: Wei; }> { return this.produceBlockWrapper(BlockType.Blinded, blockAttributes); } @@ -518,7 +517,7 @@ export class BeaconChain implements IBeaconChain { ): Promise<{ block: AssembledBlockType; executionPayloadValue: Wei; - consensusBlockValue: Gwei; + consensusBlockValue: Wei; shouldOverrideBuilder?: boolean; }> { const head = this.forkChoice.getHead(); @@ -598,7 +597,7 @@ export class BeaconChain implements IBeaconChain { this.metrics?.blockProductionCaches.producedContentsCache.set(this.producedContentsCache.size); } - return {block, executionPayloadValue, consensusBlockValue: proposerReward, shouldOverrideBuilder}; + return {block, executionPayloadValue, consensusBlockValue: gweiToWei(proposerReward), shouldOverrideBuilder}; } /** diff --git a/packages/beacon-node/src/chain/interface.ts b/packages/beacon-node/src/chain/interface.ts index 0771a01caf08..3939457a8ac3 100644 --- a/packages/beacon-node/src/chain/interface.ts +++ b/packages/beacon-node/src/chain/interface.ts @@ -10,7 +10,6 @@ import { ValidatorIndex, deneb, Wei, - Gwei, capella, altair, } from "@lodestar/types"; @@ -162,13 +161,13 @@ export interface IBeaconChain { produceBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BeaconBlock; executionPayloadValue: Wei; - consensusBlockValue: Gwei; + consensusBlockValue: Wei; shouldOverrideBuilder?: boolean; }>; produceBlindedBlock(blockAttributes: BlockAttributes & {commonBlockBody?: CommonBlockBody}): Promise<{ block: allForks.BlindedBeaconBlock; executionPayloadValue: Wei; - consensusBlockValue: Gwei; + consensusBlockValue: Wei; }>; /** Process a block until complete */ diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index 9ca426672efe..56913e241e3b 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -72,7 +72,7 @@ describe("api/validator - produceBlockV2", function () { const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); const executionPayloadValue = ssz.Wei.defaultValue(); - const consensusBlockValue = ssz.Gwei.defaultValue(); + const consensusBlockValue = ssz.Wei.defaultValue(); const currentSlot = 100000; vi.spyOn(server.chainStub.clock, "currentSlot", "get").mockReturnValue(currentSlot); diff --git a/packages/state-transition/src/cache/rewardCache.ts b/packages/state-transition/src/cache/rewardCache.ts index 669060d143cd..c404f26a3c96 100644 --- a/packages/state-transition/src/cache/rewardCache.ts +++ b/packages/state-transition/src/cache/rewardCache.ts @@ -2,6 +2,7 @@ * A simple data structure to store rewards payable to block proposer in the memory. * Rewards are updated throughout the state transition * Should only hold info for one state transition + * All values are in Gwei */ export type RewardCache = { attestations: number; diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index dec08bf9967c..72b3dbbae2e7 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -11,7 +11,7 @@ import { } from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {ForkPreBlobs, ForkBlobs, ForkSeq, ForkExecution} from "@lodestar/params"; -import {ETH_TO_GWEI, ETH_TO_WEI, extendError, gweiToWei, prettyBytes} from "@lodestar/utils"; +import {ETH_TO_WEI, extendError, gweiToWei, prettyBytes} from "@lodestar/utils"; import {Api, ApiError, routes} from "@lodestar/api"; import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; @@ -221,7 +221,7 @@ export class BlockProposingService { executionPayloadBlinded: response.executionPayloadBlinded, // winston logger doesn't like bigint executionPayloadValue: `${formatBigDecimal(response.executionPayloadValue, ETH_TO_WEI, MAX_DECIMAL_FACTOR)} ETH`, - consensusBlockValue: `${formatBigDecimal(response.consensusBlockValue, ETH_TO_GWEI, MAX_DECIMAL_FACTOR)} ETH`, + consensusBlockValue: `${formatBigDecimal(response.consensusBlockValue, ETH_TO_WEI, MAX_DECIMAL_FACTOR)} ETH`, totalBlockValue: `${formatBigDecimal( response.executionPayloadValue + gweiToWei(response.consensusBlockValue), ETH_TO_WEI, From 9eb9cce0fa8b0c37877963793308a348f4f4cdfb Mon Sep 17 00:00:00 2001 From: Cayman Date: Tue, 16 Jan 2024 12:52:52 -0500 Subject: [PATCH 39/70] feat: update libp2p (#6285) * wip * chore: update discv5 and enr * chore: bump dependencies * chore: fix import statement * chore: update libp2p dependencies * chore: yarn.lock cleanup * chore: update discv5 * feat: revamp libp2p dashboard * Clean up metrics registry type casts * chore: fix lint / build errors * chore: more import updates * chore: more yarn.lock cleanup * chore: update gossipsub --------- Co-authored-by: Nico Flaig --- dashboards/lodestar_libp2p.json | 470 +++++-- package.json | 2 +- packages/beacon-node/package.json | 36 +- .../beacon-node/src/api/impl/node/utils.ts | 2 +- .../src/network/core/networkCore.ts | 5 +- .../network/core/networkCoreWorkerHandler.ts | 2 +- .../beacon-node/src/network/discv5/index.ts | 10 +- .../beacon-node/src/network/discv5/types.ts | 3 +- .../beacon-node/src/network/discv5/utils.ts | 2 +- .../beacon-node/src/network/discv5/worker.ts | 17 +- packages/beacon-node/src/network/events.ts | 3 +- .../src/network/gossip/encoding.ts | 2 +- .../src/network/gossip/interface.ts | 2 +- packages/beacon-node/src/network/interface.ts | 53 +- .../beacon-node/src/network/libp2p/index.ts | 20 +- .../beacon-node/src/network/libp2p/noise.ts | 85 -- packages/beacon-node/src/network/network.ts | 2 +- .../beacon-node/src/network/peers/discover.ts | 5 +- .../src/network/peers/peerManager.ts | 3 +- .../src/network/peers/peersData.ts | 2 +- .../src/network/peers/score/interface.ts | 2 +- .../src/network/peers/score/store.ts | 2 +- .../peers/utils/getConnectedPeerIds.ts | 3 +- .../network/peers/utils/prioritizePeers.ts | 3 +- .../network/processor/gossipValidatorFn.ts | 2 +- .../src/network/processor/types.ts | 2 +- .../src/network/reqresp/ReqRespBeaconNode.ts | 2 +- .../src/network/reqresp/interface.ts | 2 +- packages/beacon-node/src/network/util.ts | 10 +- packages/beacon-node/src/node/nodejs.ts | 2 +- .../beacon-node/src/sync/backfill/errors.ts | 2 +- packages/beacon-node/src/util/peerId.ts | 2 +- .../beacon-node/test/e2e/network/mdns.test.ts | 4 +- .../test/e2e/network/network.test.ts | 2 +- .../onWorker/dataSerialization.test.ts | 2 +- .../e2e/network/peers/peerManager.test.ts | 4 +- .../test/perf/network/noise/sendData.test.ts | 10 +- .../peers/util/prioritizePeers.test.ts | 2 +- .../unit/network/peers/priorization.test.ts | 2 +- .../test/unit/network/reqresp/utils.ts | 4 +- packages/beacon-node/test/utils/network.ts | 2 +- .../beacon-node/test/utils/node/beacon.ts | 2 +- packages/beacon-node/test/utils/node/p2p.ts | 3 +- packages/beacon-node/test/utils/peer.ts | 2 +- packages/cli/package.json | 11 +- .../cli/src/cmds/beacon/initPeerIdAndEnr.ts | 12 +- packages/cli/src/cmds/bootnode/handler.ts | 5 +- packages/cli/src/config/peerId.ts | 2 +- packages/cli/src/networks/index.ts | 2 +- .../src/options/beaconNodeOptions/network.ts | 2 +- packages/cli/test/unit/cmds/beacon.test.ts | 4 +- packages/db/package.json | 2 +- packages/light-client/package.json | 2 +- packages/reqresp/package.json | 12 +- packages/reqresp/src/ReqResp.ts | 3 +- .../src/rate_limiter/ReqRespRateLimiter.ts | 2 +- packages/reqresp/src/request/index.ts | 2 +- packages/reqresp/src/response/index.ts | 3 +- packages/reqresp/src/types.ts | 2 +- packages/reqresp/src/utils/peerId.ts | 2 +- .../reqresp/test/unit/request/index.test.ts | 2 +- .../reqresp/test/unit/response/index.test.ts | 2 +- packages/reqresp/test/utils/index.ts | 4 +- packages/reqresp/test/utils/peer.ts | 2 +- yarn.lock | 1138 ++++++++--------- 65 files changed, 1083 insertions(+), 932 deletions(-) delete mode 100644 packages/beacon-node/src/network/libp2p/noise.ts diff --git a/dashboards/lodestar_libp2p.json b/dashboards/lodestar_libp2p.json index 7c6a76ec7175..0fe72e0a4032 100644 --- a/dashboards/lodestar_libp2p.json +++ b/dashboards/lodestar_libp2p.json @@ -76,7 +76,7 @@ "refId": "A" } ], - "title": "Bandwidth", + "title": "General", "type": "row" }, { @@ -120,18 +120,17 @@ "mode": "off" } }, - "mappings": [], - "unit": "Bps" + "mappings": [] }, "overrides": [] }, "gridPos": { - "h": 9, + "h": 8, "w": 12, "x": 0, "y": 1 }, - "id": 2, + "id": 27, "options": { "legend": { "calcs": [], @@ -150,14 +149,16 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, - "expr": "rate(libp2p_global_stats[$rate_interval])", + "expr": "libp2p_connection_manager_connections", "interval": "", - "legendFormat": "{{direction}}", + "legendFormat": "{{libp2p_connection_manager_connections}}", + "range": true, "refId": "A" } ], - "title": "Total Bandwidth", + "title": "Total Connections", "type": "timeseries" }, { @@ -201,8 +202,7 @@ "mode": "off" } }, - "mappings": [], - "unit": "Bps" + "mappings": [] }, "overrides": [] }, @@ -212,7 +212,169 @@ "x": 12, "y": 1 }, - "id": 8, + "id": 28, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "exemplar": false, + "expr": "libp2p_connection_manager_protocol_streams_per_connection_90th_percentile", + "interval": "", + "legendFormat": "{{protocol}}", + "refId": "A" + } + ], + "title": "Streams Per Connection (90th percentile)", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [] + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 9 + }, + "id": 29, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "libp2p_dial_queue", + "instant": false, + "legendFormat": "{{libp2p_dial_queue}}", + "range": true, + "refId": "A" + } + ], + "title": "Dial Queue", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 9 + }, + "id": 30, "options": { "legend": { "calcs": [], @@ -231,14 +393,99 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, + "editorMode": "code", "exemplar": false, - "expr": "rate(libp2p_protocol__meshsub_1_1_0_bytes[$rate_interval])", + "expr": "libp2p_protocol_streams_total", "interval": "", - "legendFormat": "{{direction}}", + "legendFormat": "{{protocol}}", + "range": true, "refId": "A" } ], - "title": "Gossip Bandwidth", + "title": "Total Streams", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "unit": "Bps" + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 17 + }, + "id": 31, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "mode": "single", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "exemplar": false, + "expr": "rate(libp2p_data_transfer_bytes_total[$rate_interval])", + "interval": "", + "legendFormat": "{{protocol}}", + "range": true, + "refId": "A" + } + ], + "title": "Total Bandwidth", "type": "timeseries" }, { @@ -251,7 +498,7 @@ "h": 1, "w": 24, "x": 0, - "y": 10 + "y": 26 }, "id": 24, "panels": [], @@ -308,7 +555,8 @@ "mode": "off" } }, - "mappings": [] + "mappings": [], + "unit": "none" }, "overrides": [] }, @@ -316,9 +564,9 @@ "h": 8, "w": 12, "x": 0, - "y": 11 + "y": 27 }, - "id": 20, + "id": 32, "options": { "legend": { "calcs": [], @@ -338,13 +586,15 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(libp2p_tcp_listener_events_total[$rate_interval])", - "legendFormat": "{{address}}", + "exemplar": false, + "expr": "rate(libp2p_tcp_dialer_events_total[$rate_interval])", + "interval": "", + "legendFormat": "{{event}}", "range": true, "refId": "A" } ], - "title": "Listener Event Rate", + "title": "Dialer Event Rate", "type": "timeseries" }, { @@ -396,9 +646,9 @@ "h": 8, "w": 12, "x": 12, - "y": 11 + "y": 27 }, - "id": 26, + "id": 20, "options": { "legend": { "calcs": [], @@ -418,13 +668,13 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "rate(libp2p_tcp_listener_errors_total[$rate_interval])", + "expr": "rate(libp2p_tcp_listener_events_total[$rate_interval])", "legendFormat": "{{address}}", "range": true, "refId": "A" } ], - "title": "Listener Error Rate", + "title": "Listener Event Rate", "type": "timeseries" }, { @@ -494,7 +744,7 @@ "h": 8, "w": 12, "x": 0, - "y": 19 + "y": 35 }, "id": 22, "options": { @@ -566,8 +816,7 @@ "mode": "off" } }, - "mappings": [], - "unit": "Bps" + "mappings": [] }, "overrides": [] }, @@ -575,9 +824,9 @@ "h": 8, "w": 12, "x": 12, - "y": 19 + "y": 35 }, - "id": 16, + "id": 26, "options": { "legend": { "calcs": [], @@ -596,16 +845,42 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "exemplar": false, - "expr": "rate(libp2p_protocol__ipfs_id_push_1_0_0_bytes[$rate_interval])", - "interval": "", - "legendFormat": "{{direction}}", + "editorMode": "code", + "expr": "rate(libp2p_tcp_listener_errors_total[$rate_interval])", + "legendFormat": "{{address}}", + "range": true, "refId": "A" } ], - "title": "Identify-Push Protocol Bandwidth", + "title": "Listener Error Rate", "type": "timeseries" }, + { + "collapsed": false, + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 43 + }, + "id": 14, + "panels": [], + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "refId": "A" + } + ], + "title": "Noise", + "type": "row" + }, { "datasource": { "type": "prometheus", @@ -630,6 +905,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -647,7 +923,7 @@ } }, "mappings": [], - "unit": "Bps" + "unit": "outcomes/interval" }, "overrides": [] }, @@ -655,9 +931,9 @@ "h": 8, "w": 12, "x": 0, - "y": 27 + "y": 44 }, - "id": 10, + "id": 33, "options": { "legend": { "calcs": [], @@ -676,41 +952,29 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "exemplar": false, - "expr": "rate(libp2p_protocol__ipfs_id_1_0_0_bytes[$rate_interval])", - "interval": "", - "legendFormat": "{{direction}}", + "editorMode": "code", + "expr": "rate(libp2p_noise_xxhandshake_successes_total[$rate_interval])", + "instant": false, + "legendFormat": "success", + "range": true, "refId": "A" - } - ], - "title": "Identify Protocol Bandwidth", - "type": "timeseries" - }, - { - "collapsed": false, - "datasource": { - "type": "prometheus", - "uid": "${DS_PROMETHEUS}" - }, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 35 - }, - "id": 14, - "panels": [], - "targets": [ + }, { "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "refId": "A" + "editorMode": "code", + "expr": "rate(libp2p_noise_xxhandshake_error_total[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "failure", + "range": true, + "refId": "B" } ], - "title": "Connection Manager", - "type": "row" + "title": "Handshake Outcome Rate", + "type": "timeseries" }, { "datasource": { @@ -736,6 +1000,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -752,17 +1017,18 @@ "mode": "off" } }, - "mappings": [] + "mappings": [], + "unit": "packets/interval" }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, - "x": 0, - "y": 36 + "x": 12, + "y": 44 }, - "id": 4, + "id": 34, "options": { "legend": { "calcs": [], @@ -781,14 +1047,28 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "exemplar": false, - "expr": "libp2p_connection_manager_connections", - "interval": "", - "legendFormat": "{{direction}}", + "editorMode": "code", + "expr": "rate(libp2p_noise_encrypted_packets_total[$rate_interval])", + "instant": false, + "legendFormat": "encrypted", + "range": true, "refId": "A" + }, + { + "datasource": { + "type": "prometheus", + "uid": "${DS_PROMETHEUS}" + }, + "editorMode": "code", + "expr": "rate(libp2p_noise_decrypted_packets_total[$rate_interval])", + "hide": false, + "instant": false, + "legendFormat": "decrypted", + "range": true, + "refId": "B" } ], - "title": "Total Connections", + "title": "Packet Rate", "type": "timeseries" }, { @@ -815,6 +1095,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -831,23 +1112,24 @@ "mode": "off" } }, - "mappings": [] + "mappings": [], + "unit": "errors/interval" }, "overrides": [] }, "gridPos": { "h": 8, "w": 12, - "x": 12, - "y": 36 + "x": 0, + "y": 52 }, - "id": 6, + "id": 35, "options": { "legend": { "calcs": [], "displayMode": "list", "placement": "bottom", - "showLegend": true + "showLegend": false }, "tooltip": { "mode": "single", @@ -860,14 +1142,15 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "exemplar": false, - "expr": "libp2p_connection_manager_protocol_streams_total", - "interval": "", - "legendFormat": "{{protocol}}", + "editorMode": "code", + "expr": "rate(libp2p_noise_decrypt_errors_total[$rate_interval])", + "instant": false, + "legendFormat": "Decryption Errors", + "range": true, "refId": "A" } ], - "title": "Total Streams", + "title": "Packet Decryption Error Rate", "type": "timeseries" }, { @@ -894,6 +1177,7 @@ "tooltip": false, "viz": false }, + "insertNulls": false, "lineInterpolation": "linear", "lineWidth": 1, "pointSize": 5, @@ -910,7 +1194,8 @@ "mode": "off" } }, - "mappings": [] + "mappings": [], + "unit": "percentunit" }, "overrides": [] }, @@ -918,9 +1203,9 @@ "h": 8, "w": 12, "x": 12, - "y": 44 + "y": 52 }, - "id": 18, + "id": 36, "options": { "legend": { "calcs": [], @@ -939,14 +1224,15 @@ "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "exemplar": false, - "expr": "libp2p_connection_manager_protocol_streams_per_connection_90th_percentile", - "interval": "", - "legendFormat": "{{protocol}}", + "editorMode": "code", + "expr": "rate(libp2p_noise_decrypt_errors_total[$rate_interval]) / rate(libp2p_noise_decrypted_packets_total[$rate_interval])", + "instant": false, + "legendFormat": "Decryption Error Percentage", + "range": true, "refId": "A" } ], - "title": "Streams Per Connection (90th percentile)", + "title": "Packet Decryption Error Percentage", "type": "timeseries" } ], diff --git a/package.json b/package.json index 5d055bd2f4ce..b422c2a604aa 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "karma-spec-reporter": "^0.0.36", "karma-webpack": "^5.0.0", "lerna": "^7.3.0", - "libp2p": "0.46.12", + "libp2p": "1.1.1", "mocha": "^10.2.0", "node-gyp": "^9.4.0", "npm-run-all": "^4.1.5", diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index b418dbe6ed15..54c21fe032ab 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -99,9 +99,10 @@ "@chainsafe/as-sha256": "^0.3.1", "@chainsafe/bls": "7.1.1", "@chainsafe/blst": "^0.2.9", - "@chainsafe/discv5": "^5.1.0", - "@chainsafe/libp2p-gossipsub": "^10.1.1", - "@chainsafe/libp2p-noise": "^13.0.1", + "@chainsafe/discv5": "^7.1.0", + "@chainsafe/enr": "^2.0.2", + "@chainsafe/libp2p-gossipsub": "^11.1.0", + "@chainsafe/libp2p-noise": "^14.1.0", "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/prometheus-gc-stats": "^1.0.0", "@chainsafe/ssz": "^0.14.0", @@ -111,14 +112,15 @@ "@fastify/cors": "^8.2.1", "@fastify/swagger": "^8.10.0", "@fastify/swagger-ui": "^1.9.3", - "@libp2p/bootstrap": "^9.0.7", - "@libp2p/interface": "^0.1.2", - "@libp2p/mdns": "^9.0.9", - "@libp2p/mplex": "^9.0.7", - "@libp2p/peer-id": "^3.0.2", - "@libp2p/peer-id-factory": "^3.0.4", - "@libp2p/prometheus-metrics": "^2.0.7", - "@libp2p/tcp": "8.0.8", + "@libp2p/bootstrap": "^10.0.10", + "@libp2p/identify": "^1.0.9", + "@libp2p/interface": "^1.1.1", + "@libp2p/mdns": "^10.0.10", + "@libp2p/mplex": "^10.0.10", + "@libp2p/peer-id": "^4.0.4", + "@libp2p/peer-id-factory": "^4.0.3", + "@libp2p/prometheus-metrics": "^3.0.10", + "@libp2p/tcp": "9.0.10", "@lodestar/api": "^1.14.0", "@lodestar/config": "^1.14.0", "@lodestar/db": "^1.14.0", @@ -139,20 +141,20 @@ "datastore-level": "^10.1.1", "deepmerge": "^4.3.1", "fastify": "^4.19.0", - "interface-datastore": "^8.2.0", - "it-all": "^3.0.2", + "interface-datastore": "^8.2.7", + "it-all": "^3.0.4", "it-pipe": "^3.0.1", "jwt-simple": "0.5.6", - "libp2p": "0.46.12", + "libp2p": "1.1.1", "multiformats": "^11.0.1", "prom-client": "^15.1.0", "qs": "^6.11.1", "snappyjs": "^0.7.0", "strict-event-emitter-types": "^2.0.0", "systeminformation": "^5.17.12", - "uint8-varint": "^2.0.1", - "uint8arraylist": "^2.4.3", - "uint8arrays": "^4.0.3", + "uint8-varint": "^2.0.2", + "uint8arraylist": "^2.4.7", + "uint8arrays": "^4.0.9", "xxhash-wasm": "1.0.2" }, "devDependencies": { diff --git a/packages/beacon-node/src/api/impl/node/utils.ts b/packages/beacon-node/src/api/impl/node/utils.ts index 7e13053e7df0..f26539eb0b36 100644 --- a/packages/beacon-node/src/api/impl/node/utils.ts +++ b/packages/beacon-node/src/api/impl/node/utils.ts @@ -1,4 +1,4 @@ -import {Connection, StreamStatus} from "@libp2p/interface/connection"; +import {Connection, StreamStatus} from "@libp2p/interface"; import {routes} from "@lodestar/api"; /** diff --git a/packages/beacon-node/src/network/core/networkCore.ts b/packages/beacon-node/src/network/core/networkCore.ts index 3037b69b4263..c17c4a201bdf 100644 --- a/packages/beacon-node/src/network/core/networkCore.ts +++ b/packages/beacon-node/src/network/core/networkCore.ts @@ -1,10 +1,9 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {Connection, PeerId} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; -import {Connection} from "@libp2p/interface/connection"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; import {fromHexString} from "@chainsafe/ssz"; -import {ENR} from "@chainsafe/discv5"; +import {ENR} from "@chainsafe/enr"; import {routes} from "@lodestar/api"; import {BeaconConfig} from "@lodestar/config"; import type {LoggerNode} from "@lodestar/logger/node"; diff --git a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts index ae39e6759099..8370d3687635 100644 --- a/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts +++ b/packages/beacon-node/src/network/core/networkCoreWorkerHandler.ts @@ -3,7 +3,7 @@ import worker_threads from "node:worker_threads"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/dist/src/score/peer-score.js"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {ModuleThread, Thread, Worker, spawn} from "@chainsafe/threads"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {exportToProtobuf} from "@libp2p/peer-id-factory"; import {routes} from "@lodestar/api"; import {BeaconConfig, chainConfigToJson} from "@lodestar/config"; diff --git a/packages/beacon-node/src/network/discv5/index.ts b/packages/beacon-node/src/network/discv5/index.ts index babe279afe86..5a06545b98af 100644 --- a/packages/beacon-node/src/network/discv5/index.ts +++ b/packages/beacon-node/src/network/discv5/index.ts @@ -1,8 +1,8 @@ import EventEmitter from "events"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import StrictEventEmitter from "strict-event-emitter-types"; import {exportToProtobuf} from "@libp2p/peer-id-factory"; -import {createKeypairFromPeerId, ENR, ENRData, IKeypair, SignableENR} from "@chainsafe/discv5"; +import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR} from "@chainsafe/enr"; import {spawn, Thread, Worker} from "@chainsafe/threads"; import {chainConfigFromJson, chainConfigToJson, BeaconConfig} from "@lodestar/config"; import {LoggerNode} from "@lodestar/logger/node"; @@ -25,7 +25,7 @@ export type Discv5Events = { * Wrapper class abstracting the details of discv5 worker instantiation and message-passing */ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter}) { - private readonly keypair: IKeypair; + private readonly keypair; private readonly subscription: {unsubscribe: () => void}; private closed = false; @@ -35,7 +35,7 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter this.onDiscovered(enrObj)); } @@ -80,7 +80,7 @@ export class Discv5Worker extends (EventEmitter as {new (): StrictEventEmitter { const obj = await this.workerApi.enr(); - return new SignableENR(obj.kvs, obj.seq, this.keypair); + return new SignableENR(obj.kvs, obj.seq, this.keypair.privateKey); } setEnrValue(key: string, value: Uint8Array): Promise { diff --git a/packages/beacon-node/src/network/discv5/types.ts b/packages/beacon-node/src/network/discv5/types.ts index 3c7677b4575c..63c5cd52b6fe 100644 --- a/packages/beacon-node/src/network/discv5/types.ts +++ b/packages/beacon-node/src/network/discv5/types.ts @@ -1,4 +1,5 @@ -import {Discv5, ENRData, SignableENRData} from "@chainsafe/discv5"; +import {Discv5} from "@chainsafe/discv5"; +import {ENRData, SignableENRData} from "@chainsafe/enr"; import {Observable} from "@chainsafe/threads/observable"; import {ChainConfig} from "@lodestar/config"; import {LoggerNodeOpts} from "@lodestar/logger/node"; diff --git a/packages/beacon-node/src/network/discv5/utils.ts b/packages/beacon-node/src/network/discv5/utils.ts index 70bf9517ac01..e5707b483281 100644 --- a/packages/beacon-node/src/network/discv5/utils.ts +++ b/packages/beacon-node/src/network/discv5/utils.ts @@ -1,4 +1,4 @@ -import {ENR} from "@chainsafe/discv5"; +import {ENR} from "@chainsafe/enr"; import {BeaconConfig} from "@lodestar/config"; import {ENRKey} from "../metadata.js"; diff --git a/packages/beacon-node/src/network/discv5/worker.ts b/packages/beacon-node/src/network/discv5/worker.ts index e09b063d13d1..be8fdc4af601 100644 --- a/packages/beacon-node/src/network/discv5/worker.ts +++ b/packages/beacon-node/src/network/discv5/worker.ts @@ -5,15 +5,8 @@ import {createFromProtobuf} from "@libp2p/peer-id-factory"; import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; import {expose} from "@chainsafe/threads/worker"; import {Observable, Subject} from "@chainsafe/threads/observable"; -import { - createKeypairFromPeerId, - Discv5, - ENR, - ENRData, - IDiscv5CreateOptions, - SignableENR, - SignableENRData, -} from "@chainsafe/discv5"; +import {Discv5} from "@chainsafe/discv5"; +import {createPrivateKeyFromPeerId, ENR, ENRData, SignableENR, SignableENRData} from "@chainsafe/enr"; import {createBeaconConfig} from "@lodestar/config"; import {getNodeLogger} from "@lodestar/logger/node"; import {Gauge} from "@lodestar/utils"; @@ -51,20 +44,20 @@ if (workerData.metrics) { } const peerId = await createFromProtobuf(workerData.peerIdProto); -const keypair = createKeypairFromPeerId(peerId); +const keypair = createPrivateKeyFromPeerId(peerId); const config = createBeaconConfig(workerData.chainConfig, workerData.genesisValidatorsRoot); // Initialize discv5 const discv5 = Discv5.create({ - enr: SignableENR.decodeTxt(workerData.enr, keypair), + enr: SignableENR.decodeTxt(workerData.enr, keypair.privateKey), peerId, bindAddrs: { ip4: (workerData.bindAddrs.ip4 ? multiaddr(workerData.bindAddrs.ip4) : undefined) as Multiaddr, ip6: workerData.bindAddrs.ip6 ? multiaddr(workerData.bindAddrs.ip6) : undefined, }, config: workerData.config, - metricsRegistry: metricsRegistry as IDiscv5CreateOptions["metricsRegistry"], + metricsRegistry, }); // Load boot enrs diff --git a/packages/beacon-node/src/network/events.ts b/packages/beacon-node/src/network/events.ts index 815efda7d9b8..67ea0a1dd0e0 100644 --- a/packages/beacon-node/src/network/events.ts +++ b/packages/beacon-node/src/network/events.ts @@ -1,6 +1,5 @@ import {EventEmitter} from "events"; -import {PeerId} from "@libp2p/interface/peer-id"; -import {TopicValidatorResult} from "@libp2p/interface/pubsub"; +import {PeerId, TopicValidatorResult} from "@libp2p/interface"; import {phase0, RootHex} from "@lodestar/types"; import {BlockInput} from "../chain/blocks/types.js"; import {StrictEventEmitterSingleArg} from "../util/strictEvents.js"; diff --git a/packages/beacon-node/src/network/gossip/encoding.ts b/packages/beacon-node/src/network/gossip/encoding.ts index 5c39dd96cec9..cccb0807b101 100644 --- a/packages/beacon-node/src/network/gossip/encoding.ts +++ b/packages/beacon-node/src/network/gossip/encoding.ts @@ -1,6 +1,6 @@ import {compress, uncompress} from "snappyjs"; import xxhashFactory from "xxhash-wasm"; -import {Message} from "@libp2p/interface/pubsub"; +import {Message} from "@libp2p/interface"; import {digest} from "@chainsafe/as-sha256"; import {RPC} from "@chainsafe/libp2p-gossipsub/message"; import {intToBytes, toHex} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/network/gossip/interface.ts b/packages/beacon-node/src/network/gossip/interface.ts index 600f96193296..df26c2328c70 100644 --- a/packages/beacon-node/src/network/gossip/interface.ts +++ b/packages/beacon-node/src/network/gossip/interface.ts @@ -1,5 +1,5 @@ import {Libp2p} from "libp2p"; -import {Message, TopicValidatorResult} from "@libp2p/interface/pubsub"; +import {Message, TopicValidatorResult} from "@libp2p/interface"; import {PeerIdStr} from "@chainsafe/libp2p-gossipsub/types"; import {ForkName} from "@lodestar/params"; import {allForks, altair, capella, deneb, phase0, Slot} from "@lodestar/types"; diff --git a/packages/beacon-node/src/network/interface.ts b/packages/beacon-node/src/network/interface.ts index 9531c8529acf..573698c13ded 100644 --- a/packages/beacon-node/src/network/interface.ts +++ b/packages/beacon-node/src/network/interface.ts @@ -1,5 +1,20 @@ import {Libp2p as ILibp2p} from "libp2p"; -import {Components} from "libp2p/components"; +import { + Libp2pEvents, + ComponentLogger, + NodeInfo, + ConnectionProtector, + ConnectionGater, + ContentRouting, + TypedEventTarget, + Metrics, + PeerId, + PeerRouting, + PeerStore, + Upgrader, +} from "@libp2p/interface"; +import type {AddressManager, ConnectionManager, Registrar, TransportManager} from "@libp2p/interface-internal"; +import type {Datastore} from "interface-datastore"; import {Slot, SlotRootHex, allForks, altair, capella, deneb, phase0} from "@lodestar/types"; import {PeerIdStr} from "../util/peerId.js"; import {INetworkEventBus} from "./events.js"; @@ -64,21 +79,23 @@ export interface INetwork extends INetworkCorePublic { writeDiscv5HeapSnapshot(prefix: string, dirpath: string): Promise; } -export type LodestarComponents = Pick< - Components, - | "peerId" - | "events" - | "addressManager" - | "peerStore" - | "upgrader" - | "registrar" - | "connectionManager" - | "transportManager" - | "connectionGater" - | "contentRouting" - | "peerRouting" - | "datastore" - | "connectionProtector" - | "metrics" ->; +export type LodestarComponents = { + peerId: PeerId; + nodeInfo: NodeInfo; + logger: ComponentLogger; + events: TypedEventTarget; + addressManager: AddressManager; + peerStore: PeerStore; + upgrader: Upgrader; + registrar: Registrar; + connectionManager: ConnectionManager; + transportManager: TransportManager; + connectionGater: ConnectionGater; + contentRouting: ContentRouting; + peerRouting: PeerRouting; + datastore: Datastore; + connectionProtector?: ConnectionProtector; + metrics?: Metrics; +}; + export type Libp2p = ILibp2p<{components: LodestarComponents}>; diff --git a/packages/beacon-node/src/network/libp2p/index.ts b/packages/beacon-node/src/network/libp2p/index.ts index cdbb3fb16224..ccbd07355c32 100644 --- a/packages/beacon-node/src/network/libp2p/index.ts +++ b/packages/beacon-node/src/network/libp2p/index.ts @@ -1,18 +1,17 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {Registry} from "prom-client"; -import {ENR} from "@chainsafe/discv5"; -import type {Components} from "libp2p/components"; -import {identifyService} from "libp2p/identify"; +import {ENR} from "@chainsafe/enr"; +import {identify} from "@libp2p/identify"; import {bootstrap} from "@libp2p/bootstrap"; import {mdns} from "@libp2p/mdns"; import {createLibp2p} from "libp2p"; import {mplex} from "@libp2p/mplex"; import {prometheusMetrics} from "@libp2p/prometheus-metrics"; import {tcp} from "@libp2p/tcp"; +import {noise} from "@chainsafe/libp2p-noise"; import {defaultNetworkOptions, NetworkOptions} from "../options.js"; import {Eth2PeerDataStore} from "../peers/datastore.js"; -import {Libp2p} from "../interface.js"; -import {createNoise} from "./noise.js"; +import {Libp2p, LodestarComponents} from "../interface.js"; export type NodeJsLibp2pOpts = { peerStoreDir?: string; @@ -70,7 +69,7 @@ export async function createNodeJsLibp2p( listen: localMultiaddrs, announce: [], }, - connectionEncryption: [createNoise()], + connectionEncryption: [noise()], // Reject connections when the server's connection count gets high transports: [ tcp({ @@ -98,7 +97,6 @@ export async function createNodeJsLibp2p( // dialer config maxParallelDials: 100, maxPeerAddrsToDial: 4, - maxParallelDialsPerPeer: 2, dialTimeout: 30_000, // Rely entirely on lodestar's peer manager to prune connections @@ -111,13 +109,15 @@ export async function createNodeJsLibp2p( }, datastore, services: { - identify: identifyService({ + identify: identify({ agentVersion: networkOpts.private ? "" : networkOpts.version ? `lodestar/${networkOpts.version}` : "lodestar", }), // individual components are specified because the components object is a Proxy // and passing it here directly causes problems downstream, not to mention is slowwww - components: (components: Components) => ({ + components: (components: LodestarComponents) => ({ peerId: components.peerId, + nodeInfo: components.nodeInfo, + logger: components.logger, events: components.events, addressManager: components.addressManager, peerStore: components.peerStore, diff --git a/packages/beacon-node/src/network/libp2p/noise.ts b/packages/beacon-node/src/network/libp2p/noise.ts deleted file mode 100644 index fcb00fe41893..000000000000 --- a/packages/beacon-node/src/network/libp2p/noise.ts +++ /dev/null @@ -1,85 +0,0 @@ -import crypto from "node:crypto"; -import type {ConnectionEncrypter} from "@libp2p/interface/connection-encrypter"; -import {ICryptoInterface, noise, pureJsCrypto} from "@chainsafe/libp2p-noise"; -import {digest} from "@chainsafe/as-sha256"; -import {newInstance, ChaCha20Poly1305} from "@chainsafe/as-chacha20poly1305"; - -const ctx = newInstance(); -const asImpl = new ChaCha20Poly1305(ctx); - -const CHACHA_POLY1305 = "chacha20-poly1305"; - -const nodeCrypto: Pick = { - hashSHA256(data) { - return crypto.createHash("sha256").update(data).digest(); - }, - - chaCha20Poly1305Encrypt(plaintext, nonce, ad, k) { - const cipher = crypto.createCipheriv(CHACHA_POLY1305, k, nonce, { - authTagLength: 16, - }); - cipher.setAAD(ad, {plaintextLength: plaintext.byteLength}); - const updated = cipher.update(plaintext); - const final = cipher.final(); - const tag = cipher.getAuthTag(); - - const encrypted = Buffer.concat([updated, tag, final]); - return encrypted; - }, - - chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, _dst) { - const authTag = ciphertext.slice(ciphertext.length - 16); - const text = ciphertext.slice(0, ciphertext.length - 16); - const decipher = crypto.createDecipheriv(CHACHA_POLY1305, k, nonce, { - authTagLength: 16, - }); - decipher.setAAD(ad, { - plaintextLength: text.byteLength, - }); - decipher.setAuthTag(authTag); - const updated = decipher.update(text); - const final = decipher.final(); - if (final.byteLength > 0) { - return Buffer.concat([updated, final]); - } - return updated; - }, -}; - -const asCrypto: Pick = { - hashSHA256(data) { - return digest(data); - }, - chaCha20Poly1305Encrypt(plaintext, nonce, ad, k) { - return asImpl.seal(k, nonce, plaintext, ad); - }, - chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) { - return asImpl.open(k, nonce, ciphertext, ad, dst); - }, -}; - -// benchmarks show that for chacha20poly1305 -// the as implementation is faster for smaller payloads(<1200) -// and the node implementation is faster for larger payloads -const lodestarCrypto: ICryptoInterface = { - ...pureJsCrypto, - hashSHA256(data) { - return nodeCrypto.hashSHA256(data); - }, - chaCha20Poly1305Encrypt(plaintext, nonce, ad, k) { - if (plaintext.length < 1200) { - return asCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k); - } - return nodeCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k); - }, - chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) { - if (ciphertext.length < 1200) { - return asCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst); - } - return nodeCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst); - }, -}; - -export function createNoise(): () => ConnectionEncrypter { - return noise({crypto: lodestarCrypto}); -} diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 200bd4fd3a8d..609ee2d44ba1 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {PublishOpts} from "@chainsafe/libp2p-gossipsub/types"; import {PeerScoreStatsDump} from "@chainsafe/libp2p-gossipsub/score"; import {BeaconConfig} from "@lodestar/config"; diff --git a/packages/beacon-node/src/network/peers/discover.ts b/packages/beacon-node/src/network/peers/discover.ts index 2805f67b4763..34ea959d4ec7 100644 --- a/packages/beacon-node/src/network/peers/discover.ts +++ b/packages/beacon-node/src/network/peers/discover.ts @@ -1,7 +1,6 @@ -import {PeerId} from "@libp2p/interface/peer-id"; import {Multiaddr} from "@multiformats/multiaddr"; -import type {PeerInfo} from "@libp2p/interface/peer-info"; -import {ENR} from "@chainsafe/discv5"; +import type {PeerId, PeerInfo} from "@libp2p/interface"; +import {ENR} from "@chainsafe/enr"; import {BeaconConfig} from "@lodestar/config"; import {pruneSetToMax, sleep} from "@lodestar/utils"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index ca493389803c..5100987566e2 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -1,5 +1,4 @@ -import {Connection} from "@libp2p/interface/connection"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {Connection, PeerId} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; import {SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {BeaconConfig} from "@lodestar/config"; diff --git a/packages/beacon-node/src/network/peers/peersData.ts b/packages/beacon-node/src/network/peers/peersData.ts index 9b27bafaa682..5487a9a44159 100644 --- a/packages/beacon-node/src/network/peers/peersData.ts +++ b/packages/beacon-node/src/network/peers/peersData.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {altair} from "@lodestar/types"; import {Encoding} from "@lodestar/reqresp"; import {ClientKind} from "./client.js"; diff --git a/packages/beacon-node/src/network/peers/score/interface.ts b/packages/beacon-node/src/network/peers/score/interface.ts index ba52c512d3c6..f6e2dc88013a 100644 --- a/packages/beacon-node/src/network/peers/score/interface.ts +++ b/packages/beacon-node/src/network/peers/score/interface.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {NetworkCoreMetrics} from "../../core/metrics.js"; export type PeerIdStr = string; diff --git a/packages/beacon-node/src/network/peers/score/store.ts b/packages/beacon-node/src/network/peers/score/store.ts index f03064053039..9b1ef5a297e6 100644 --- a/packages/beacon-node/src/network/peers/score/store.ts +++ b/packages/beacon-node/src/network/peers/score/store.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {MapDef, pruneSetToMax} from "@lodestar/utils"; import {NetworkCoreMetrics} from "../../core/metrics.js"; import {DEFAULT_SCORE, MAX_ENTRIES, MAX_SCORE, MIN_SCORE, SCORE_THRESHOLD} from "./constants.js"; diff --git a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts index 77a61eb3c0b9..8542df605b06 100644 --- a/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts +++ b/packages/beacon-node/src/network/peers/utils/getConnectedPeerIds.ts @@ -1,5 +1,4 @@ -import {Connection} from "@libp2p/interface/connection"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {Connection, PeerId} from "@libp2p/interface"; import {Libp2p} from "../../interface.js"; import {getConnectionsMap} from "../../util.js"; diff --git a/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts b/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts index 5c486a79a48b..b6fe4cb6bc77 100644 --- a/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts +++ b/packages/beacon-node/src/network/peers/utils/prioritizePeers.ts @@ -1,5 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; -import {Direction} from "@libp2p/interface/connection"; +import {Direction, PeerId} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; import {altair, phase0} from "@lodestar/types"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; diff --git a/packages/beacon-node/src/network/processor/gossipValidatorFn.ts b/packages/beacon-node/src/network/processor/gossipValidatorFn.ts index 89c40b7482f0..e5b276e7c707 100644 --- a/packages/beacon-node/src/network/processor/gossipValidatorFn.ts +++ b/packages/beacon-node/src/network/processor/gossipValidatorFn.ts @@ -1,4 +1,4 @@ -import {TopicValidatorResult} from "@libp2p/interface/pubsub"; +import {TopicValidatorResult} from "@libp2p/interface"; import {ChainForkConfig} from "@lodestar/config"; import {Logger} from "@lodestar/utils"; import {Metrics} from "../../metrics/index.js"; diff --git a/packages/beacon-node/src/network/processor/types.ts b/packages/beacon-node/src/network/processor/types.ts index 8a1aa934e9b9..386b9e8afc37 100644 --- a/packages/beacon-node/src/network/processor/types.ts +++ b/packages/beacon-node/src/network/processor/types.ts @@ -1,4 +1,4 @@ -import {Message} from "@libp2p/interface/pubsub"; +import {Message} from "@libp2p/interface"; import {Slot, SlotOptionalRoot} from "@lodestar/types"; import {GossipTopic, GossipType} from "../gossip/index.js"; import {PeerIdStr} from "../../util/peerId.js"; diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index cc5713532d50..962962ab8842 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {Libp2p} from "libp2p"; import {BeaconConfig} from "@lodestar/config"; import {ForkName, ForkSeq} from "@lodestar/params"; diff --git a/packages/beacon-node/src/network/reqresp/interface.ts b/packages/beacon-node/src/network/reqresp/interface.ts index 972e12329b68..0a9d2f59b3ad 100644 --- a/packages/beacon-node/src/network/reqresp/interface.ts +++ b/packages/beacon-node/src/network/reqresp/interface.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; /** * Rate limiter interface for inbound and outbound requests. diff --git a/packages/beacon-node/src/network/util.ts b/packages/beacon-node/src/network/util.ts index 59a333c3d74d..dd317b5a0427 100644 --- a/packages/beacon-node/src/network/util.ts +++ b/packages/beacon-node/src/network/util.ts @@ -1,6 +1,4 @@ -import type {PeerId} from "@libp2p/interface/peer-id"; -import type {Connection} from "@libp2p/interface/connection"; -import type {DefaultConnectionManager} from "libp2p/connection-manager/index.js"; +import type {Connection, PeerId} from "@libp2p/interface"; import type {PeerIdStr} from "../util/peerId.js"; import type {Libp2p} from "./interface.js"; @@ -17,10 +15,8 @@ export function prettyPrintPeerIdStr(id: PeerIdStr): string { */ // Compat function for efficiency reasons export function getConnectionsMap(libp2p: Libp2p): Map { - return (libp2p.services.components.connectionManager as DefaultConnectionManager)["connections"] as Map< - string, - Connection[] - >; + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return libp2p.services.components.connectionManager.getConnectionsMap()["map"]; } export function getConnection(libp2p: Libp2p, peerIdStr: string): Connection | undefined { diff --git a/packages/beacon-node/src/node/nodejs.ts b/packages/beacon-node/src/node/nodejs.ts index da4f802a521c..1e9c7794ac68 100644 --- a/packages/beacon-node/src/node/nodejs.ts +++ b/packages/beacon-node/src/node/nodejs.ts @@ -1,7 +1,7 @@ import {setMaxListeners} from "node:events"; import {Registry} from "prom-client"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {BeaconConfig} from "@lodestar/config"; import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; diff --git a/packages/beacon-node/src/sync/backfill/errors.ts b/packages/beacon-node/src/sync/backfill/errors.ts index 2cec1dc487ad..e62c90407ed5 100644 --- a/packages/beacon-node/src/sync/backfill/errors.ts +++ b/packages/beacon-node/src/sync/backfill/errors.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {LodestarError} from "@lodestar/utils"; import {Root} from "@lodestar/types"; diff --git a/packages/beacon-node/src/util/peerId.ts b/packages/beacon-node/src/util/peerId.ts index fa653ee8e3ee..2afb9bed390e 100644 --- a/packages/beacon-node/src/util/peerId.ts +++ b/packages/beacon-node/src/util/peerId.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {base58btc} from "multiformats/bases/base58"; import {peerIdFromString} from "@libp2p/peer-id"; diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index a09a1becc1cf..91cbab09bae9 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -1,8 +1,8 @@ import {describe, it, afterEach, beforeEach, expect, vi} from "vitest"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {multiaddr} from "@multiformats/multiaddr"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {SignableENR} from "@chainsafe/discv5"; +import {SignableENR} from "@chainsafe/enr"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; diff --git a/packages/beacon-node/test/e2e/network/network.test.ts b/packages/beacon-node/test/e2e/network/network.test.ts index 97bd101ba69d..2a727481118b 100644 --- a/packages/beacon-node/test/e2e/network/network.test.ts +++ b/packages/beacon-node/test/e2e/network/network.test.ts @@ -1,5 +1,5 @@ import {describe, it, expect, afterEach, beforeEach, vi} from "vitest"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {config} from "@lodestar/config/default"; import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; diff --git a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts index 36aae25284a8..a49c6923a9ea 100644 --- a/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts +++ b/packages/beacon-node/test/e2e/network/onWorker/dataSerialization.test.ts @@ -1,5 +1,5 @@ import {describe, it, beforeAll, afterAll, expect} from "vitest"; -import {TopicValidatorResult} from "@libp2p/interface/pubsub"; +import {TopicValidatorResult} from "@libp2p/interface"; import {BitArray} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; import {routes} from "@lodestar/api"; diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index e2f42f76221f..5ef836761cb6 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -1,6 +1,6 @@ import {describe, it, afterEach, expect} from "vitest"; -import {Connection} from "@libp2p/interface/connection"; -import {CustomEvent} from "@libp2p/interface/events"; +import {Connection} from "@libp2p/interface"; +import {CustomEvent} from "@libp2p/interface"; import sinon from "sinon"; import {BitArray} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; diff --git a/packages/beacon-node/test/perf/network/noise/sendData.test.ts b/packages/beacon-node/test/perf/network/noise/sendData.test.ts index a6843c13ece2..35538a417adf 100644 --- a/packages/beacon-node/test/perf/network/noise/sendData.test.ts +++ b/packages/beacon-node/test/perf/network/noise/sendData.test.ts @@ -3,7 +3,9 @@ import {duplexPair} from "it-pair/duplex"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {pipe} from "it-pipe"; import drain from "it-drain"; -import {createNoise} from "../../../../src/network/libp2p/noise.js"; +import {defaultLogger} from "@libp2p/logger"; +import {noise} from "@chainsafe/libp2p-noise"; +import {Uint8ArrayList} from "uint8arraylist"; describe("network / noise / sendData", () => { const numberOfMessages = 1000; @@ -24,10 +26,10 @@ describe("network / noise / sendData", () => { beforeEach: async () => { const peerA = await createSecp256k1PeerId(); const peerB = await createSecp256k1PeerId(); - const noiseA = createNoise()(); - const noiseB = createNoise()(); + const noiseA = noise()({logger: defaultLogger()}); + const noiseB = noise()({logger: defaultLogger()}); - const [inboundConnection, outboundConnection] = duplexPair(); + const [inboundConnection, outboundConnection] = duplexPair(); const [outbound, inbound] = await Promise.all([ noiseA.secureOutbound(peerA, outboundConnection, peerB), noiseB.secureInbound(peerB, inboundConnection, peerA), diff --git a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts index b58199ea8e71..a0d648a161ea 100644 --- a/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts +++ b/packages/beacon-node/test/perf/network/peers/util/prioritizePeers.test.ts @@ -1,5 +1,5 @@ import {itBench} from "@dapplion/benchmark"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; import {altair, phase0} from "@lodestar/types"; diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index 6f6591d00842..cc9ef9b7d711 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {BitArray} from "@chainsafe/ssz"; import {describe, it, expect} from "vitest"; diff --git a/packages/beacon-node/test/unit/network/reqresp/utils.ts b/packages/beacon-node/test/unit/network/reqresp/utils.ts index 455bd6c89104..a1a1a6c69bd2 100644 --- a/packages/beacon-node/test/unit/network/reqresp/utils.ts +++ b/packages/beacon-node/test/unit/network/reqresp/utils.ts @@ -1,5 +1,6 @@ import {expect} from "vitest"; -import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface/connection"; +import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface"; +import {logger} from "@libp2p/logger"; import {Uint8ArrayList} from "uint8arraylist"; import {toHexString} from "@chainsafe/ssz"; import {Root} from "@lodestar/types"; @@ -35,6 +36,7 @@ export function expectEqualByteChunks(chunks: Uint8Array[], expectedChunks: Uint */ export class MockLibP2pStream implements Stream { id = "mock"; + log = logger("mock"); direction: Direction = "inbound"; timeline = { open: Date.now(), diff --git a/packages/beacon-node/test/utils/network.ts b/packages/beacon-node/test/utils/network.ts index 44615f83e0bb..5b0cdbe04b6c 100644 --- a/packages/beacon-node/test/utils/network.ts +++ b/packages/beacon-node/test/utils/network.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {BitArray} from "@chainsafe/ssz"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; diff --git a/packages/beacon-node/test/utils/node/beacon.ts b/packages/beacon-node/test/utils/node/beacon.ts index 92b09f0e02b6..8c1ae9503b7c 100644 --- a/packages/beacon-node/test/utils/node/beacon.ts +++ b/packages/beacon-node/test/utils/node/beacon.ts @@ -1,6 +1,6 @@ import deepmerge from "deepmerge"; import tmp from "tmp"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {config as minimalConfig} from "@lodestar/config/default"; import {createBeaconConfig, createChainForkConfig, ChainConfig} from "@lodestar/config"; diff --git a/packages/beacon-node/test/utils/node/p2p.ts b/packages/beacon-node/test/utils/node/p2p.ts index 40ddfc3c5a85..7f534d3ab4ae 100644 --- a/packages/beacon-node/test/utils/node/p2p.ts +++ b/packages/beacon-node/test/utils/node/p2p.ts @@ -1,5 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; -import {Direction} from "@libp2p/interface/connection"; +import {Direction, PeerId} from "@libp2p/interface"; import {routes} from "@lodestar/api"; export function lodestarNodePeer( diff --git a/packages/beacon-node/test/utils/peer.ts b/packages/beacon-node/test/utils/peer.ts index aae9df41e51a..8bd5c6c67be8 100644 --- a/packages/beacon-node/test/utils/peer.ts +++ b/packages/beacon-node/test/utils/peer.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {peerIdFromBytes} from "@libp2p/peer-id"; import {peerIdToString} from "../../src/util/peerId.js"; diff --git a/packages/cli/package.json b/packages/cli/package.json index 60fd19ae9e73..594ef5ebbb67 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -58,13 +58,14 @@ "@chainsafe/bls-keygen": "^0.3.0", "@chainsafe/bls-keystore": "^3.0.0", "@chainsafe/blst": "^0.2.9", - "@chainsafe/discv5": "^5.1.0", + "@chainsafe/discv5": "^7.1.0", + "@chainsafe/enr": "^2.0.2", "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/ssz": "^0.14.0", "@chainsafe/threads": "^1.11.1", - "@libp2p/crypto": "^2.0.4", - "@libp2p/peer-id": "^3.0.2", - "@libp2p/peer-id-factory": "^3.0.4", + "@libp2p/crypto": "^3.0.4", + "@libp2p/peer-id": "^4.0.4", + "@libp2p/peer-id-factory": "^4.0.3", "@lodestar/api": "^1.14.0", "@lodestar/beacon-node": "^1.14.0", "@lodestar/config": "^1.14.0", @@ -91,7 +92,7 @@ "prom-client": "^15.1.0", "rimraf": "^4.4.1", "source-map-support": "^0.5.21", - "uint8arrays": "^4.0.3", + "uint8arrays": "^4.0.9", "uuidv4": "^6.2.13", "yargs": "^17.7.1" }, diff --git a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts index 37c5d766d7a3..58246e3a9199 100644 --- a/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts +++ b/packages/cli/src/cmds/beacon/initPeerIdAndEnr.ts @@ -1,10 +1,10 @@ import fs from "node:fs"; import path from "node:path"; import os from "node:os"; -import type {PeerId} from "@libp2p/interface/peer-id"; +import type {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {Multiaddr} from "@multiformats/multiaddr"; -import {createKeypairFromPeerId, SignableENR} from "@chainsafe/discv5"; +import {createPrivateKeyFromPeerId, SignableENR} from "@chainsafe/enr"; import {Logger} from "@lodestar/utils"; import {exportToJSON, readPeerId} from "../../config/index.js"; import {writeFile600Perm} from "../../util/file.js"; @@ -142,7 +142,7 @@ export async function initPeerIdAndEnr( const newPeerIdAndENR = async (): Promise<{peerId: PeerId; enr: SignableENR}> => { const peerId = await createSecp256k1PeerId(); - const enr = SignableENR.createV4(createKeypairFromPeerId(peerId)); + const enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); return {peerId, enr}; }; @@ -162,16 +162,16 @@ export async function initPeerIdAndEnr( } // attempt to read stored enr try { - enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), createKeypairFromPeerId(peerId)); + enr = SignableENR.decodeTxt(fs.readFileSync(enrFile, "utf-8"), createPrivateKeyFromPeerId(peerId).privateKey); } catch (e) { logger.warn("Unable to decode stored local ENR, creating a new ENR"); - enr = SignableENR.createV4(createKeypairFromPeerId(peerId)); + enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); return {peerId, enr, newEnr: true}; } // check stored peer id against stored enr if (!peerId.equals(await enr.peerId())) { logger.warn("Stored local ENR doesn't match peerIdFile, creating a new ENR"); - enr = SignableENR.createV4(createKeypairFromPeerId(peerId)); + enr = SignableENR.createV4(createPrivateKeyFromPeerId(peerId).privateKey); return {peerId, enr, newEnr: true}; } return {peerId, enr, newEnr: false}; diff --git a/packages/cli/src/cmds/bootnode/handler.ts b/packages/cli/src/cmds/bootnode/handler.ts index 7bf9169cfdc6..77851b1fcb88 100644 --- a/packages/cli/src/cmds/bootnode/handler.ts +++ b/packages/cli/src/cmds/bootnode/handler.ts @@ -1,6 +1,7 @@ import path from "node:path"; import {Multiaddr, multiaddr} from "@multiformats/multiaddr"; -import {Discv5, ENR, IDiscv5CreateOptions} from "@chainsafe/discv5"; +import {Discv5} from "@chainsafe/discv5"; +import {ENR} from "@chainsafe/enr"; import {ErrorAborted} from "@lodestar/utils"; import {HttpMetricsServer, RegistryMetricCreator, getHttpMetricsServer} from "@lodestar/beacon-node"; @@ -58,7 +59,7 @@ export async function bootnodeHandler(args: BootnodeArgs & GlobalArgs): Promise< ip6: bindAddrs.ip6 ? multiaddr(bindAddrs.ip6) : undefined, }, config: {enrUpdate: !enr.ip && !enr.ip6}, - metricsRegistry: metricsRegistry as IDiscv5CreateOptions["metricsRegistry"], + metricsRegistry, }); // If there are any bootnodes, add them to the routing table diff --git a/packages/cli/src/config/peerId.ts b/packages/cli/src/config/peerId.ts index 9ddd26460846..d4906c716ba7 100644 --- a/packages/cli/src/config/peerId.ts +++ b/packages/cli/src/config/peerId.ts @@ -1,4 +1,4 @@ -import type {PeerId} from "@libp2p/interface/peer-id"; +import type {PeerId} from "@libp2p/interface"; import {peerIdFromBytes} from "@libp2p/peer-id"; import {createFromPrivKey, createFromPubKey} from "@libp2p/peer-id-factory"; import {unmarshalPrivateKey, unmarshalPublicKey} from "@libp2p/crypto/keys"; diff --git a/packages/cli/src/networks/index.ts b/packages/cli/src/networks/index.ts index 85846164b473..c7d4b5301062 100644 --- a/packages/cli/src/networks/index.ts +++ b/packages/cli/src/networks/index.ts @@ -1,6 +1,6 @@ import fs from "node:fs"; import got from "got"; -import {ENR} from "@chainsafe/discv5"; +import {ENR} from "@chainsafe/enr"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ApiError, getClient} from "@lodestar/api"; import {getStateTypeFromBytes} from "@lodestar/beacon-node"; diff --git a/packages/cli/src/options/beaconNodeOptions/network.ts b/packages/cli/src/options/beaconNodeOptions/network.ts index 745308ec7c8c..79ec3d710d44 100644 --- a/packages/cli/src/options/beaconNodeOptions/network.ts +++ b/packages/cli/src/options/beaconNodeOptions/network.ts @@ -1,5 +1,5 @@ import {multiaddr} from "@multiformats/multiaddr"; -import {ENR} from "@chainsafe/discv5"; +import {ENR} from "@chainsafe/enr"; import {defaultOptions, IBeaconNodeOptions} from "@lodestar/beacon-node"; import {CliCommandOptions, YargsError} from "../../util/index.js"; diff --git a/packages/cli/test/unit/cmds/beacon.test.ts b/packages/cli/test/unit/cmds/beacon.test.ts index 7d111b3362a8..fc1f50ad1251 100644 --- a/packages/cli/test/unit/cmds/beacon.test.ts +++ b/packages/cli/test/unit/cmds/beacon.test.ts @@ -3,7 +3,7 @@ import fs from "node:fs"; import {describe, it, expect} from "vitest"; import {createFromJSON, createSecp256k1PeerId} from "@libp2p/peer-id-factory"; import {multiaddr} from "@multiformats/multiaddr"; -import {createKeypairFromPeerId, ENR, SignableENR} from "@chainsafe/discv5"; +import {createPrivateKeyFromPeerId, ENR, SignableENR} from "@chainsafe/enr"; import {chainConfig} from "@lodestar/config/default"; import {chainConfigToJson} from "@lodestar/config"; import {LogLevel} from "@lodestar/utils"; @@ -66,7 +66,7 @@ describe("cmds / beacon / args handler", () => { const peerIdFile = path.join(testFilesDir, "peer-id.json"); fs.writeFileSync(peerIdFile, JSON.stringify(exportToJSON(prevPeerId))); - const enr = SignableENR.createV4(createKeypairFromPeerId(prevPeerId)); + const enr = SignableENR.createV4(createPrivateKeyFromPeerId(prevPeerId).privateKey); const enrFilePath = path.join(testFilesDir, "enr"); fs.writeFileSync(enrFilePath, enr.encodeTxt()); diff --git a/packages/db/package.json b/packages/db/package.json index 1bccf368c55f..13ffff098279 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -41,7 +41,7 @@ "@lodestar/config": "^1.14.0", "@lodestar/utils": "^1.14.0", "@types/levelup": "^4.3.3", - "it-all": "^3.0.2", + "it-all": "^3.0.4", "level": "^8.0.0" }, "devDependencies": { diff --git a/packages/light-client/package.json b/packages/light-client/package.json index 3270dc14f088..f34fe11601e8 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -83,7 +83,7 @@ "@chainsafe/as-sha256": "^0.3.1", "@types/qs": "^6.9.7", "qs": "^6.11.1", - "uint8arrays": "^4.0.3" + "uint8arrays": "^4.0.9" }, "keywords": [ "ethereum", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 9d81d082d087..8cea3d0d6072 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -55,24 +55,24 @@ }, "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", - "@libp2p/interface": "^0.1.2", + "@libp2p/interface": "^1.1.1", "@lodestar/config": "^1.14.0", "@lodestar/params": "^1.14.0", "@lodestar/utils": "^1.14.0", - "it-all": "^3.0.2", + "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", "snappyjs": "^0.7.0", - "uint8-varint": "^2.0.1", - "uint8arraylist": "^2.4.3" + "uint8-varint": "^2.0.2", + "uint8arraylist": "^2.4.7" }, "devDependencies": { "@lodestar/logger": "^1.14.0", "@lodestar/types": "^1.14.0", - "libp2p": "0.46.12" + "libp2p": "1.1.1" }, "peerDependencies": { - "libp2p": "~0.46.12" + "libp2p": "~1.1.1" }, "keywords": [ "ethereum", diff --git a/packages/reqresp/src/ReqResp.ts b/packages/reqresp/src/ReqResp.ts index 671df3c83662..d89acd8e2689 100644 --- a/packages/reqresp/src/ReqResp.ts +++ b/packages/reqresp/src/ReqResp.ts @@ -1,6 +1,5 @@ import {setMaxListeners} from "node:events"; -import {Connection, Stream} from "@libp2p/interface/connection"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {Connection, PeerId, Stream} from "@libp2p/interface"; import type {Libp2p} from "libp2p"; import {Logger, MetricsRegister} from "@lodestar/utils"; import {getMetrics, Metrics} from "./metrics.js"; diff --git a/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts b/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts index 36bbe7df5ff2..66dfbd9f1cc7 100644 --- a/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts +++ b/packages/reqresp/src/rate_limiter/ReqRespRateLimiter.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {InboundRateLimitQuota, ReqRespRateLimiterOpts} from "../types.js"; import {RateLimiterGRCA} from "./rateLimiterGRCA.js"; diff --git a/packages/reqresp/src/request/index.ts b/packages/reqresp/src/request/index.ts index e1923c8856b4..4920a32eb221 100644 --- a/packages/reqresp/src/request/index.ts +++ b/packages/reqresp/src/request/index.ts @@ -1,5 +1,5 @@ import {pipe} from "it-pipe"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import type {Libp2p} from "libp2p"; import {Uint8ArrayList} from "uint8arraylist"; import {ErrorAborted, Logger, withTimeout, TimeoutError} from "@lodestar/utils"; diff --git a/packages/reqresp/src/response/index.ts b/packages/reqresp/src/response/index.ts index 288111c12093..27758caa3f24 100644 --- a/packages/reqresp/src/response/index.ts +++ b/packages/reqresp/src/response/index.ts @@ -1,6 +1,5 @@ import {pipe} from "it-pipe"; -import {PeerId} from "@libp2p/interface/peer-id"; -import {Stream} from "@libp2p/interface/connection"; +import {PeerId, Stream} from "@libp2p/interface"; import {Uint8ArrayList} from "uint8arraylist"; import {Logger, TimeoutError, withTimeout} from "@lodestar/utils"; import {prettyPrintPeerId} from "../utils/index.js"; diff --git a/packages/reqresp/src/types.ts b/packages/reqresp/src/types.ts index a9fff1d70252..c52cab895b61 100644 --- a/packages/reqresp/src/types.ts +++ b/packages/reqresp/src/types.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {BeaconConfig, ForkDigestContext} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; import {LodestarError} from "@lodestar/utils"; diff --git a/packages/reqresp/src/utils/peerId.ts b/packages/reqresp/src/utils/peerId.ts index 7f62ebd2171f..b358a3b2a466 100644 --- a/packages/reqresp/src/utils/peerId.ts +++ b/packages/reqresp/src/utils/peerId.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; export function prettyPrintPeerId(peerId: PeerId): string { const id = peerId.toString(); diff --git a/packages/reqresp/test/unit/request/index.test.ts b/packages/reqresp/test/unit/request/index.test.ts index b3241a8cc44a..888520457bb2 100644 --- a/packages/reqresp/test/unit/request/index.test.ts +++ b/packages/reqresp/test/unit/request/index.test.ts @@ -1,5 +1,5 @@ import {describe, it, expect, vi, beforeEach, afterEach} from "vitest"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import all from "it-all"; import {pipe} from "it-pipe"; import {Libp2p} from "libp2p"; diff --git a/packages/reqresp/test/unit/response/index.test.ts b/packages/reqresp/test/unit/response/index.test.ts index 5ab299b586ab..62a8e63f3fe0 100644 --- a/packages/reqresp/test/unit/response/index.test.ts +++ b/packages/reqresp/test/unit/response/index.test.ts @@ -1,5 +1,5 @@ import {describe, it, expect, beforeEach, afterEach} from "vitest"; -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {LodestarError, fromHex} from "@lodestar/utils"; import {getEmptyLogger} from "@lodestar/logger/empty"; import {Protocol, RespStatus} from "../../../src/index.js"; diff --git a/packages/reqresp/test/utils/index.ts b/packages/reqresp/test/utils/index.ts index 924218c73cd4..98a7387233ba 100644 --- a/packages/reqresp/test/utils/index.ts +++ b/packages/reqresp/test/utils/index.ts @@ -1,4 +1,5 @@ -import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface/connection"; +import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface"; +import {logger} from "@libp2p/logger"; import {expect} from "chai"; import {Uint8ArrayList} from "uint8arraylist"; import {toHexString} from "@chainsafe/ssz"; @@ -37,6 +38,7 @@ export function expectInEqualByteChunks(chunks: Uint8Array[], expectedChunks: Ui export class MockLibP2pStream implements Stream { protocol: string; id = "mock"; + log = logger("mock"); direction: Direction = "inbound"; status: StreamStatus = "open"; readStatus: ReadStatus = "ready"; diff --git a/packages/reqresp/test/utils/peer.ts b/packages/reqresp/test/utils/peer.ts index 34af7d2a9317..43edaefbafdd 100644 --- a/packages/reqresp/test/utils/peer.ts +++ b/packages/reqresp/test/utils/peer.ts @@ -1,4 +1,4 @@ -import {PeerId} from "@libp2p/interface/peer-id"; +import {PeerId} from "@libp2p/interface"; import {peerIdFromBytes} from "@libp2p/peer-id"; /** diff --git a/yarn.lock b/yarn.lock index 6e1a1681d774..28ddde61a8cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,31 +7,6 @@ resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== -"@achingbrain/nat-port-mapper@^1.0.9": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@achingbrain/nat-port-mapper/-/nat-port-mapper-1.0.9.tgz#8e61cf6f5dbeaa55c4e64a0023a362d4a1f61a36" - integrity sha512-w1M7dh7IsO5fvX9VQpH0w8MMphzLUl52Kf+paXTScNmFH4Ua+R6XI+x5p7LI3vY36JkTllTqAxNo8g1y0CMCrA== - dependencies: - "@achingbrain/ssdp" "^4.0.1" - "@libp2p/logger" "^2.0.0" - default-gateway "^6.0.2" - err-code "^3.0.1" - it-first "^3.0.1" - p-defer "^4.0.0" - p-timeout "^6.1.1" - xml2js "^0.6.0" - -"@achingbrain/ssdp@^4.0.1": - version "4.0.1" - resolved "https://registry.yarnpkg.com/@achingbrain/ssdp/-/ssdp-4.0.1.tgz#47ccaaa8256cf73b7b2ab86a0ad14128cfaf77b7" - integrity sha512-z/CkfFI0Ksrpo8E+lu2rKahlE1KJHUn8X8ihQj2Jg6CEL+oHYGCNfttOES0+VnV7htuog70c8bYNHYhlmmqxBQ== - dependencies: - event-iterator "^2.0.0" - freeport-promise "^2.0.0" - merge-options "^3.0.4" - uuid "^8.3.2" - xml2js "^0.4.23" - "@actions/cache@^1.0.7": version "1.0.7" resolved "https://registry.npmjs.org/@actions/cache/-/cache-1.0.7.tgz" @@ -599,25 +574,37 @@ node-fetch "^2.6.1" node-gyp "^8.4.0" -"@chainsafe/discv5@^5.1.0": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-5.1.1.tgz#537826c24dc1190aaf795810e2afccf188e173ff" - integrity sha512-Zcv7fyKirKta305/gTX+wvFA2Ockx+FxUTW+/Yj37+idFjt/UrGho4tcPGyPJC/46cXp+NRGI1wNqsh54+Hnow== +"@chainsafe/discv5@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/discv5/-/discv5-7.1.0.tgz#c892075c84bdc75428774d4993e7346205ff8724" + integrity sha512-spO801KWe0C9XrXkVt4E1paXP1ZtfsgxOf+FSW6yCDQTWFVGRfcl/ww4B7JtdJOnZauqaHqXxAuNBpSafJoalw== dependencies: - "@libp2p/crypto" "^2.0.0" - "@libp2p/interface" "^0.1.2" - "@libp2p/peer-id" "^3.0.1" - "@multiformats/multiaddr" "^12.1.3" - base64url "^3.0.1" + "@chainsafe/enr" "^2.0.2" + "@libp2p/crypto" "^3.0.4" + "@libp2p/interface" "^1.1.1" + "@multiformats/multiaddr" "^12.1.10" bcrypto "^5.4.0" bigint-buffer "^1.1.5" debug "^4.3.1" - dgram "^1.0.1" err-code "^3.0.1" - lru-cache "^6.0.0" + lru-cache "^10.1.0" rlp "^2.2.6" strict-event-emitter-types "^2.0.0" - uint8-varint "^2.0.1" + +"@chainsafe/enr@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@chainsafe/enr/-/enr-2.0.2.tgz#29814ae506a87d466640cddbac49369029334f09" + integrity sha512-90IEkHHb5ZHk2BuyX5QkLomaxH+HXF41wFOzDC2Hpla6c3ersxAJJms4kJSot7j20Uzfka4Xjxvkwjj8WfL77g== + dependencies: + "@libp2p/crypto" "^3.0.4" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" + "@multiformats/multiaddr" "^12.1.10" + base64url "^3.0.1" + bcrypto "^5.4.0" + bigint-buffer "^1.1.5" + rlp "^2.2.6" + uint8-varint "^2.0.2" "@chainsafe/eslint-plugin-node@^11.2.3": version "11.2.3" @@ -649,17 +636,16 @@ resolved "https://registry.yarnpkg.com/@chainsafe/is-ip/-/is-ip-2.0.2.tgz#7311e7403f11d8c5cfa48111f56fcecaac37c9f6" integrity sha512-ndGqEMG1W5WkGagaqOZHpPU172AGdxr+LD15sv3WIUvT5oCFUrG1Y0CW/v2Egwj4JXEvSibaIIIqImsm98y1nA== -"@chainsafe/libp2p-gossipsub@^10.1.1": - version "10.1.1" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-10.1.1.tgz#906aa2a67efb5fea0bacc6721ef4e7ee4e353d7e" - integrity sha512-nou65zlGaUIPwlUq7ceEVpszJX4tBWRRanppYaKsJk7rbDeIKRJQla2duATGOI3fwj1+pGSlDQuF2zG7P0VJQw== - dependencies: - "@libp2p/crypto" "^2.0.0" - "@libp2p/interface" "^0.1.4" - "@libp2p/interface-internal" "^0.1.0" - "@libp2p/logger" "^3.0.0" - "@libp2p/peer-id" "^3.0.0" - "@libp2p/pubsub" "^8.0.0" +"@chainsafe/libp2p-gossipsub@^11.1.0": + version "11.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-gossipsub/-/libp2p-gossipsub-11.1.0.tgz#e5ebd8dd08601845073f3b8c9601e047d7bdc279" + integrity sha512-6baEtpC9gu5D9bXv86zIdNIOekKgQPV3KRWvnsldtsKpiWtUv6K2mLsl3wsDi0nW/c3zxTAneaJMTLQoSXysJQ== + dependencies: + "@libp2p/crypto" "^3.0.1" + "@libp2p/interface" "^1.0.1" + "@libp2p/interface-internal" "^1.0.1" + "@libp2p/peer-id" "^4.0.1" + "@libp2p/pubsub" "^9.0.0" "@multiformats/multiaddr" "^12.1.3" abortable-iterator "^5.0.1" denque "^2.1.0" @@ -671,16 +657,17 @@ uint8arraylist "^2.4.3" uint8arrays "^4.0.4" -"@chainsafe/libp2p-noise@^13.0.1": - version "13.0.1" - resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-13.0.1.tgz#d6309d50b2a36014e8fb4781c9d7af3723659d2a" - integrity sha512-eeOFubXyS9sK0oBg/qRfve6LVGzZX1vyULVidaKGTJr8Y4dtyU4+Btqw/aVo3o1lhdvb/qoY+p/Ep2pUsvJKhg== - dependencies: - "@libp2p/crypto" "^2.0.0" - "@libp2p/interface" "^0.1.0" - "@libp2p/logger" "^3.0.0" - "@libp2p/peer-id" "^3.0.0" - "@noble/ciphers" "^0.3.0" +"@chainsafe/libp2p-noise@^14.1.0": + version "14.1.0" + resolved "https://registry.yarnpkg.com/@chainsafe/libp2p-noise/-/libp2p-noise-14.1.0.tgz#4084a448cec73a941fddfc94751f6ce2e23c07cd" + integrity sha512-uHmptoxgMsfDIP7cQMQ4Zp9+y27oON5+gloBLXi+7EJpMhyvo7tjafUxRILwLofzeAtfaF3ZHraoXRFUSbhK2Q== + dependencies: + "@chainsafe/as-chacha20poly1305" "^0.1.0" + "@chainsafe/as-sha256" "^0.4.1" + "@libp2p/crypto" "^3.0.0" + "@libp2p/interface" "^1.0.0" + "@libp2p/peer-id" "^4.0.0" + "@noble/ciphers" "^0.4.0" "@noble/curves" "^1.1.0" "@noble/hashes" "^1.3.1" it-byte-stream "^1.0.0" @@ -691,7 +678,8 @@ it-stream-types "^2.0.1" protons-runtime "^5.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.4" + uint8arrays "^5.0.0" + wherearewe "^2.0.1" "@chainsafe/netmask@^2.0.0": version "2.0.0" @@ -1720,283 +1708,246 @@ yargs "16.2.0" yargs-parser "20.2.4" -"@libp2p/bootstrap@^9.0.7": - version "9.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-9.0.7.tgz#bcc7682ff153f48a021f3c085311962917403643" - integrity sha512-xpDJlxBGYSa4eVm3GWChtY9QL58Oh1PowtowMEuE5TEW1zcLzvQaQ9YiG2Mo9+q+0CNnAyemJF5rBequ7XbLBQ== +"@libp2p/bootstrap@^10.0.10": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@libp2p/bootstrap/-/bootstrap-10.0.10.tgz#7cb64b19ecb4d6222499f50f5b3ff59f898bd316" + integrity sha512-VJ0+uNld94oGnLPyPdCLNhnOdTmqFP4E9OCAiyFZjSeaqS6qMblNR4yHz+Zgmk/sp+vNXILVYs5BRf6cW4bm/Q== dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@libp2p/peer-id" "^3.0.2" - "@multiformats/mafmt" "^12.1.2" - "@multiformats/multiaddr" "^12.1.5" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" + "@multiformats/mafmt" "^12.1.6" + "@multiformats/multiaddr" "^12.1.10" -"@libp2p/crypto@^2.0.0", "@libp2p/crypto@^2.0.2", "@libp2p/crypto@^2.0.4": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-2.0.4.tgz#f0c6fcf246c8b6974e4fc92499a0bdce19c3c54c" - integrity sha512-1/PDtJC+k64Sd0bzK4DvGflk8Brj5fGskRCfBOndhNmitjHe8+ewbuA9lldTOerfkVgMn7Zb+sjNsytyr6BqlA== +"@libp2p/crypto@^3.0.0", "@libp2p/crypto@^3.0.1", "@libp2p/crypto@^3.0.4": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/crypto/-/crypto-3.0.4.tgz#8768b262c24a036774c6c5e290a1f0d76535a7d3" + integrity sha512-FzSwBo+RJOUzdzEwug5ZL4dAGKwEBWTLzj+EmUTHHY6c87+oLh571DQk/w0oYObSD9hYbcKePgSBaZeBx0JaZg== dependencies: - "@libp2p/interface" "^0.1.2" + "@libp2p/interface" "^1.1.1" "@noble/curves" "^1.1.0" "@noble/hashes" "^1.3.1" - multiformats "^12.0.1" + multiformats "^13.0.0" node-forge "^1.1.0" protons-runtime "^5.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" + uint8arrays "^5.0.0" -"@libp2p/interface-internal@^0.1.0", "@libp2p/interface-internal@^0.1.2", "@libp2p/interface-internal@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-0.1.5.tgz#819d15c3b0b2cd25e1be59aacc2c5cb42fe811e3" - integrity sha512-h6f1fk2M6BhqjooE4I1iODmY/jorCvJ1bX1IOMHOMNkrbwsMS2BOpDkBJD+u+QlKMoRIA2zEfWezXB4Pa8GASw== - dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/peer-collections" "^4.0.4" - "@multiformats/multiaddr" "^12.1.5" +"@libp2p/identify@^1.0.9": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@libp2p/identify/-/identify-1.0.9.tgz#6756d74919b7a171c7cdcdce45669b9f633fbb0f" + integrity sha512-zDJofRDMlB3XYM2vvH/D/XrFeE9JzwVW09GPTMplGoECdq25Id7V4nWhkdNOmAQOQkhl/lFZmZHF7ZjCDgLybQ== + dependencies: + "@libp2p/interface" "^1.1.1" + "@libp2p/interface-internal" "^1.0.5" + "@libp2p/peer-id" "^4.0.4" + "@libp2p/peer-record" "^7.0.4" + "@multiformats/multiaddr" "^12.1.10" + "@multiformats/multiaddr-matcher" "^1.1.0" + it-protobuf-stream "^1.0.2" + protons-runtime "^5.0.0" uint8arraylist "^2.4.3" + uint8arrays "^5.0.0" + wherearewe "^2.0.1" -"@libp2p/interface-peer-id@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@libp2p/interface-peer-id/-/interface-peer-id-2.0.2.tgz#6302e70b6fc17c451bc3daa11447d059357bcc32" - integrity sha512-9pZp9zhTDoVwzRmp0Wtxw0Yfa//Yc0GqBCJi3EznBDE6HGIAVvppR91wSh2knt/0eYg0AQj7Y35VSesUTzMCUg== - dependencies: - multiformats "^11.0.0" - -"@libp2p/interface@^0.1.0", "@libp2p/interface@^0.1.1", "@libp2p/interface@^0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-0.1.2.tgz#4ea5a4fa8bbd46c3fe4c945ff6b8c6d5d41f10b0" - integrity sha512-Q5t27434Mvn+R6AUJlRH+q/jSXarDpP+KXVkyGY7S1fKPI2berqoFPqT61bRRBYsCH2OPZiKBB53VUzxL9uEvg== +"@libp2p/interface-internal@^1.0.1", "@libp2p/interface-internal@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@libp2p/interface-internal/-/interface-internal-1.0.5.tgz#b7687e4c5cb765fd686fcd442d2cc4c49e8304d7" + integrity sha512-qT4APD2nZKEGnkn4LfM2mzNbYv9bx/2FyvYaJ4exjzIIBPiRmjrek7hfWErKkazCDwO51+WuZ/DERdd32O9Fxg== dependencies: - "@multiformats/multiaddr" "^12.1.5" - abortable-iterator "^5.0.1" - it-pushable "^3.2.0" - it-stream-types "^2.0.1" - multiformats "^12.0.1" - p-defer "^4.0.0" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-collections" "^5.1.3" + "@multiformats/multiaddr" "^12.1.10" uint8arraylist "^2.4.3" -"@libp2p/interface@^0.1.4": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-0.1.6.tgz#1328cf6086f02c499183489ccb143fe9c159e871" - integrity sha512-Lzc5cS/hXuoXhuAbVIxJIHLCYmfPcbU0vVgrpMoiP1Qb2Q3ETU4A46GB8s8mWXgSU6tr9RcqerUqzFYD6+OAag== +"@libp2p/interface@^1.0.0", "@libp2p/interface@^1.0.1", "@libp2p/interface@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@libp2p/interface/-/interface-1.1.1.tgz#f37ea4930bd74e1299fbcafa49fdab39a28abba9" + integrity sha512-g6xgF+q38ZDTRkjuJfuOByS4N0zGld+VPRiWPXYX8wA/9vS6lqJwKUoC6V33KUhP/zXHCkJaSD6z94fUbNM8vw== dependencies: - "@multiformats/multiaddr" "^12.1.5" - abortable-iterator "^5.0.1" - it-pushable "^3.2.0" + "@multiformats/multiaddr" "^12.1.10" + it-pushable "^3.2.1" it-stream-types "^2.0.1" - multiformats "^12.0.1" - p-defer "^4.0.0" - race-signal "^1.0.0" + multiformats "^13.0.0" + progress-events "^1.0.0" uint8arraylist "^2.4.3" -"@libp2p/keychain@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/keychain/-/keychain-3.0.4.tgz#94d04a592ea18d83ebed6d6d8457e9aa8cc72e91" - integrity sha512-qt9Ttv2lczOpxkbe5YmqwqJx9nty4pWEE9sJ4rY2Ci2k1K+Bt2vMla610BFBzcYq0QqYYqNN4pawFZ33sc3iLg== - dependencies: - "@libp2p/crypto" "^2.0.4" - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@libp2p/peer-id" "^3.0.2" - interface-datastore "^8.2.0" - merge-options "^3.0.4" - sanitize-filename "^1.6.3" - uint8arrays "^4.0.6" - -"@libp2p/logger@^2.0.0": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-2.1.1.tgz#e12e6c320ea64252af954bcec996895098d1cd36" - integrity sha512-2UbzDPctg3cPupF6jrv6abQnAUTrbLybNOj0rmmrdGm1cN2HJ1o/hBu0sXuq4KF9P1h/eVRn1HIRbVIEKnEJrA== - dependencies: - "@libp2p/interface-peer-id" "^2.0.2" - "@multiformats/multiaddr" "^12.1.3" - debug "^4.3.4" - interface-datastore "^8.2.0" - multiformats "^11.0.2" - -"@libp2p/logger@^3.0.0", "@libp2p/logger@^3.0.1", "@libp2p/logger@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-3.0.2.tgz#aa507db233c6905692ffaf9f4daba1e6326992c4" - integrity sha512-2JtRGBXiGfm1t5XneUIXQ2JusW7QwyYmxsW7hSAYS5J73RQJUicpt5le5obVRt7+OM39ei+nWEuC6Xvm1ugHkw== +"@libp2p/logger@^4.0.1", "@libp2p/logger@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/logger/-/logger-4.0.4.tgz#98c5357e8b857d93a506f6818db6abe734d342ee" + integrity sha512-lr6/Cmj9VhtET4ZnRhWls4kY4K5moTAIEZtZugmkflT4qJXJywkmn/EpLO3kjgE+PDjrgOr8lUVVJBGvEHL8Jg== dependencies: - "@libp2p/interface" "^0.1.2" - "@multiformats/multiaddr" "^12.1.5" + "@libp2p/interface" "^1.1.1" + "@multiformats/multiaddr" "^12.1.10" debug "^4.3.4" interface-datastore "^8.2.0" - multiformats "^12.0.1" - -"@libp2p/mdns@^9.0.9": - version "9.0.9" - resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-9.0.9.tgz#9ef4944b71204e6578f2283c9634dec61da58ada" - integrity sha512-Id3iPJa1TRomYH1rIgcPxQTFpVlhscU5b8wqulzYSyzShggnM4MoxisrgLoSSySVzIrgIlKRTG8/m03neLIrZw== - dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@libp2p/peer-id" "^3.0.2" - "@libp2p/utils" "^4.0.3" - "@multiformats/multiaddr" "^12.1.5" + multiformats "^13.0.0" + +"@libp2p/mdns@^10.0.10": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@libp2p/mdns/-/mdns-10.0.10.tgz#02f08f1a485e3640ce575460af63a0b8c4171b64" + integrity sha512-Zxwbvg+rkmjE5YNue9Bldl/mpQS3BPMZlPPLjwQkVFRVjJdsBuWAWNFy08rzjYZunjBP1N4RMUdncrbjAYnoSg== + dependencies: + "@libp2p/interface" "^1.1.1" + "@libp2p/interface-internal" "^1.0.5" + "@libp2p/peer-id" "^4.0.4" + "@libp2p/utils" "^5.2.0" + "@multiformats/multiaddr" "^12.1.10" "@types/multicast-dns" "^7.2.1" dns-packet "^5.4.0" multicast-dns "^7.2.5" -"@libp2p/mplex@^9.0.7": - version "9.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-9.0.7.tgz#c8233d184c5142453776bc59cc66edb3b399050b" - integrity sha512-ycIjBdEPnVSjW3ZuMVuFk7cwJwK6/Hjd1KFCSXTZ9E8M6df+EQg9m8iw5ObMJNQ5+GWIHUu5+Fq1HquZO06Y9g== +"@libp2p/mplex@^10.0.10": + version "10.0.10" + resolved "https://registry.yarnpkg.com/@libp2p/mplex/-/mplex-10.0.10.tgz#04476551f8ab205c2b6754cc94692264a883629b" + integrity sha512-vwyqjuc/P/co5Kj+FknYl2BJ69es+rM8TmtQ5e/xnTDpaD2JPGIeMhKXC3hSNAIvmL9OHdwqzLGHD98vRfMv/A== dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - abortable-iterator "^5.0.1" - benchmark "^2.1.4" - it-batched-bytes "^2.0.2" - it-pushable "^3.2.0" + "@libp2p/interface" "^1.1.1" + "@libp2p/utils" "^5.2.0" + it-pipe "^3.0.1" + it-pushable "^3.2.1" it-stream-types "^2.0.1" - rate-limiter-flexible "^3.0.0" + rate-limiter-flexible "^4.0.0" uint8-varint "^2.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" + uint8arrays "^5.0.0" -"@libp2p/multistream-select@^4.0.2": - version "4.0.2" - resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-4.0.2.tgz#547ebc682907d1e02f0f3eec311010ebf3b62ec1" - integrity sha512-Ss3kPD+1Z8RFLUT+oN9I2ynEtp/Yj2+rOngU1XjIxustg1nt5lq0kk9hvWJyBexzmuML0xCknNjUXovpRbFPgQ== +"@libp2p/multistream-select@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@libp2p/multistream-select/-/multistream-select-5.1.1.tgz#81b7eddf33a3b87cfbf70bb69c9ae548afb43800" + integrity sha512-hdcsmrqF0ffh/dNjw+KKfllXIJocpxWzlNSGWxswsmoZFV0Krx7HH/kHQDr5f2mehrO08wJyzRCnlKv9LrirAQ== dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - abortable-iterator "^5.0.1" - it-first "^3.0.1" - it-handshake "^4.1.3" - it-length-prefixed "^9.0.1" - it-merge "^3.0.0" - it-pipe "^3.0.1" - it-pushable "^3.2.0" - it-reader "^6.0.1" + "@libp2p/interface" "^1.1.1" + it-length-prefixed "^9.0.3" + it-length-prefixed-stream "^1.1.1" it-stream-types "^2.0.1" + p-defer "^4.0.0" + race-signal "^1.0.2" + uint8-varint "^2.0.2" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" + uint8arrays "^5.0.0" -"@libp2p/peer-collections@^4.0.2", "@libp2p/peer-collections@^4.0.4": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-4.0.4.tgz#56163995e6f7b3178e927b92b9c6e894a93e7f12" - integrity sha512-MGuTtt6a2TLUlr4b1dUAOd43SAe/lxLZX3E9iYeRqI9IWzw6cwvvOzGNTYwAlkBpASCmm0aJpGXDA/r6lpIzMQ== +"@libp2p/peer-collections@^5.0.0", "@libp2p/peer-collections@^5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@libp2p/peer-collections/-/peer-collections-5.1.3.tgz#52734a31fe52f01f2ff67132ed0eae28b3229ae4" + integrity sha512-qiQHO8s4neLaAZmjHHWvPc091Lp9nOEokjnTmrE2/YBNjKoiA1aPCf7gM/KasynuquFceTQBDVd/Y79Mfqxw4w== dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/peer-id" "^3.0.2" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" -"@libp2p/peer-id-factory@^3.0.4": - version "3.0.4" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id-factory/-/peer-id-factory-3.0.4.tgz#8dc6890a99fbd4c6f4a295761cc495e214c81369" - integrity sha512-9xpKb1UdAhKVmPHy/jssOnyJkuyyyIeP5tO3HlaiBQNtDZU66UMQORnEUD6HdYHKfBRInah2JHxTCtm2nUhGcw== +"@libp2p/peer-id-factory@^4.0.3": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@libp2p/peer-id-factory/-/peer-id-factory-4.0.3.tgz#0d6c141ec0a0ee06a14e7c77cec22294069e30db" + integrity sha512-IdSMwn6ogrHOUR6xPhgu6ZMZrIhvnRRJBnslCr09ATzir1Vs77s06OpXiMrZQ5xbEbLJuD52PE8s1Oz2Ei/iLg== dependencies: - "@libp2p/crypto" "^2.0.4" - "@libp2p/interface" "^0.1.2" - "@libp2p/peer-id" "^3.0.2" - multiformats "^12.0.1" + "@libp2p/crypto" "^3.0.4" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" protons-runtime "^5.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" + uint8arrays "^5.0.0" -"@libp2p/peer-id@^3.0.0", "@libp2p/peer-id@^3.0.1", "@libp2p/peer-id@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-3.0.2.tgz#5ca40a687a513c53744513f0c23a44d291e4399d" - integrity sha512-133qGXu9UBiqsYm7nBDJaAh4eiKe79DPLKF+/aRu0Z7gKcX7I0+LewEky4kBt3olhYQSF1CAnJIzD8Dmsn40Yw== +"@libp2p/peer-id@^4.0.0", "@libp2p/peer-id@^4.0.1", "@libp2p/peer-id@^4.0.4": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/peer-id/-/peer-id-4.0.4.tgz#3de8f012f2abdc1ab287ad652d24de587e653ca3" + integrity sha512-UHWpo0f34IOaAhlvMNtCMAFVVhv29Dy3IqNvfugFNwzv5p+Jo6TfPGd78H7RX2WIzyVzIgBYxVxmIIHHcqZQ5Q== dependencies: - "@libp2p/interface" "^0.1.2" - multiformats "^12.0.1" - uint8arrays "^4.0.6" + "@libp2p/interface" "^1.1.1" + multiformats "^13.0.0" + uint8arrays "^5.0.0" -"@libp2p/peer-record@^6.0.5": - version "6.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-6.0.5.tgz#19e102ecd96b50421ed10e5563e0e5a5d6aeaa7c" - integrity sha512-+nJpi9L6X+cYdu1UWL/W36+3pmL0Ev7/HpX9J/bESsICP8rSN2N1aFlekqJq2v7TW4dJ3VJO7TcMZCcKcLhZCQ== - dependencies: - "@libp2p/crypto" "^2.0.4" - "@libp2p/interface" "^0.1.2" - "@libp2p/peer-id" "^3.0.2" - "@libp2p/utils" "^4.0.3" - "@multiformats/multiaddr" "^12.1.5" +"@libp2p/peer-record@^7.0.4": + version "7.0.4" + resolved "https://registry.yarnpkg.com/@libp2p/peer-record/-/peer-record-7.0.4.tgz#8c19cef2a3d82da576942440d67c482c5a0f344a" + integrity sha512-4UXsfo22qT3BnWfBkGp0jgrNPJjBI60ehZV9piB/3EIeT7hLIvuBuBbn3+QM87ew5D5vpvwr+Lo1CyampqbB7g== + dependencies: + "@libp2p/crypto" "^3.0.4" + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-id" "^4.0.4" + "@libp2p/utils" "^5.2.0" + "@multiformats/multiaddr" "^12.1.10" protons-runtime "^5.0.0" uint8-varint "^2.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" - -"@libp2p/peer-store@^9.0.5": - version "9.0.5" - resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-9.0.5.tgz#1beeda7aac7c186e2663de1f65e0aa1df833595e" - integrity sha512-LUYN2i58F/eVvrFEYCIfArMNZaCGy2J2xSG9kd3/iHZqHAyLkuQHnYfHdoJLSUJFcS2pZsFo+c9atVvlOD7w5A== - dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@libp2p/peer-collections" "^4.0.4" - "@libp2p/peer-id" "^3.0.2" - "@libp2p/peer-id-factory" "^3.0.4" - "@libp2p/peer-record" "^6.0.5" - "@multiformats/multiaddr" "^12.1.5" + uint8arrays "^5.0.0" + +"@libp2p/peer-store@^10.0.5": + version "10.0.5" + resolved "https://registry.yarnpkg.com/@libp2p/peer-store/-/peer-store-10.0.5.tgz#b969d1707f5dcbf4d110e099270de285b075aa02" + integrity sha512-n+rwX8HNkyquOeL6vkcGJMesJsauKBuBIeMG+OnBY3mfFjaVjtGeHF2DQniS6AXHt2hktK9TlC2NEDRh6oGvRw== + dependencies: + "@libp2p/interface" "^1.1.1" + "@libp2p/peer-collections" "^5.1.3" + "@libp2p/peer-id" "^4.0.4" + "@libp2p/peer-record" "^7.0.4" + "@multiformats/multiaddr" "^12.1.10" interface-datastore "^8.2.0" it-all "^3.0.2" mortice "^3.0.1" - multiformats "^12.0.1" + multiformats "^13.0.0" protons-runtime "^5.0.0" uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" + uint8arrays "^5.0.0" -"@libp2p/prometheus-metrics@^2.0.7": - version "2.0.7" - resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-2.0.7.tgz#4d93bd3f4bb9221356cc16797d4ad1f2ba5a05b6" - integrity sha512-P2F8xRY3usuw0W39ZMsem9PXQ8UFn3pFbxTEhplN4OCfe9wpfT5UYBK212s8eIKcPhMSvQSx7er41ObqXJeIUg== +"@libp2p/prometheus-metrics@^3.0.10": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@libp2p/prometheus-metrics/-/prometheus-metrics-3.0.10.tgz#b95f4c6f20817fb157b803012034baccc588ddb5" + integrity sha512-ESOWM2uAM8X2fjb1nZF98LkYs/Nf2Ifxnfj3LVdSlaYbz44jDvCQ2ZW5vpGfooonVnU2Jkm5kvEeCWYt/9y8mQ== dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" + "@libp2p/interface" "^1.1.1" it-foreach "^2.0.3" it-stream-types "^2.0.1" - prom-client "^14.2.0" + prom-client "^15.0.0" + uint8arraylist "^2.4.3" -"@libp2p/pubsub@^8.0.0": - version "8.0.3" - resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-8.0.3.tgz#93c839c89b9f432fc4c18bcb9491c822688db21c" - integrity sha512-NIVM5MjN+Kx9jNoBzNPW44mhc3eedWpNc4IT1Nz2cxurA+QgzI01mz42SiN+GqapQmiZrVrWClnb0Knc4t7TtQ== - dependencies: - "@libp2p/crypto" "^2.0.2" - "@libp2p/interface" "^0.1.1" - "@libp2p/interface-internal" "^0.1.2" - "@libp2p/logger" "^3.0.1" - "@libp2p/peer-collections" "^4.0.2" - "@libp2p/peer-id" "^3.0.1" - abortable-iterator "^5.0.1" - it-length-prefixed "^9.0.1" +"@libp2p/pubsub@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@libp2p/pubsub/-/pubsub-9.0.0.tgz#e9d3869addd653868f87797849dbebfd23cd3a38" + integrity sha512-yvgKBNKtF09x4ahbxJrxj/OBTNvOoJibR28YaTlrlCIDU78wMMhIx89Ma14g2FAN1OsxagifyAgq188vGrsGfA== + dependencies: + "@libp2p/crypto" "^3.0.1" + "@libp2p/interface" "^1.0.1" + "@libp2p/interface-internal" "^1.0.1" + "@libp2p/peer-collections" "^5.0.0" + "@libp2p/peer-id" "^4.0.1" + "@libp2p/utils" "^5.0.2" + it-length-prefixed "^9.0.3" it-pipe "^3.0.1" - it-pushable "^3.2.0" - multiformats "^12.0.1" - p-queue "^7.3.4" + it-pushable "^3.2.1" + multiformats "^12.1.3" + p-queue "^7.4.1" uint8arraylist "^2.4.3" - uint8arrays "^4.0.4" + uint8arrays "^4.0.6" -"@libp2p/tcp@8.0.8": - version "8.0.8" - resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-8.0.8.tgz#e692bbd04f79c37b9a42bc7d51583226c61b1242" - integrity sha512-hIjAKWQOP4MCS2yUhWMdfweFK/ykDiaMZSrgIJJ+YEikxi0HihB5fRtk08oLvOew0B52GsGXQsfQg8I9sOncWg== - dependencies: - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@libp2p/utils" "^4.0.3" - "@multiformats/mafmt" "^12.1.2" - "@multiformats/multiaddr" "^12.1.5" - "@types/sinon" "^10.0.15" +"@libp2p/tcp@9.0.10": + version "9.0.10" + resolved "https://registry.yarnpkg.com/@libp2p/tcp/-/tcp-9.0.10.tgz#94ad87f728b857651608582393f33a8ca095c69d" + integrity sha512-ixwa2aDpCiS3ng/TjLB/7QIWChmlKEmH6L/vS089chJ7M5mYqRJdbLeo4zfod6lSmJab2mj8Q0sKzGeplAPE5Q== + dependencies: + "@libp2p/interface" "^1.1.1" + "@libp2p/utils" "^5.2.0" + "@multiformats/mafmt" "^12.1.6" + "@multiformats/multiaddr" "^12.1.10" + "@types/sinon" "^17.0.0" stream-to-it "^0.2.2" -"@libp2p/utils@^4.0.3": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-4.0.3.tgz#e27e46930fd0bf72fc9344127194dbff90c25d45" - integrity sha512-jusH8y4G9YluKRm63EPIiN9fNv0hVtfKY7O0nsLI14o0/W/WJhTsQWm+kPOfvoAgCIqAVrxefBqAmFGiiYPnvg== +"@libp2p/utils@^5.0.2", "@libp2p/utils@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@libp2p/utils/-/utils-5.2.0.tgz#896bcb9ceb5b90caea0b2a8a5bb353dc2116cc13" + integrity sha512-zAremC/0u7mhS32TS++WBlsjwmKKKonEB7dZMfTtKH0QfghII8vcBOgBCTEqhtm0AqwsT6vIlm6wAg9bbZKbQA== dependencies: "@chainsafe/is-ip" "^2.0.2" - "@libp2p/interface" "^0.1.2" - "@libp2p/logger" "^3.0.2" - "@multiformats/multiaddr" "^12.1.5" - "@multiformats/multiaddr-matcher" "^1.0.1" + "@libp2p/interface" "^1.1.1" + "@libp2p/logger" "^4.0.4" + "@multiformats/multiaddr" "^12.1.10" + "@multiformats/multiaddr-matcher" "^1.1.0" + get-iterator "^2.0.1" is-loopback-addr "^2.0.1" + it-pushable "^3.2.2" it-stream-types "^2.0.1" - private-ip "^3.0.0" + p-defer "^4.0.0" + private-ip "^3.0.1" + race-event "^1.1.0" + race-signal "^1.0.1" uint8arraylist "^2.4.3" "@lukeed/ms@^2.0.1": @@ -2004,34 +1955,34 @@ resolved "https://registry.yarnpkg.com/@lukeed/ms/-/ms-2.0.1.tgz#3c2bbc258affd9cc0e0cc7828477383c73afa6ee" integrity sha512-Xs/4RZltsAL7pkvaNStUQt7netTkyxrS0K+RILcVr3TRMS/ToOg4I6uNfhB9SlGsnWBym4U+EaXq0f0cEMNkHA== -"@multiformats/mafmt@^12.1.2": +"@multiformats/mafmt@^12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@multiformats/mafmt/-/mafmt-12.1.6.tgz#e7c1831c1e94c94932621826049afc89f3ad43b7" integrity sha512-tlJRfL21X+AKn9b5i5VnaTD6bNttpSpcqwKVmDmSHLwxoz97fAHaepqFOk/l1fIu94nImIXneNbhsJx/RQNIww== dependencies: "@multiformats/multiaddr" "^12.0.0" -"@multiformats/multiaddr-matcher@^1.0.0", "@multiformats/multiaddr-matcher@^1.0.1": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.0.2.tgz#014b8bf34106363b7c2635c01b5627d216fa192f" - integrity sha512-YzviFV31TsDbatWhEmkNnpWC82F/Wfc+alaOBT94Lk6KJeKKfzsaLhYPsjyhElXiUtCKvB3p5e4+WsE5ZYy1kg== +"@multiformats/multiaddr-matcher@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.1.0.tgz#27e14a549a00594c24d85897c4b0b7e83df3e59d" + integrity sha512-B/QbKpAxaHYVXFnbTdTgYqPDxmqoF2RYffwYoOv1MWfi2vBCZLdzmEKUBKv6fQr6s+LJFSHn2j2vczmwMFCQIA== dependencies: "@chainsafe/is-ip" "^2.0.1" "@multiformats/multiaddr" "^12.0.0" multiformats "^12.0.1" -"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.3", "@multiformats/multiaddr@^12.1.5": - version "12.1.7" - resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.1.7.tgz#eb71733be20dd9f0ac0ff4c3ffe4bae422726beb" - integrity sha512-MZRj+uUrtF2WqgByrsPolrdyPDSFstw7Fe0ewabWgWl27fcOmfDOSrEt2aUVkSzapXbyCG7JQh0QvimmTF4aMA== +"@multiformats/multiaddr@^12.0.0", "@multiformats/multiaddr@^12.1.10", "@multiformats/multiaddr@^12.1.3": + version "12.1.12" + resolved "https://registry.yarnpkg.com/@multiformats/multiaddr/-/multiaddr-12.1.12.tgz#d1609933dc5589d53f6b77fb88fe5e5ea787deae" + integrity sha512-hrY4uN/oeYhn410jBSpVXn37eenn4djKOj6Dh20Yh4xzGgqmS6u+/X08zQfHgWNjk7NJejPUcRfHEfs8e/MOcw== dependencies: "@chainsafe/is-ip" "^2.0.1" "@chainsafe/netmask" "^2.0.0" - "@libp2p/interface" "^0.1.1" - dns-over-http-resolver "^2.1.0" - multiformats "^12.0.1" + "@libp2p/interface" "^1.0.0" + dns-over-http-resolver "3.0.0" + multiformats "^13.0.0" uint8-varint "^2.0.1" - uint8arrays "^4.0.2" + uint8arrays "^5.0.0" "@napi-rs/snappy-android-arm-eabi@7.2.2": version "7.2.2" @@ -2098,10 +2049,10 @@ resolved "https://registry.yarnpkg.com/@napi-rs/snappy-win32-x64-msvc/-/snappy-win32-x64-msvc-7.2.2.tgz#4f598d3a5d50904d9f72433819f68b21eaec4f7d" integrity sha512-a43cyx1nK0daw6BZxVcvDEXxKMFLSBSDTAhsFD0VqSKcC7MGUBMaqyoWUcMiI7LBSz4bxUmxDWKfCYzpEmeb3w== -"@noble/ciphers@^0.3.0": - version "0.3.0" - resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.3.0.tgz#6ba3090afdc7a7051393486f6af210e62e0f04ec" - integrity sha512-ldbrnOjmNRwFdXcTM6uXDcxpMIFrbzAWNnpBPp4oTJTFF0XByGD6vf45WrehZGXRQTRVV+Zm8YP+EgEf+e4cWA== +"@noble/ciphers@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@noble/ciphers/-/ciphers-0.4.0.tgz#e3f69e3ce935683dd8dadb636652a5cb5cd5958c" + integrity sha512-xaUaUUDWbHIFSxaQ/pIe+33VG2mfJp6N/KxKLmZr5biWdNznCAmfu24QRhX10BbVAuqOahAoyp0S4M9md6GPDw== "@noble/curves@1.0.0", "@noble/curves@~1.0.0": version "1.0.0" @@ -3479,11 +3430,6 @@ resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz" integrity sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g== -"@types/retry@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" - integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== - "@types/semver@^7.5.0": version "7.5.2" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" @@ -3504,13 +3450,20 @@ dependencies: "@types/sinonjs__fake-timers" "*" -"@types/sinon@^10.0.15", "@types/sinon@^10.0.16": +"@types/sinon@^10.0.16": version "10.0.16" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.16.tgz#4bf10313bd9aa8eef1e50ec9f4decd3dd455b4d3" integrity sha512-j2Du5SYpXZjJVJtXBokASpPRj+e2z+VUhCPHmM6WMfe3dpHu6iVKJMU6AiBcMp/XTAYnEj6Wc1trJUWwZ0QaAQ== dependencies: "@types/sinonjs__fake-timers" "*" +"@types/sinon@^17.0.0": + version "17.0.2" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.2.tgz#9a769f67e62b45b7233f1fe01cb1f231d2393e1c" + integrity sha512-Zt6heIGsdqERkxctIpvN5Pv3edgBrhoeb3yHyxffd4InN0AX2SVNKSrhdDZKGQICVOxWP/q4DyhpfPNMSrpIiA== + dependencies: + "@types/sinonjs__fake-timers" "*" + "@types/sinonjs__fake-timers@*": version "6.0.2" resolved "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz" @@ -3758,6 +3711,15 @@ "@vitest/utils" "1.1.0" chai "^4.3.10" +"@vitest/expect@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.2.0.tgz#de93f5c32c2781c41415a8c3a6e48e1c023d6613" + integrity sha512-H+2bHzhyvgp32o7Pgj2h9RTHN0pgYaoi26Oo3mE+dCi1PAqV31kIIVfTbqMO3Bvshd5mIrJLc73EwSRrbol9Lw== + dependencies: + "@vitest/spy" "1.2.0" + "@vitest/utils" "1.2.0" + chai "^4.3.10" + "@vitest/runner@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.1.0.tgz#b3bf60f4a78f4324ca09811dd0f87b721a96b534" @@ -3767,6 +3729,15 @@ p-limit "^5.0.0" pathe "^1.1.1" +"@vitest/runner@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.2.0.tgz#84775f0f5c48620ff1943a45c19863355791c6d9" + integrity sha512-vaJkDoQaNUTroT70OhM0NPznP7H3WyRwt4LvGwCVYs/llLaqhoSLnlIhUClZpbF5RgAee29KRcNz0FEhYcgxqA== + dependencies: + "@vitest/utils" "1.2.0" + p-limit "^5.0.0" + pathe "^1.1.1" + "@vitest/snapshot@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.1.0.tgz#b9924e4303382b43bb2c31061b173e69a6fb3437" @@ -3776,6 +3747,15 @@ pathe "^1.1.1" pretty-format "^29.7.0" +"@vitest/snapshot@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.2.0.tgz#2fcddb5c6e8a9d2fc9f18ea2f8fd39b1b6e691b4" + integrity sha512-P33EE7TrVgB3HDLllrjK/GG6WSnmUtWohbwcQqmm7TAk9AVHpdgf7M3F3qRHKm6vhr7x3eGIln7VH052Smo6Kw== + dependencies: + magic-string "^0.30.5" + pathe "^1.1.1" + pretty-format "^29.7.0" + "@vitest/spy@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.1.0.tgz#7f40697e4fc217ac8c3cc89a865d1751b263f561" @@ -3783,6 +3763,13 @@ dependencies: tinyspy "^2.2.0" +"@vitest/spy@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.2.0.tgz#61104de4c19a3addefff021d884c9e20dc17ebcd" + integrity sha512-MNxSAfxUaCeowqyyGwC293yZgk7cECZU9wGb8N1pYQ0yOn/SIr8t0l9XnGRdQZvNV/ZHBYu6GO/W3tj5K3VN1Q== + dependencies: + tinyspy "^2.2.0" + "@vitest/utils@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.1.0.tgz#d177a5f41bdb484bbb43c8d73a77ca782df068b5" @@ -3792,6 +3779,16 @@ loupe "^2.3.7" pretty-format "^29.7.0" +"@vitest/utils@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.2.0.tgz#deb9bdc3d094bf47f93a592a6a0b3946aa575e7a" + integrity sha512-FyD5bpugsXlwVpTcGLDf3wSPYy8g541fQt14qtzo8mJ4LdEpDKZ9mQy2+qdJm2TZRpjY5JLXihXCgIxiRJgi5g== + dependencies: + diff-sequences "^29.6.3" + estree-walker "^3.0.3" + loupe "^2.3.7" + pretty-format "^29.7.0" + "@wdio/config@8.27.0": version "8.27.0" resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.27.0.tgz#c738d8108b5161cf3f80bb34d0e1f4d700b1a9ce" @@ -4100,6 +4097,11 @@ acorn-walk@^8.3.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== +acorn-walk@^8.3.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + acorn@^8.10.0, acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" @@ -4672,14 +4674,6 @@ before-after-hook@^2.2.0: resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== -benchmark@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/benchmark/-/benchmark-2.1.4.tgz#09f3de31c916425d498cc2ee565a0ebf3c2a5629" - integrity sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ== - dependencies: - lodash "^4.17.4" - platform "^1.3.3" - big-integer@^1.6.17: version "1.6.52" resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" @@ -6007,43 +6001,24 @@ data-urls@^5.0.0: whatwg-mimetype "^4.0.0" whatwg-url "^14.0.0" -datastore-core@^9.0.0, datastore-core@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-9.1.1.tgz#613db89a9bb2624943811dd39b831125319fab79" - integrity sha512-Way+QZdrlAjLOHm7hc3r5mEIfmdkZCtb/bAWv+Mhp9FGQKSyaf8yL5oOcmp3pv+WrqdFYB7qYx7xe/FX3+zcjw== - dependencies: - "@libp2p/logger" "^2.0.0" - err-code "^3.0.1" - interface-store "^5.0.0" - it-all "^3.0.1" - it-drain "^3.0.1" - it-filter "^3.0.0" - it-map "^3.0.1" - it-merge "^3.0.0" - it-pipe "^3.0.0" - it-pushable "^3.0.0" - it-sort "^3.0.1" - it-take "^3.0.1" - uint8arrays "^4.0.2" - -datastore-core@^9.0.1: - version "9.2.2" - resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-9.2.2.tgz#92b0efbc5a0b6362ecce3506ccc285b0691a834b" - integrity sha512-WFB1wVlD3Tr2yBZpJutPedBc18A4t0HvLOSksokYr/2nHBapplgnwkg2esI6xxctma+76FghhXx7G26khx2Uxg== +datastore-core@^9.0.0, datastore-core@^9.0.1, datastore-core@^9.1.1: + version "9.2.7" + resolved "https://registry.yarnpkg.com/datastore-core/-/datastore-core-9.2.7.tgz#25d0773a56f6c6d4e475d850c550a09672171242" + integrity sha512-S5ADNGRy1p6kHT6Khld+FThe1ITHuUiyYQ84VX2Kv8s6cXDiUuLlYPBIbZaWIgqR/JwxQCwa+5/08w6BZSIAow== dependencies: - "@libp2p/logger" "^3.0.0" + "@libp2p/logger" "^4.0.1" err-code "^3.0.1" interface-store "^5.0.0" it-all "^3.0.1" it-drain "^3.0.1" it-filter "^3.0.0" it-map "^3.0.1" - it-merge "^3.0.0" + it-merge "^3.0.1" it-pipe "^3.0.0" it-pushable "^3.0.0" it-sort "^3.0.1" it-take "^3.0.1" - uint8arrays "^4.0.2" + uint8arrays "^5.0.0" datastore-level@*, datastore-level@^10.1.1: version "10.1.1" @@ -6176,13 +6151,6 @@ default-browser@^4.0.0: execa "^7.1.1" titleize "^3.0.0" -default-gateway@^6.0.2: - version "6.0.3" - resolved "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== - dependencies: - execa "^5.0.0" - default-require-extensions@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz" @@ -6247,11 +6215,6 @@ degenerator@^5.0.0: escodegen "^2.1.0" esprima "^4.0.1" -delay@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-6.0.0.tgz#43749aefdf6cabd9e17b0d00bd3904525137e607" - integrity sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw== - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -6328,11 +6291,6 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" -dgram@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/dgram/-/dgram-1.0.1.tgz" - integrity sha1-N/OyAPgDOl/3WTAwicgc42G2UcM= - di@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" @@ -6345,12 +6303,12 @@ diff-sequences@^29.6.3: diff@5.0.0: version "5.0.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== diff@^4.0.1: version "4.0.2" - resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== diff@^5.1.0: @@ -6374,7 +6332,7 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -dns-over-http-resolver@^2.1.0, dns-over-http-resolver@^2.1.1: +dns-over-http-resolver@3.0.0, dns-over-http-resolver@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/dns-over-http-resolver/-/dns-over-http-resolver-2.1.3.tgz#bb7f2e10cc18d960339a6e30e21b8c1d99be7b38" integrity sha512-zjRYFhq+CsxPAouQWzOsxNMvEN+SHisjzhX8EMxd2Y0EG3thvn6wXQgMJLnTDImkhe4jhLbOQpXtL10nALBOSA== @@ -7253,11 +7211,6 @@ ethers@^6.7.0: tslib "2.4.0" ws "8.5.0" -event-iterator@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/event-iterator/-/event-iterator-2.0.0.tgz#10f06740cc1e9fd6bc575f334c2bc1ae9d2dbf62" - integrity sha512-KGft0ldl31BZVV//jj+IAIGCxkvvUkkON+ScH6zfoX+l+omX6001ggyRSpI0Io2Hlro0ThXotswCtfzS8UkIiQ== - event-target-shim@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz" @@ -7268,6 +7221,11 @@ eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + events@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -7788,11 +7746,6 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -freeport-promise@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/freeport-promise/-/freeport-promise-2.0.0.tgz#11e4f81e24d680b88a20c15b2103551f4b6663d8" - integrity sha512-dwWpT1DdQcwrhmRwnDnPM/ZFny+FtzU+k50qF2eid3KxaQDsMiBrwo1i0G3qSugkN5db6Cb0zgfc68QeTOpEFg== - fromentries@^1.2.0: version "1.3.2" resolved "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz" @@ -7874,6 +7827,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + function.prototype.name@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621" @@ -7985,15 +7943,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: has "^1.0.3" has-symbols "^1.0.3" -get-intrinsic@^1.1.0: - version "1.1.1" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - get-intrinsic@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" @@ -8013,6 +7962,16 @@ get-intrinsic@^1.2.1: has-proto "^1.0.1" has-symbols "^1.0.3" +get-intrinsic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" + integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== + dependencies: + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-iterator@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-iterator/-/get-iterator-1.0.2.tgz" @@ -8023,6 +7982,11 @@ get-iterator@^2.0.0: resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-2.0.0.tgz#c9ac9f8002e5d8d6b4dc9dae07c30945022a58c1" integrity sha512-BDJawD5PU2gZv6Vlp8O28H4GnZcsr3h9gZUvnAP5xXP3WOy/QAoOsyMepSkw21jur+4t5Vppde72ChjhTIzxzg== +get-iterator@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-2.0.1.tgz#a904829f61bace789e0d64bd1a504c511a015c3f" + integrity sha512-7HuY/hebu4gryTDT7O/XY/fvY9wRByEGdK6QOa4of8npTcv0+NS6frFKABcf6S9EBAsveTuKTsZQQBFMMNILIg== + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" @@ -8457,6 +8421,13 @@ hasha@^5.0.0: is-stream "^2.0.0" type-fest "^0.8.0" +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" @@ -8817,13 +8788,13 @@ inquirer@^9.1.5: through "^2.3.6" wrap-ansi "^8.1.0" -interface-datastore@^8.0.0, interface-datastore@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.0.tgz#70076985ac17dcdb35b33c2b0f957480ce6489e1" - integrity sha512-rDMAcpCGxWMubRk2YQuSEHl11bc0xcZeBZzfLvqhoZJdByUWeo7YDJUdgyRKgD6liGXVYirtDkFU9nyn9xl2hg== +interface-datastore@^8.0.0, interface-datastore@^8.2.0, interface-datastore@^8.2.7: + version "8.2.7" + resolved "https://registry.yarnpkg.com/interface-datastore/-/interface-datastore-8.2.7.tgz#6a1e168fd98a271a92b85223bae58fa30031fb9c" + integrity sha512-ot5B5+VogufRfjhedAXZHm5NuEKyYZkDyVpTjBYIrxYUpS5GIfF2soE/dsd/FiBVqubcxa4IEToMXL5ruMwhjw== dependencies: interface-store "^5.0.0" - nanoid "^4.0.0" + nanoid "^5.0.3" uint8arrays "^4.0.2" interface-store@^5.0.0: @@ -8832,12 +8803,12 @@ interface-store@^5.0.0: integrity sha512-mjUwX3XSoreoxCS3sXS3pSRsGnUjl9T06KBqt/T7AgE9Sgp4diH64ZyURJKnj2T5WmCvTbC0Dm+mwQV5hfLSBQ== internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + version "1.0.6" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" + integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" + get-intrinsic "^1.2.2" + hasown "^2.0.0" side-channel "^1.0.4" internal-slot@^1.0.5: @@ -8874,10 +8845,10 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== +ipaddr.js@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" + integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== is-arguments@^1.0.4: version "1.1.0" @@ -9091,11 +9062,6 @@ is-negative-zero@^2.0.1, is-negative-zero@^2.0.2: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== -is-network-error@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.0.0.tgz#757d7af42263f18f616626e63af12abb19002bbc" - integrity sha512-P3fxi10Aji2FZmHTrMPSNFbNC6nnp4U5juPAIjXPHkUNubi4+qK7vvdsaNpAUwXslhYm9oyjEYTxs1xd/+Ph0w== - is-number-object@^1.0.4: version "1.0.7" resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" @@ -9428,13 +9394,10 @@ it-all@^3.0.0, it-all@^3.0.1, it-all@^3.0.2: resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.2.tgz#620b82c702c9c6d1c4caddb6407dba4a4baa970b" integrity sha512-ujqWETXhsDbF6C+6X6fvRw5ohlowRoy/o/h9BC8D+R3JQ13oLQ153w9gSWkWupOY7omZFQbJiAL1aJo5Gwe2yw== -it-batched-bytes@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/it-batched-bytes/-/it-batched-bytes-2.0.3.tgz#b05cb114c5b3dfa5d6512a18225093d1a943b358" - integrity sha512-vUhr1K6NerlrSbSKpBGW9bDd3s64GPUQePWUzoUF0zkYw2ufFpCXEYCZAtJMP45n6BJNChWDYTYwxAZvQG0b0g== - dependencies: - p-defer "^4.0.0" - uint8arraylist "^2.4.1" +it-all@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/it-all/-/it-all-3.0.4.tgz#08f2e3eb3df04fa4525a343dcacfbdf91ffee162" + integrity sha512-UMiy0i9DqCHBdWvMbzdYvVGa5/w4t1cc4nchpbnjdLhklglv8mQeEYnii0gvKESJuL1zV32Cqdb33R6/GPfxpQ== it-byte-stream@^1.0.0: version "1.0.0" @@ -9445,7 +9408,7 @@ it-byte-stream@^1.0.0: it-stream-types "^2.0.1" uint8arraylist "^2.4.1" -it-drain@^3.0.1, it-drain@^3.0.2: +it-drain@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-3.0.2.tgz#4fb2ab30119072268c68a895fa5b9f2037942c44" integrity sha512-0hJvS/4Ktt9wT/bktmovjjMAY8r6FCsXqpL3zjqBBNwoL21VgQfguEnwbLSGuCip9Zq1vfU43cbHkmaRZdBfOg== @@ -9455,18 +9418,13 @@ it-drain@^3.0.3: resolved "https://registry.yarnpkg.com/it-drain/-/it-drain-3.0.3.tgz#f80719d3d0d7e7d02dc298d86ca9d0e7f7bd666b" integrity sha512-l4s+izxUpFAR2axprpFiCaq0EtxK1QMd0LWbEtau5b+OegiZ5xdRtz35iJyh6KZY9QtuwEiQxydiOfYJc7stoA== -it-filter@^3.0.0, it-filter@^3.0.1: +it-filter@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/it-filter/-/it-filter-3.0.2.tgz#19ddf6185ea21d417e6075d5796c799fa2633b69" integrity sha512-Hhzp5anX7tmKOBqTPasBYTPlq7l4Xk4lMBfLB5GfKZnL9WCc6pr8M9Waud4nHh3s9neb4xwDWk7KQsEapgWyJw== dependencies: it-peekable "^3.0.0" -it-first@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/it-first/-/it-first-3.0.2.tgz#6186a40ca52c6212815177346a784c1db1034cbb" - integrity sha512-QPLAM2BOkait/o6W25HvP0XTEv+Os3Ce4wET//ADNaPv+WYAHWfQwJuMu5FB8X066hA1F7LEMnULvTpE7/4yQw== - it-foreach@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/it-foreach/-/it-foreach-2.0.3.tgz#40c96680d9875805203f61fdd1064b7190a17e5a" @@ -9474,17 +9432,6 @@ it-foreach@^2.0.3: dependencies: it-peekable "^3.0.0" -it-handshake@^4.1.3: - version "4.1.3" - resolved "https://registry.yarnpkg.com/it-handshake/-/it-handshake-4.1.3.tgz#4e6650f8eff5cb3686c6861958645289fb3dc32a" - integrity sha512-V6Lt9A9usox9iduOX+edU1Vo94E6v9Lt9dOvg3ubFaw1qf5NCxXLi93Ao4fyCHWDYd8Y+DUhadwNtWVyn7qqLg== - dependencies: - it-pushable "^3.1.0" - it-reader "^6.0.1" - it-stream-types "^2.0.1" - p-defer "^4.0.0" - uint8arraylist "^2.0.0" - it-length-prefixed-stream@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.0.2.tgz#dbcb291118fc9cf031c89ab4be3f99cdb452f548" @@ -9496,7 +9443,18 @@ it-length-prefixed-stream@^1.0.0: uint8-varint "^2.0.1" uint8arraylist "^2.4.1" -it-length-prefixed@^9.0.1: +it-length-prefixed-stream@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/it-length-prefixed-stream/-/it-length-prefixed-stream-1.1.4.tgz#5e5a73685e820366d9a9dd944decef55b46f09ef" + integrity sha512-6YcQ5jsaYnuXBqF+oSGjSdSY9jF7HWl7yh+dxYytXxbE2GcdiOpn6pLM7m6AlIID9MCzQqMY5nOzaiatQ8A3/A== + dependencies: + it-byte-stream "^1.0.0" + it-length-prefixed "^9.0.1" + it-stream-types "^2.0.1" + uint8-varint "^2.0.1" + uint8arraylist "^2.4.1" + +it-length-prefixed@^9.0.1, it-length-prefixed@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/it-length-prefixed/-/it-length-prefixed-9.0.3.tgz#73af16f786cab60a0a9bfc2997e88eb26d3a72ca" integrity sha512-YAu424ceYpXctxtjcLOqn7vJq082CaoP8J646ZusYISfQc3bpzQErgTUqMFj81V262KG2W9/YMBHsy6A/4yvmg== @@ -9508,7 +9466,7 @@ it-length-prefixed@^9.0.1: uint8arraylist "^2.0.0" uint8arrays "^4.0.2" -it-map@^3.0.1, it-map@^3.0.3: +it-map@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/it-map/-/it-map-3.0.3.tgz#42be39fc68dc9b0d70cfd8ac4b8311d4b5cd7f22" integrity sha512-Yf89GJYeYUZb2NZzWkvFHm3IBXlxro74i2vGRmpf8BYau3BhlaS37ieDenJEdYzkTGJhL/EbM1jPPw/KGVVVIw== @@ -9522,6 +9480,13 @@ it-merge@^3.0.0: dependencies: it-pushable "^3.1.0" +it-merge@^3.0.1: + version "3.0.3" + resolved "https://registry.yarnpkg.com/it-merge/-/it-merge-3.0.3.tgz#c7d407c8e0473accf7f9958ce2e0f60276002e84" + integrity sha512-FYVU15KC5pb/GQX1Ims+lee8d4pdqGVCpWr0lkNj8o4xuNo7jY71k6GuEiWdP+T7W1bJqewSxX5yoTy5yZpRVA== + dependencies: + it-pushable "^3.2.0" + it-pair@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/it-pair/-/it-pair-2.0.6.tgz#072defa6b96f611af34e0b0c84573107ddb9f28f" @@ -9530,10 +9495,10 @@ it-pair@^2.0.6: it-stream-types "^2.0.1" p-defer "^4.0.0" -it-parallel@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.3.tgz#b02f1d6459418c7253ecf13e367111560a616491" - integrity sha512-Q5KmdvERHCOLDcgKqrzQ+yiMCdG6H9h7ZL3Zjx/Tx9xhZy8txSKoy+EiCgWZFs0rfYvxJhk6UkOpKLzJ1zM9ZA== +it-parallel@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/it-parallel/-/it-parallel-3.0.6.tgz#d8f9efa56dac5f960545b3a148d2ca171694d228" + integrity sha512-i7UM7I9LTkDJw3YIqXHFAPZX6CWYzGc+X3irdNrVExI4vPazrJdI7t5OqrSVN8CONXLAunCiqaSV/zZRbQR56A== dependencies: p-defer "^4.0.0" @@ -9551,10 +9516,10 @@ it-pipe@^3.0.0, it-pipe@^3.0.1: it-pushable "^3.1.2" it-stream-types "^2.0.1" -it-protobuf-stream@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.0.2.tgz#e8bdcc1f67b43f11090cc81f5a4931474fc37f87" - integrity sha512-2lESJIeZS2ZlYJc/1SKs6LL4Y83rCCvZv750xV1e4uuP9114yNkw2MhIGCtSReg+qNWCvzGqOwjQbKV0LFE6wQ== +it-protobuf-stream@^1.0.2: + version "1.1.1" + resolved "https://registry.yarnpkg.com/it-protobuf-stream/-/it-protobuf-stream-1.1.1.tgz#cc303ac31b9de768d24288b0898c18ebd7624868" + integrity sha512-H7fiC+m85AAz84I8SQOKHKZTDREFrsYfKxEhWTlhAdySoUyiC72Xe2ocqBFy3zUWCGYq6rCTMGnCbTKntSlcog== dependencies: it-length-prefixed-stream "^1.0.0" it-stream-types "^2.0.1" @@ -9573,6 +9538,13 @@ it-pushable@^3.2.0: dependencies: p-defer "^4.0.0" +it-pushable@^3.2.1, it-pushable@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/it-pushable/-/it-pushable-3.2.3.tgz#e2b80aed90cfbcd54b620c0a0785e546d4e5f334" + integrity sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg== + dependencies: + p-defer "^4.0.0" + it-reader@^6.0.1: version "6.0.4" resolved "https://registry.yarnpkg.com/it-reader/-/it-reader-6.0.4.tgz#439cb88225dcd15116be0ffde9e846a928c3871a" @@ -10102,56 +10074,32 @@ libnpmpublish@7.3.0: sigstore "^1.4.0" ssri "^10.0.1" -libp2p@0.46.12: - version "0.46.12" - resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-0.46.12.tgz#de913134c7f5d98e59bfe0356b0067e881985a76" - integrity sha512-LPEfSVW/tsFNaUplNo/QqDsg9C7wed+lBGPUUhUsRcnPnKQTqZnKBpA9pSv2+A0ST9B++uiyCOk+JK7nIlpjeA== - dependencies: - "@achingbrain/nat-port-mapper" "^1.0.9" - "@libp2p/crypto" "^2.0.4" - "@libp2p/interface" "^0.1.2" - "@libp2p/interface-internal" "^0.1.5" - "@libp2p/keychain" "^3.0.4" - "@libp2p/logger" "^3.0.2" - "@libp2p/multistream-select" "^4.0.2" - "@libp2p/peer-collections" "^4.0.4" - "@libp2p/peer-id" "^3.0.2" - "@libp2p/peer-id-factory" "^3.0.4" - "@libp2p/peer-record" "^6.0.5" - "@libp2p/peer-store" "^9.0.5" - "@libp2p/utils" "^4.0.3" - "@multiformats/mafmt" "^12.1.2" - "@multiformats/multiaddr" "^12.1.5" - "@multiformats/multiaddr-matcher" "^1.0.0" +libp2p@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/libp2p/-/libp2p-1.1.1.tgz#a57f4793ee87a0eba67a3f039724c79ad1b24224" + integrity sha512-577X5MPRH5vhJzWPLNbXg5EdWNuTzZG90HHTaCFGdrzYLyrGcQWb4RK4Ji3dZALYmx6NmuwTkZv5oojnu2ayng== + dependencies: + "@libp2p/crypto" "^3.0.4" + "@libp2p/interface" "^1.1.1" + "@libp2p/interface-internal" "^1.0.5" + "@libp2p/logger" "^4.0.4" + "@libp2p/multistream-select" "^5.1.1" + "@libp2p/peer-collections" "^5.1.3" + "@libp2p/peer-id" "^4.0.4" + "@libp2p/peer-id-factory" "^4.0.3" + "@libp2p/peer-store" "^10.0.5" + "@libp2p/utils" "^5.2.0" + "@multiformats/multiaddr" "^12.1.10" any-signal "^4.1.1" datastore-core "^9.0.1" - delay "^6.0.0" interface-datastore "^8.2.0" - it-all "^3.0.2" - it-drain "^3.0.2" - it-filter "^3.0.1" - it-first "^3.0.1" - it-handshake "^4.1.3" - it-length-prefixed "^9.0.1" - it-map "^3.0.3" it-merge "^3.0.0" - it-pair "^2.0.6" - it-parallel "^3.0.0" - it-pipe "^3.0.1" - it-protobuf-stream "^1.0.0" - it-stream-types "^2.0.1" + it-parallel "^3.0.6" merge-options "^3.0.4" - multiformats "^12.0.1" - p-defer "^4.0.0" - p-queue "^7.3.4" - p-retry "^6.0.0" - private-ip "^3.0.0" - protons-runtime "^5.0.0" - rate-limiter-flexible "^3.0.0" - uint8arraylist "^2.4.3" - uint8arrays "^4.0.6" - wherearewe "^2.0.1" - xsalsa20 "^1.1.0" + multiformats "^13.0.0" + private-ip "^3.0.1" + rate-limiter-flexible "^4.0.0" + uint8arrays "^5.0.0" light-my-request@^5.9.1: version "5.10.0" @@ -10345,7 +10293,7 @@ lodash.zip@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" integrity sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4: +lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10421,6 +10369,11 @@ lowercase-keys@^3.0.0: resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== +lru-cache@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.1.0.tgz#2098d41c2dc56500e6c88584aa656c84de7d0484" + integrity sha512-/1clY/ui8CzjKFyjdvwPWJUYKiFVXG2I2cY0ssG7h4+hwk+XOIX7ZSG9Q7TW8TW3Kp3BUSqgFWBLgL4PJ+Blag== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -10888,24 +10841,17 @@ minipass-sized@^1.0.3: dependencies: minipass "^3.0.0" -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: - version "3.3.4" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.4.tgz#ca99f95dd77c43c7a76bf51e6d200025eee0ffae" - integrity sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw== - dependencies: - yallist "^4.0.0" - -minipass@^3.1.6: - version "3.3.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.3.tgz#fd1f0e6c06449c10dadda72618b59c00f3d6378d" - integrity sha512-N0BOsdFAlNRfmwMhjAsLVWOk7Ljmeb39iqFlsV1At+jqRhSUP9yeof8FyJu4imaJiSUp8vQebWD/guZwGQC8iA== +minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3, minipass@^3.1.6: + version "3.3.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" minipass@^4.0.0, minipass@^4.2.4: - version "4.2.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.5.tgz#9e0e5256f1e3513f8c34691dd68549e85b2c8ceb" - integrity sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q== + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== minipass@^5.0.0: version "5.0.0" @@ -10913,9 +10859,9 @@ minipass@^5.0.0: integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": - version "7.0.2" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.2.tgz#58a82b7d81c7010da5bd4b2c0c85ac4b4ec5131e" - integrity sha512-eL79dXrE1q9dBbDCLg7xfn/vl7MS4F1gvJAgjJrQli/jbQWdUttuVawphqpffoIYfRdq78LHx6GP4bU/EQ2ATA== + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" @@ -11035,8 +10981,8 @@ mrmime@^1.0.0: ms@2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== ms@2.1.2: version "2.1.2" @@ -11056,17 +11002,7 @@ multicast-dns@^7.2.5: dns-packet "^5.2.2" thunky "^1.0.2" -multiformats@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-10.0.2.tgz#e549ae833dac77edb534bece4adf1d1a214879f0" - integrity sha512-nJEHLFOYhO4L+aNApHhCnWqa31FyqAHv9Q77AhmwU3KsM2f1j7tuJpCk5ByZ33smzycNCpSG5klNIejIyfFx2A== - -multiformats@^11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-11.0.1.tgz#ba58c3f69f032ab67dab4b48cc70f01ac2ca07fe" - integrity sha512-atWruyH34YiknSdL5yeIir00EDlJRpHzELYQxG7Iy29eCyL+VrZHpPrX5yqlik3jnuqpLpRKVZ0SGVb9UzKaSA== - -multiformats@^11.0.1, multiformats@^11.0.2: +multiformats@^11.0.1: version "11.0.2" resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-11.0.2.tgz#b14735efc42cd8581e73895e66bebb9752151b60" integrity sha512-b5mYMkOkARIuVZCpvijFj9a6m5wMVLC7cf/jIPd5D/ARDOfLC5+IFkbgDXQgcU2goIsTD/O9NY4DI/Mt4OGvlg== @@ -11076,6 +11012,16 @@ multiformats@^12.0.1: resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-12.0.1.tgz#dd3e19dd44114c2672e4795a36888d263be30131" integrity sha512-s01wijBJoDUqESWSzePY0lvTw7J3PVO9x2Cc6ASI5AMZM2Gnhh7BC17+nlFhHKU7dDzaCaRfb+NiqNzOsgPUoQ== +multiformats@^12.1.3: + version "12.1.3" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-12.1.3.tgz#cbf7a9861e11e74f8228b21376088cb43ba8754e" + integrity sha512-eajQ/ZH7qXZQR2AgtfpmSMizQzmyYVmCql7pdhldPuYQi4atACekbJaQplk6dWyIi10jCaFnd6pqvcEFXjbaJw== + +multiformats@^13.0.0: + version "13.0.1" + resolved "https://registry.yarnpkg.com/multiformats/-/multiformats-13.0.1.tgz#c0622affa5171189eacd57c06f977195ca7acb08" + integrity sha512-bt3R5iXe2O8xpp3wkmQhC73b/lC4S2ihU8Dndwcsysqbydqb8N+bpP116qMcClZ17g58iSIwtXUTcg2zT4sniA== + multimatch@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" @@ -11122,6 +11068,11 @@ nanoid@^4.0.0: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-4.0.2.tgz#140b3c5003959adbebf521c170f282c5e7f9fb9e" integrity sha512-7ZtY5KTCNheRGfEFxnedV5zFiORN1+Y1N6zvPTnHQd8ENUvfaDBeuJDZb2bN/oXwXxu3qkTXDzy57W5vAmDTBw== +nanoid@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-5.0.3.tgz#6c97f53d793a7a1de6a38ebb46f50f95bf9793c7" + integrity sha512-I7X2b22cxA4LIHXPSqbBCEQSL+1wv8TuoefejsX4HFWyC6jc5JG7CEaxOltiKjc1M+YCS2YkrZZcj4+dytw9GA== + napi-macros@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz" @@ -11981,12 +11932,12 @@ p-queue@^7.2.0: eventemitter3 "^4.0.7" p-timeout "^5.0.2" -p-queue@^7.3.4: - version "7.3.4" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.3.4.tgz#7ef7d89b6c1a0563596d98adbc9dc404e9ed4a84" - integrity sha512-esox8CWt0j9EZECFvkFl2WNPat8LN4t7WWeXq73D9ha0V96qPRufApZi4ZhPwXAln1uVVal429HVVKPa2X0yQg== +p-queue@^7.4.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-7.4.1.tgz#7f86f853048beca8272abdbb7cec1ed2afc0f265" + integrity sha512-vRpMXmIkYF2/1hLBKisKeVYJZ8S2tZ0zEAmIJgdVKP2nq0nh4qCdf8bgw+ZgKrkh71AOCaqzwbJJk1WtdcF3VA== dependencies: - eventemitter3 "^4.0.7" + eventemitter3 "^5.0.1" p-timeout "^5.0.2" p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: @@ -11994,15 +11945,6 @@ p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== -p-retry@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.1.0.tgz#ea5c188f9f818a5bfa89a27bdf043c74fa9be472" - integrity sha512-fJLEQ2KqYBJRuaA/8cKMnqhulqNM+bpcjYtXNex2t3mOXKRYPitAJt9NacSf8XAFzcYahSAbKpobiWDSqHSh2g== - dependencies: - "@types/retry" "0.12.2" - is-network-error "^1.0.0" - retry "^0.13.1" - p-timeout@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -12020,11 +11962,6 @@ p-timeout@^6.0.0: resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-6.1.1.tgz#bcee5e37d730f5474d973b6ff226751a1a5e6ff1" integrity sha512-yqz2Wi4fiFRpMmK0L2pGAU49naSUaP23fFIQL2Y6YT+qDGPoFwpvgQM/wzc6F8JoenUkIlAFa4Ql7NguXBxI7w== -p-timeout@^6.1.1: - version "6.1.2" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-6.1.2.tgz#22b8d8a78abf5e103030211c5fc6dee1166a6aa5" - integrity sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ== - p-try@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" @@ -12367,11 +12304,6 @@ pkg-types@^1.0.3: mlly "^1.2.0" pathe "^1.1.0" -platform@^1.3.3: - version "1.3.6" - resolved "https://registry.yarnpkg.com/platform/-/platform-1.3.6.tgz#48b4ce983164b209c2d45a107adb31f473a6e7a7" - integrity sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg== - postcss@^8.4.32: version "8.4.32" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9" @@ -12407,14 +12339,14 @@ pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" -private-ip@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/private-ip/-/private-ip-3.0.0.tgz#a65d10e2db06f6bb2f97f716f1a8976a3460a4a6" - integrity sha512-HkMBs4nMtrP+cvcw0bDi2BAZIGgiKI4Zq8Oc+dMqNBpHS8iGL4+WO/pRtc8Bwnv9rjnV0QwMDwEBymFtqv7Kww== +private-ip@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/private-ip/-/private-ip-3.0.1.tgz#1fa8108f53512c6b82f79d4d2ac665140dee5da5" + integrity sha512-Ezc16ANuhSHmWAE6lbXUKburNzGpR0J5X0Zh5Um/PZ/s57Fp+HYqYe6BYPH2QbqKr/5WebfzJQ1jq6Kj5dbRmA== dependencies: "@chainsafe/is-ip" "^2.0.1" ip-regex "^5.0.0" - ipaddr.js "^2.0.1" + ipaddr.js "^2.1.0" netmask "^2.0.2" proc-log@^3.0.0: @@ -12444,16 +12376,22 @@ process@^0.11.10: resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== +progress-events@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/progress-events/-/progress-events-1.0.0.tgz#34f5e8fdb5dae3561837b22672d1e02277bb2109" + integrity sha512-zIB6QDrSbPfRg+33FZalluFIowkbV5Xh1xSuetjG+rlC5he6u2dc6VQJ0TbMdlN3R1RHdpOqxEFMKTnQ+itUwA== + progress@2.0.3, progress@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -prom-client@^14.2.0: - version "14.2.0" - resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-14.2.0.tgz#ca94504e64156f6506574c25fb1c34df7812cf11" - integrity sha512-sF308EhTenb/pDRPakm+WgiN+VdM/T1RaHj1x+MvAuT8UiQP8JmOEbxVqtkbfR4LrvOg5n7ic01kRBDGXjYikA== +prom-client@^15.0.0: + version "15.0.0" + resolved "https://registry.yarnpkg.com/prom-client/-/prom-client-15.0.0.tgz#067da874a2aa5d2e21bd5cdba9f24a8178bdab6a" + integrity sha512-UocpgIrKyA2TKLVZDSfm8rGkL13C19YrQBAiG3xo3aDFWcHedxRxI3z+cIcucoxpSO0h5lff5iv/SXoxyeopeA== dependencies: + "@opentelemetry/api" "^1.4.0" tdigest "^0.1.1" prom-client@^15.1.0: @@ -12717,7 +12655,12 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -race-signal@^1.0.0: +race-event@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/race-event/-/race-event-1.1.0.tgz#69c2d855653acf11d8b23ea8f6fa50e1180a088b" + integrity sha512-8BTiN6IAbov8mqkVEc3LiYbtUzanLfzFhwPF7kZV74ztYeQXdFPIgMCd/sy8xie6ZMtf2JPeMBedx78/RRNO3g== + +race-signal@^1.0.1, race-signal@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/race-signal/-/race-signal-1.0.2.tgz#e42379fba0cec4ee8dab7c9bbbd4aa6e0d14c25f" integrity sha512-o3xNv0iTcIDQCXFlF6fPAMEBRjFxssgGoRqLbg06m+AdzEXXLUmoNOoUHTVz2NoBI8hHwKFKoC6IqyNtWr2bww== @@ -12747,10 +12690,10 @@ range-parser@^1.2.1: resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== -rate-limiter-flexible@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-3.0.0.tgz#1dba6de44d4d5a5e6494774c2ff7657e82856673" - integrity sha512-janAJkWxWxmLka0hV+XvCTo0M8keeSeOuz8ZL33cTXrkS4ek9mQ2VJm9ri7fm03oTVth19Sfqb1ijCmo7K/vAg== +rate-limiter-flexible@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-4.0.0.tgz#4754706216f0b442e7527b1367e42b7682145010" + integrity sha512-SkA18LEPqJJKHixi6E7tzBKTXbj9gu5wPyfTykPVRZR5JGSw0dMCjtZsjlfuabVY940pu28Wu87NZN4FhztnyQ== raw-body@2.5.1: version "2.5.1" @@ -13080,7 +13023,7 @@ ret@~0.2.0: resolved "https://registry.npmjs.org/ret/-/ret-0.2.2.tgz" integrity sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ== -retry@0.13.1, retry@^0.13.1: +retry@0.13.1: version "0.13.1" resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== @@ -13294,13 +13237,6 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-filename@^1.6.3: - version "1.6.3" - resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz" - integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== - dependencies: - truncate-utf8-bytes "^1.0.0" - sax@1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" @@ -14503,13 +14439,6 @@ triple-beam@^1.2.0, triple-beam@^1.3.0: resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== -truncate-utf8-bytes@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz" - integrity sha1-QFkjkJWS1W94pYGENLC3hInKXys= - dependencies: - utf8-byte-length "^1.0.1" - ts-api-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" @@ -14796,41 +14725,34 @@ uglify-js@^3.1.4: resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.17.2.tgz#f55f668b9a64b213977ae688703b6bbb7ca861c6" integrity sha512-bbxglRjsGQMchfvXZNusUcYgiB9Hx2K4AHYXQy2DITZ9Rd+JzhX7+hoocE5Winr7z2oHvPsekkBwXtigvxevXg== -uint8-varint@^2.0.0, uint8-varint@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/uint8-varint/-/uint8-varint-2.0.1.tgz#e8f73c24974b384f6f0e1cd73c884c5a19e32f53" - integrity sha512-euvmpuulJstK5+xNuI4S1KfnxJnbI5QP52RXIR3GZ3/ZMkOsEK2AgCtFpNvEQLXMxMx2o0qcyevK1fJwOZJagQ== +uint8-varint@^2.0.0, uint8-varint@^2.0.1, uint8-varint@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/uint8-varint/-/uint8-varint-2.0.3.tgz#049fceb3e870757dec26b29633770900f3132233" + integrity sha512-seXTM8ba4uuAMDgi3UHXPdDxCBKjWWZigW+F+1ESPhOZv9ekT1qmbdzYHLSNA+u+wHj10P55dQ41y2Qh7NOqiA== dependencies: uint8arraylist "^2.0.0" - uint8arrays "^4.0.2" - -uint8arraylist@^2.0.0, uint8arraylist@^2.4.1, uint8arraylist@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/uint8arraylist/-/uint8arraylist-2.4.3.tgz#1148aa979b407d382e4eb8d9c8f2b4bf3f5910d5" - integrity sha512-oEVZr4/GrH87K0kjNce6z8pSCzLEPqHNLNR5sj8cJOySrTP8Vb/pMIbZKLJGhQKxm1TiZ31atNrpn820Pyqpow== - dependencies: - uint8arrays "^4.0.2" + uint8arrays "^5.0.0" -uint8arrays@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.2.tgz#163bdbcf3f7403b0781754e0436c268548b237c2" - integrity sha512-8CWXXZdOvVrIL4SeY/Gnp+idxxiGK4XFkP4FY26Sx/fpTz/b6vv4BVWELMDzQweSyyhdcuAcU14H6izzB6k1Cw== +uint8arraylist@^2.0.0, uint8arraylist@^2.4.1, uint8arraylist@^2.4.3, uint8arraylist@^2.4.7: + version "2.4.8" + resolved "https://registry.yarnpkg.com/uint8arraylist/-/uint8arraylist-2.4.8.tgz#5a4d17f4defd77799cb38e93fd5db0f0dceddc12" + integrity sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ== dependencies: - multiformats "^10.0.0" + uint8arrays "^5.0.1" -uint8arrays@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.3.tgz#43109c03c4c10d312e7f2e9f4d53e5cd2398c7fd" - integrity sha512-b+aKlI2oTnxnfeSQWV1sMacqSNxqhtXySaH6bflvONGxF8V/fT3ZlYH7z2qgGfydsvpVo4JUgM/Ylyfl2YouCg== +uint8arrays@^4.0.2, uint8arrays@^4.0.4, uint8arrays@^4.0.6, uint8arrays@^4.0.9: + version "4.0.10" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.10.tgz#3ec5cde3348903c140e87532fc53f46b8f2e921f" + integrity sha512-AnJNUGGDJAgFw/eWu/Xb9zrVKEGlwJJCaeInlf3BkecE/zcTobk5YXYIPNQJO1q5Hh1QZrQQHf0JvcHqz2hqoA== dependencies: - multiformats "^11.0.0" + multiformats "^12.0.1" -uint8arrays@^4.0.4, uint8arrays@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-4.0.6.tgz#bae68b536c2e87147045b95d73d29e503e45ecab" - integrity sha512-4ZesjQhqOU2Ip6GPReIwN60wRxIupavL8T0Iy36BBHr2qyMrNxsPJvr7vpS4eFt8F8kSguWUPad6ZM9izs/vyw== +uint8arrays@^5.0.0, uint8arrays@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/uint8arrays/-/uint8arrays-5.0.1.tgz#6016ef944379eabb6de605934ead4d7a698c9f07" + integrity sha512-ND5RpJAnPgHmZT7hWD/2T4BwRp04j8NLKvMKC/7bhiEwEjUMkQ4kvBKiH6hOqbljd6qJ2xS8reL3vl1e33grOQ== dependencies: - multiformats "^12.0.1" + multiformats "^13.0.0" unbox-primitive@^1.0.0, unbox-primitive@^1.0.2: version "1.0.2" @@ -14992,11 +14914,6 @@ userhome@1.0.0: resolved "https://registry.yarnpkg.com/userhome/-/userhome-1.0.0.tgz#b6491ff12d21a5e72671df9ccc8717e1c6688c0b" integrity sha512-ayFKY3H+Pwfy4W98yPdtH1VqH4psDeyW8lYYFzfecR9d6hqLpqhecktvYR3SEEXt7vG0S1JEpciI3g94pMErig== -utf8-byte-length@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz" - integrity sha1-9F8VDExm7uloGGUFq5P8u4rWv2E= - util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -15046,7 +14963,7 @@ utils-merge@1.0.1: uuid@3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== uuid@8.3.2, uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: @@ -15138,6 +15055,17 @@ vite-node@1.1.0: picocolors "^1.0.0" vite "^5.0.0" +vite-node@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.0.tgz#9a359804469203a54ac49daad3065f2fd0bfb9c3" + integrity sha512-ETnQTHeAbbOxl7/pyBck9oAPZZZo+kYnFt1uQDD+hPReOc+wCjXw4r4jHriBRuVDB5isHmPXxrfc1yJnfBERqg== + dependencies: + cac "^6.7.14" + debug "^4.3.4" + pathe "^1.1.1" + picocolors "^1.0.0" + vite "^5.0.0" + vite-plugin-node-polyfills@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.18.0.tgz#2ad147960f7a35dbbb1c9f9c1ae928bd0f438c1e" @@ -15171,6 +15099,33 @@ vitest-when@^0.3.0: resolved "https://registry.yarnpkg.com/vitest-when/-/vitest-when-0.3.0.tgz#663d4274f1e7302bd24ec00dda8269d20b2eff04" integrity sha512-wYfmzd+GkvdNNhbeb/40PnKpetUP5I7qxvdbu1OAXRXaLrnLfSrJTa/dMIbqqrc8SA0vhonpw5p0RHDXwhDM1Q== +vitest@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.2.0.tgz#2ddff4a32ed992339655f243525c0e187b5af6d9" + integrity sha512-Ixs5m7BjqvLHXcibkzKRQUvD/XLw0E3rvqaCMlrm/0LMsA0309ZqYvTlPzkhh81VlEyVZXFlwWnkhb6/UMtcaQ== + dependencies: + "@vitest/expect" "1.2.0" + "@vitest/runner" "1.2.0" + "@vitest/snapshot" "1.2.0" + "@vitest/spy" "1.2.0" + "@vitest/utils" "1.2.0" + acorn-walk "^8.3.1" + cac "^6.7.14" + chai "^4.3.10" + debug "^4.3.4" + execa "^8.0.1" + local-pkg "^0.5.0" + magic-string "^0.30.5" + pathe "^1.1.1" + picocolors "^1.0.0" + std-env "^3.5.0" + strip-literal "^1.3.0" + tinybench "^2.5.1" + tinypool "^0.8.1" + vite "^5.0.0" + vite-node "1.2.0" + why-is-node-running "^2.2.2" + vitest@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.1.0.tgz#47ba67c564aa137b53b0197d2a992908e7f5b04d" @@ -15868,7 +15823,7 @@ xml2js@0.4.19: sax ">=0.6.0" xmlbuilder "~9.0.1" -xml2js@^0.4.19, xml2js@^0.4.23: +xml2js@^0.4.19: version "0.4.23" resolved "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -15876,14 +15831,6 @@ xml2js@^0.4.19, xml2js@^0.4.23: sax ">=0.6.0" xmlbuilder "~11.0.0" -xml2js@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.0.tgz#07afc447a97d2bd6507a1f76eeadddb09f7a8282" - integrity sha512-eLTh0kA8uHceqesPqSE+VvO1CDDJWMwlQfB6LuN6T8w6MaDJ8Txm8P7s5cHD0miF0V+GGTZrDQfxPZQVsur33w== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz" @@ -15899,11 +15846,6 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xsalsa20@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/xsalsa20/-/xsalsa20-1.1.0.tgz" - integrity sha512-zd3ytX2cm+tcSndRU+krm0eL4TMMpZE7evs5hLRAoOy6gviqLfe3qOlkjF3i5SeAkQUCeJk0lJZrEU56kHRfWw== - xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" From d7ca290d173dfa82b2977f3e94df6e5e8d12ef3e Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Tue, 16 Jan 2024 18:54:37 +0100 Subject: [PATCH 40/70] feat: allow to skip gossip validation (#6308) * Allow to skip gossip validation * Add code comment --- packages/api/src/beacon/routes/beacon/block.ts | 8 ++++++++ packages/beacon-node/src/api/impl/beacon/blocks/index.ts | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index b56006fe4191..95a32097028d 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -39,6 +39,14 @@ export type BlockHeaderResponse = { }; export enum BroadcastValidation { + /* + NOTE: The value `none` is not part of the spec. + + In case a node is configured only with the unknownBlockSync, it needs to know the unknown parent blocks on the network + to initiate the syncing process. Such cases can be covered only if we publish blocks and make sure no gossip validation + is performed on those. But this behavior is not the default. + */ + none = "none", gossip = "gossip", consensus = "consensus", consensusAndEquivocation = "consensus_and_equivocation", diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts index 89565426426e..f2e29f00fe57 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -149,6 +149,11 @@ export function getBeaconBlockApi({ break; } + case routes.beacon.BroadcastValidation.none: { + chain.logger.debug("Skipping broadcast validation", valLogMeta); + break; + } + default: { // error or log warning we do not support this validation const message = `Broadcast validation of ${broadcastValidation} type not implemented yet`; From 912ec0931c137f7df4086d4b9331f8839e8b3199 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Wed, 17 Jan 2024 19:48:57 +0100 Subject: [PATCH 41/70] test: stabilize sim tests (#6312) * Fix sim test genesis delay * Update the defaults for the all sim tests * Increase the limit for slotImportTolerance for unknown block sync * Update the additional slots for TTD * Adjust the ttd time * Adjust the ttd * Adjust the ttd * Update the ttd calculation * Add timestamp to report * Update the slot to check the merge transition * Update ttd calculations * Increase the genesis delay * Update the shangai ttd calculation * Increase the slot tolerance * Disable broadcast validation for unknown block tests * Fix lint errors --- .github/workflows/test-sim.yml | 7 ++ packages/cli/test/scripts/e2e_test_env.ts | 26 ++----- .../cli/test/sim/backup_eth_provider.test.ts | 41 ++--------- packages/cli/test/sim/deneb.test.ts | 38 +++------- packages/cli/test/sim/endpoints.test.ts | 33 +++------ packages/cli/test/sim/mixed_client.test.ts | 36 ++------- packages/cli/test/sim/multi_fork.test.ts | 61 ++++++---------- .../utils/simulation/SimulationEnvironment.ts | 45 ++---------- .../test/utils/simulation/TableReporter.ts | 5 ++ .../utils/simulation/beacon_clients/index.ts | 4 +- .../simulation/execution_clients/index.ts | 3 +- .../cli/test/utils/simulation/interfaces.ts | 6 +- .../cli/test/utils/simulation/utils/index.ts | 73 ++++++++++++++++--- 13 files changed, 154 insertions(+), 224 deletions(-) diff --git a/.github/workflows/test-sim.yml b/.github/workflows/test-sim.yml index a6e2581fdee6..65260fc38937 100644 --- a/.github/workflows/test-sim.yml +++ b/.github/workflows/test-sim.yml @@ -16,6 +16,11 @@ on: description: Runtime DEBUG value required: false default: "" + genesisDelaySlots: + description: 'Number of slots delay before genesis' + required: true + type: number + default: 40 env: GETH_DOCKER_IMAGE: ethereum/client-go:v1.11.6 @@ -56,6 +61,8 @@ jobs: - name: Sim tests multifork run: DEBUG='${{github.event.inputs.debug}}' yarn test:sim:multifork working-directory: packages/cli + env: + GENESIS_DELAY_SLOTS: ${{github.event.inputs.genesisDelaySlots}} - name: Sim tests endpoints run: yarn test:sim:endpoints diff --git a/packages/cli/test/scripts/e2e_test_env.ts b/packages/cli/test/scripts/e2e_test_env.ts index ef0f8851403f..b35b3524d8cf 100644 --- a/packages/cli/test/scripts/e2e_test_env.ts +++ b/packages/cli/test/scripts/e2e_test_env.ts @@ -2,37 +2,25 @@ import path from "node:path"; import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; -import {getEstimatedTTD, logFilesDir} from "../utils/simulation/utils/index.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; import {connectAllNodes} from "../utils/simulation/utils/network.js"; -const secondsPerSlot = 4; -const cliqueSealingPeriod = 5; -const genesisDelaySeconds = 30 * secondsPerSlot; const altairForkEpoch = 1; const bellatrixForkEpoch = 2; const capellaForkEpoch = 3; -// Make sure bellatrix started before TTD reach -const additionalSlotsForTTD = 2; -const ttd = getEstimatedTTD({ - genesisDelaySeconds, - bellatrixForkEpoch, - secondsPerSlot, - cliqueSealingPeriod, - additionalSlots: additionalSlotsForTTD, +const {forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + CAPELLA_FORK_EPOCH: capellaForkEpoch, + runTillEpoch: Infinity, }); const env = await SimulationEnvironment.initWithDefaults( { id: "e2e-test-env", logsDir: path.join(logFilesDir, "e2e-test-env"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - CAPELLA_FORK_EPOCH: capellaForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - TERMINAL_TOTAL_DIFFICULTY: ttd, - }, + forkConfig, }, [ {id: "node-1", beacon: BeaconClient.Lodestar, execution: ExecutionClient.Geth, keysCount: 32, mining: true}, diff --git a/packages/cli/test/sim/backup_eth_provider.test.ts b/packages/cli/test/sim/backup_eth_provider.test.ts index a9f4fa00f1a4..40ad7d4661de 100644 --- a/packages/cli/test/sim/backup_eth_provider.test.ts +++ b/packages/cli/test/sim/backup_eth_provider.test.ts @@ -1,53 +1,28 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {activePreset} from "@lodestar/params"; +import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js"; import {AssertionMatch, BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; -import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; -import { - getEstimatedTimeInSecForRun, - getEstimatedTTD, - logFilesDir, - replaceIpFromUrl, -} from "../utils/simulation/utils/index.js"; +import {defineSimTestConfig, logFilesDir, replaceIpFromUrl} from "../utils/simulation/utils/index.js"; import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; -const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; -// Make sure bellatrix started before TTD reach -const additionalSlotsForTTD = activePreset.SLOTS_PER_EPOCH - 2; const runTillEpoch = 6; const syncWaitEpoch = 2; -const runTimeoutMs = - getEstimatedTimeInSecForRun({ - genesisDelaySeconds, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - runTill: runTillEpoch + syncWaitEpoch, - // After adding Nethermind its took longer to complete - graceExtraTimeFraction: 0.3, - }) * 1000; - -const ttd = getEstimatedTTD({ - genesisDelaySeconds, - bellatrixForkEpoch: bellatrixForkEpoch, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - cliqueSealingPeriod: CLIQUE_SEALING_PERIOD, - additionalSlots: additionalSlotsForTTD, +const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + runTillEpoch: runTillEpoch + syncWaitEpoch, }); const env = await SimulationEnvironment.initWithDefaults( { id: "backup-eth-provider", logsDir: path.join(logFilesDir, "backup-eth-provider"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - TERMINAL_TOTAL_DIFFICULTY: ttd, - }, + forkConfig, }, [{id: "node-1", beacon: BeaconClient.Lodestar, execution: ExecutionClient.Geth, keysCount: 32, mining: true}] ); @@ -88,7 +63,7 @@ const node3 = await env.createNodePair({ env.nodes.push(node2); env.nodes.push(node3); -await env.start({runTimeoutMs}); +await env.start({runTimeoutMs: estimatedTimeoutMs}); await connectAllNodes(env.nodes); await waitForSlot(env.clock.getLastSlotOfEpoch(1), env.nodes, {silent: true, env}); diff --git a/packages/cli/test/sim/deneb.test.ts b/packages/cli/test/sim/deneb.test.ts index 04def4004902..5ed84d3d2792 100644 --- a/packages/cli/test/sim/deneb.test.ts +++ b/packages/cli/test/sim/deneb.test.ts @@ -1,50 +1,30 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; +import {ApiError} from "@lodestar/api"; import {activePreset} from "@lodestar/params"; import {toHex, toHexString} from "@lodestar/utils"; -import {ApiError} from "@lodestar/api"; +import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js"; import {AssertionMatch, BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; -import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; -import {getEstimatedTimeInSecForRun, getEstimatedTTD, logFilesDir} from "../utils/simulation/utils/index.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; import {connectAllNodes, connectNewNode, waitForNodeSync, waitForSlot} from "../utils/simulation/utils/network.js"; -const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; -// Make sure bellatrix started before TTD reach -const additionalSlotsForTTD = activePreset.SLOTS_PER_EPOCH - 2; const runTillEpoch = 6; const syncWaitEpoch = 2; -const runTimeoutMs = - getEstimatedTimeInSecForRun({ - genesisDelaySeconds, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - runTill: runTillEpoch + syncWaitEpoch, - // After adding Nethermind its took longer to complete - graceExtraTimeFraction: 0.3, - }) * 1000; - -const ttd = getEstimatedTTD({ - genesisDelaySeconds, - bellatrixForkEpoch: bellatrixForkEpoch, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - cliqueSealingPeriod: CLIQUE_SEALING_PERIOD, - additionalSlots: additionalSlotsForTTD, +const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + runTillEpoch: runTillEpoch + syncWaitEpoch, }); const env = await SimulationEnvironment.initWithDefaults( { id: "multi-fork", logsDir: path.join(logFilesDir, "multi-fork"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - TERMINAL_TOTAL_DIFFICULTY: ttd, - }, + forkConfig, }, [ {id: "node-1", beacon: BeaconClient.Lodestar, execution: ExecutionClient.Mock, keysCount: 32}, @@ -59,7 +39,7 @@ env.tracker.register({ }, }); -await env.start({runTimeoutMs}); +await env.start({runTimeoutMs: estimatedTimeoutMs}); await connectAllNodes(env.nodes); // The `TTD` will be reach around `start of bellatrixForkEpoch + additionalSlotsForMerge` slot diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 89d5428057f2..536e7ea24aa3 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -1,37 +1,28 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; -import {expect} from "chai"; import {toHexString} from "@chainsafe/ssz"; -import {routes} from "@lodestar/api"; -import {ApiError} from "@lodestar/api"; -import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; +import {expect} from "chai"; +import {ApiError, routes} from "@lodestar/api"; import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; -import {getEstimatedTimeInSecForRun, logFilesDir} from "../utils/simulation/utils/index.js"; +import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; import {waitForSlot} from "../utils/simulation/utils/network.js"; -import {SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js"; -const genesisDelaySeconds = 10 * SIM_TESTS_SECONDS_PER_SLOT; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; const validatorCount = 2; -const runTimeoutMs = - getEstimatedTimeInSecForRun({ - genesisDelaySeconds, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - runTill: 2, - // After adding Nethermind its took longer to complete - graceExtraTimeFraction: 0.1, - }) * 1000; + +const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + runTillEpoch: 2, +}); const env = await SimulationEnvironment.initWithDefaults( { id: "beacon-endpoints", logsDir: path.join(logFilesDir, "beacon-endpoints"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - }, + forkConfig, }, [ { @@ -43,7 +34,7 @@ const env = await SimulationEnvironment.initWithDefaults( }, ] ); -await env.start({runTimeoutMs}); +await env.start({runTimeoutMs: estimatedTimeoutMs}); const node = env.nodes[0].beacon; await waitForSlot(2, env.nodes, {env, silent: true}); diff --git a/packages/cli/test/sim/mixed_client.test.ts b/packages/cli/test/sim/mixed_client.test.ts index 35588f8d7c6f..ad2095f8c378 100644 --- a/packages/cli/test/sim/mixed_client.test.ts +++ b/packages/cli/test/sim/mixed_client.test.ts @@ -2,48 +2,28 @@ import path from "node:path"; import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; -import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js"; import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js"; -import {getEstimatedTTD, getEstimatedTimeInSecForRun, logFilesDir} from "../utils/simulation/utils/index.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; import {connectAllNodes, waitForSlot} from "../utils/simulation/utils/network.js"; -const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; const capellaForkEpoch = 6; -// Make sure bellatrix started before TTD reach -const additionalSlotsForTTD = 2; const runTillEpoch = 8; const syncWaitEpoch = 2; -const runTimeoutMs = - getEstimatedTimeInSecForRun({ - genesisDelaySeconds, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - runTill: runTillEpoch + syncWaitEpoch, - // After adding Nethermind its took longer to complete - graceExtraTimeFraction: 0.3, - }) * 1000; - -const ttd = getEstimatedTTD({ - genesisDelaySeconds, - bellatrixForkEpoch, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - cliqueSealingPeriod: CLIQUE_SEALING_PERIOD, - additionalSlots: additionalSlotsForTTD, +const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + CAPELLA_FORK_EPOCH: capellaForkEpoch, + runTillEpoch: runTillEpoch + syncWaitEpoch, }); const env = await SimulationEnvironment.initWithDefaults( { id: "mixed-clients", logsDir: path.join(logFilesDir, "mixed-clients"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - CAPELLA_FORK_EPOCH: capellaForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - TERMINAL_TOTAL_DIFFICULTY: ttd, - }, + forkConfig, }, [ { @@ -86,7 +66,7 @@ env.tracker.register({ }, }); -await env.start({runTimeoutMs}); +await env.start({runTimeoutMs: estimatedTimeoutMs}); await connectAllNodes(env.nodes); await waitForSlot(env.clock.getLastSlotOfEpoch(capellaForkEpoch + 1), env.nodes, {env, silent: true}); diff --git a/packages/cli/test/sim/multi_fork.test.ts b/packages/cli/test/sim/multi_fork.test.ts index 734ae5c5a380..24f42498c638 100644 --- a/packages/cli/test/sim/multi_fork.test.ts +++ b/packages/cli/test/sim/multi_fork.test.ts @@ -1,12 +1,10 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; import {sleep, toHex, toHexString} from "@lodestar/utils"; -import {ApiError} from "@lodestar/api"; -import {SLOTS_PER_EPOCH} from "@lodestar/params"; -import {CLIQUE_SEALING_PERIOD, SIM_TESTS_SECONDS_PER_SLOT} from "../utils/simulation/constants.js"; +import {ApiError, routes} from "@lodestar/api"; import {AssertionMatch, BeaconClient, ExecutionClient, ValidatorClient} from "../utils/simulation/interfaces.js"; import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; -import {getEstimatedTimeInSecForRun, getEstimatedTTD, logFilesDir} from "../utils/simulation/utils/index.js"; +import {defineSimTestConfig, logFilesDir} from "../utils/simulation/utils/index.js"; import { connectAllNodes, connectNewNode, @@ -18,43 +16,24 @@ import {nodeAssertion} from "../utils/simulation/assertions/nodeAssertion.js"; import {mergeAssertion} from "../utils/simulation/assertions/mergeAssertion.js"; import {createForkAssertion} from "../utils/simulation/assertions/forkAssertion.js"; -const genesisDelaySeconds = 20 * SIM_TESTS_SECONDS_PER_SLOT; const altairForkEpoch = 2; const bellatrixForkEpoch = 4; const capellaForkEpoch = 6; -// Make sure bellatrix started before TTD reach -const additionalSlotsForTTD = 2; const runTillEpoch = 8; const syncWaitEpoch = 2; -const runTimeoutMs = - getEstimatedTimeInSecForRun({ - genesisDelaySeconds, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - runTill: runTillEpoch + syncWaitEpoch, - // After adding Nethermind its took longer to complete - graceExtraTimeFraction: 0.3, - }) * 1000; - -const ttd = getEstimatedTTD({ - genesisDelaySeconds, - bellatrixForkEpoch, - secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, - cliqueSealingPeriod: CLIQUE_SEALING_PERIOD, - additionalSlots: additionalSlotsForTTD, +const {estimatedTimeoutMs, forkConfig} = defineSimTestConfig({ + ALTAIR_FORK_EPOCH: altairForkEpoch, + BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, + CAPELLA_FORK_EPOCH: capellaForkEpoch, + runTillEpoch: runTillEpoch + syncWaitEpoch, }); const env = await SimulationEnvironment.initWithDefaults( { id: "multi-fork", logsDir: path.join(logFilesDir, "multi-fork"), - chainConfig: { - ALTAIR_FORK_EPOCH: altairForkEpoch, - BELLATRIX_FORK_EPOCH: bellatrixForkEpoch, - CAPELLA_FORK_EPOCH: capellaForkEpoch, - GENESIS_DELAY: genesisDelaySeconds, - TERMINAL_TOTAL_DIFFICULTY: ttd, - }, + forkConfig, }, [ // put 1 lodestar node on produceBlockV3, and 2nd on produceBlindedBlock and 3rd on produceBlockV2 @@ -144,13 +123,13 @@ env.tracker.register({ ...mergeAssertion, match: ({slot}) => { // Check at the end of bellatrix fork, merge should happen by then - return slot === env.clock.getLastSlotOfEpoch(bellatrixForkEpoch) - 1 + return slot === env.clock.getLastSlotOfEpoch(bellatrixForkEpoch) ? AssertionMatch.Assert | AssertionMatch.Remove : AssertionMatch.None; }, }); -await env.start({runTimeoutMs}); +await env.start({runTimeoutMs: estimatedTimeoutMs}); await connectAllNodes(env.nodes); let lastForkEpoch = 0; @@ -228,12 +207,14 @@ const unknownBlockSync = await env.createNodePair({ clientOptions: { "network.allowPublishToZeroPeers": true, "sync.disableRangeSync": true, - // unknownBlockSync node start when other nodes are multiple epoch ahead and - // unknown block sync can work only if the gap is maximum `slotImportTolerance * 2` - // default value for slotImportTolerance is one epoch, so if gap is more than 2 epoch - // unknown block sync will not work. So why we have to increase it for tests. - // Adding SLOTS_PER_EPOCH will cover the case if the node starts on the last slot of epoch - "sync.slotImportTolerance": headForUnknownBlockSync.response.data.message.slot / 2 + SLOTS_PER_EPOCH, + /* + Initiation of the 'unknownBlockSync' node occurs when other nodes are several epochs ahead. + The effectiveness of the 'unknown block sync' is contingent on the gap being at most 'slotImportTolerance * 2'. + The default 'slotImportTolerance' value is one epoch; thus, if the gap exceeds 2 epochs, + the 'unknown block sync' won't function properly. Moreover, the 'unknownBlockSync' requires some startup time, + contributing to the overall gap. For stability in our CI, we've opted to set a higher limit on this constraint. + */ + "sync.slotImportTolerance": headForUnknownBlockSync.response.data.message.slot, }, }, }, @@ -248,7 +229,11 @@ await connectNewNode(unknownBlockSync, env.nodes); await sleep(5000); try { - ApiError.assert(await unknownBlockSync.beacon.api.beacon.publishBlockV2(headForUnknownBlockSync.response.data)); + ApiError.assert( + await unknownBlockSync.beacon.api.beacon.publishBlockV2(headForUnknownBlockSync.response.data, { + broadcastValidation: routes.beacon.BroadcastValidation.none, + }) + ); env.tracker.record({ message: "Publishing unknown block should fail", diff --git a/packages/cli/test/utils/simulation/SimulationEnvironment.ts b/packages/cli/test/utils/simulation/SimulationEnvironment.ts index 245f64c0139d..5baec1b79048 100644 --- a/packages/cli/test/utils/simulation/SimulationEnvironment.ts +++ b/packages/cli/test/utils/simulation/SimulationEnvironment.ts @@ -6,7 +6,7 @@ import path from "node:path"; import tmp from "tmp"; import {fromHexString} from "@chainsafe/ssz"; import {nodeUtils} from "@lodestar/beacon-node"; -import {ChainForkConfig, createChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig} from "@lodestar/config"; import {activePreset} from "@lodestar/params"; import {BeaconStateAllForks, interopSecretKey} from "@lodestar/state-transition"; import {EpochClock, MS_IN_SEC} from "./EpochClock.js"; @@ -14,13 +14,7 @@ import {ExternalSignerServer} from "./ExternalSignerServer.js"; import {SimulationTracker} from "./SimulationTracker.js"; import {createBeaconNode} from "./beacon_clients/index.js"; import {createValidatorNode, getValidatorForBeaconNode} from "./validator_clients/index.js"; -import { - CLIQUE_SEALING_PERIOD, - MOCK_ETH1_GENESIS_HASH, - SIM_ENV_CHAIN_ID, - SIM_ENV_NETWORK_ID, - SIM_TESTS_SECONDS_PER_SLOT, -} from "./constants.js"; +import {MOCK_ETH1_GENESIS_HASH} from "./constants.js"; import {createExecutionNode} from "./execution_clients/index.js"; import { BeaconClient, @@ -35,7 +29,7 @@ import { GeneratorOptions, } from "./interfaces.js"; import {Runner} from "./runner/index.js"; -import {getEstimatedTTD, registerProcessHandler, replaceIpFromUrl} from "./utils/index.js"; +import {registerProcessHandler, replaceIpFromUrl} from "./utils/index.js"; import {getNodePaths} from "./utils/paths.js"; interface StartOpts { @@ -64,7 +58,7 @@ export class SimulationEnvironment { this.options = options; this.clock = new EpochClock({ - genesisTime: this.options.elGenesisTime + this.forkConfig.GENESIS_DELAY, + genesisTime: this.options.genesisTime + this.forkConfig.GENESIS_DELAY, secondsPerSlot: this.forkConfig.SECONDS_PER_SLOT, slotsPerEpoch: activePreset.SLOTS_PER_EPOCH, signal: this.options.controller.signal, @@ -82,36 +76,13 @@ export class SimulationEnvironment { } static async initWithDefaults( - {chainConfig, logsDir, id}: SimulationInitOptions, + {forkConfig, logsDir, id}: SimulationInitOptions, clients: NodePairDefinition[] ): Promise { - const secondsPerSlot = chainConfig.SECONDS_PER_SLOT ?? SIM_TESTS_SECONDS_PER_SLOT; - const genesisTime = Math.floor(Date.now() / 1000); - const ttd = - chainConfig.TERMINAL_TOTAL_DIFFICULTY ?? - getEstimatedTTD({ - genesisDelaySeconds: chainConfig.GENESIS_DELAY, - bellatrixForkEpoch: chainConfig.BELLATRIX_FORK_EPOCH, - secondsPerSlot: secondsPerSlot, - cliqueSealingPeriod: CLIQUE_SEALING_PERIOD, - // Make sure bellatrix started before TTD reach, so we wait for few more slots to be sure - additionalSlots: activePreset.SLOTS_PER_EPOCH - 2, - }); - - const forkConfig = createChainForkConfig({ - ...chainConfig, - SECONDS_PER_SLOT: secondsPerSlot, - TERMINAL_TOTAL_DIFFICULTY: ttd, - DEPOSIT_CHAIN_ID: SIM_ENV_CHAIN_ID, - DEPOSIT_NETWORK_ID: SIM_ENV_NETWORK_ID, - SECONDS_PER_ETH1_BLOCK: CLIQUE_SEALING_PERIOD, - ETH1_FOLLOW_DISTANCE: 1, - }); - const env = new SimulationEnvironment(forkConfig, { logsDir, id, - elGenesisTime: genesisTime, + genesisTime: Math.floor(Date.now() / 1000), controller: new AbortController(), rootDir: path.join(tmp.dirSync({unsafeCleanup: true, tmpdir: "/tmp", template: "sim-XXXXXX"}).name, id), }); @@ -246,7 +217,7 @@ export class SimulationEnvironment { forkConfig: this.forkConfig, runner: this.runner, address: "0.0.0.0", - genesisTime: this.options.elGenesisTime, + genesisTime: this.options.genesisTime + this.forkConfig.GENESIS_DELAY, }; // Execution Node @@ -327,7 +298,7 @@ export class SimulationEnvironment { } const genesisState = nodeUtils.initDevState(this.forkConfig, this.keysCount, { - genesisTime: this.options.elGenesisTime + this.forkConfig.GENESIS_DELAY, + genesisTime: this.options.genesisTime + this.forkConfig.GENESIS_DELAY, eth1BlockHash: fromHexString(eth1Genesis.hash), }).state; diff --git a/packages/cli/test/utils/simulation/TableReporter.ts b/packages/cli/test/utils/simulation/TableReporter.ts index fd9ec6daabdc..1101c926269c 100644 --- a/packages/cli/test/utils/simulation/TableReporter.ts +++ b/packages/cli/test/utils/simulation/TableReporter.ts @@ -11,6 +11,7 @@ export class TableReporter extends SimulationReporter private lastPrintedSlot = -1; private table = new TableRenderer({ + time: 14, fork: 10, eph: 5, slot: 4, @@ -106,7 +107,11 @@ export class TableReporter extends SimulationReporter heads.length === nodes.length && heads.every((head) => head0 && !isNullish(head0.blockRoot) && head?.blockRoot === head0.blockRoot); + const date = new Date(); + const currentTime = `${date.getUTCHours()}:${date.getUTCMinutes()}:${date.getUTCSeconds()}.${date.getUTCMilliseconds()}`; + this.table.addRow({ + time: currentTime, fork: forkName, eph: epochStr, slot: head0 ? head0.slot : "---", diff --git a/packages/cli/test/utils/simulation/beacon_clients/index.ts b/packages/cli/test/utils/simulation/beacon_clients/index.ts index 606fc97bc46b..094ca1e9c580 100644 --- a/packages/cli/test/utils/simulation/beacon_clients/index.ts +++ b/packages/cli/test/utils/simulation/beacon_clients/index.ts @@ -16,13 +16,13 @@ export async function createBeaconNode( genesisState?: BeaconStateAllForks; } ): Promise { - const {runner, forkConfig: config, genesisState} = options; + const {runner, genesisState} = options; const clId = `${options.id}-${client}`; const opts: BeaconGeneratorOptions = { ...options, id: clId, - genesisTime: options.genesisTime + config.GENESIS_DELAY, + genesisTime: options.genesisTime, engineMock: options.engineMock ?? false, clientOptions: options.clientOptions ?? {}, address: "127.0.0.1", diff --git a/packages/cli/test/utils/simulation/execution_clients/index.ts b/packages/cli/test/utils/simulation/execution_clients/index.ts index 62e35284677b..b0d4086e663d 100644 --- a/packages/cli/test/utils/simulation/execution_clients/index.ts +++ b/packages/cli/test/utils/simulation/execution_clients/index.ts @@ -29,9 +29,8 @@ export async function createExecutionNode( shanghaiTime: options.shanghaiTime ?? getEstimatedShanghaiTime({ - genesisDelaySeconds: forkConfig.GENESIS_DELAY, capellaForkEpoch: forkConfig.CAPELLA_FORK_EPOCH, - eth1GenesisTime: options.genesisTime, + genesisTime: options.genesisTime, secondsPerSlot: forkConfig.SECONDS_PER_SLOT, additionalSlots: 0, }), diff --git a/packages/cli/test/utils/simulation/interfaces.ts b/packages/cli/test/utils/simulation/interfaces.ts index d87ca35f4a78..41339b58a1e0 100644 --- a/packages/cli/test/utils/simulation/interfaces.ts +++ b/packages/cli/test/utils/simulation/interfaces.ts @@ -3,7 +3,7 @@ import {ChildProcess} from "node:child_process"; import type {SecretKey} from "@chainsafe/bls/types"; import {Api} from "@lodestar/api"; import {Api as KeyManagerApi} from "@lodestar/api/keymanager"; -import {ChainConfig, ChainForkConfig} from "@lodestar/config"; +import {ChainForkConfig} from "@lodestar/config"; import {ForkName} from "@lodestar/params"; import {Slot, allForks, Epoch} from "@lodestar/types"; import {BeaconArgs} from "../../../src/cmds/beacon/options.js"; @@ -17,7 +17,7 @@ export type NodeId = string; export type SimulationInitOptions = { id: string; logsDir: string; - chainConfig: AtLeast; + forkConfig: ChainForkConfig; }; export type SimulationOptions = { @@ -25,7 +25,7 @@ export type SimulationOptions = { logsDir: string; rootDir: string; controller: AbortController; - elGenesisTime: number; + genesisTime: number; }; export enum BeaconClient { diff --git a/packages/cli/test/utils/simulation/utils/index.ts b/packages/cli/test/utils/simulation/utils/index.ts index 8f2a32c5b115..dfa66bed6580 100644 --- a/packages/cli/test/utils/simulation/utils/index.ts +++ b/packages/cli/test/utils/simulation/utils/index.ts @@ -1,7 +1,14 @@ /* eslint-disable no-console */ import {activePreset} from "@lodestar/params"; import {Epoch} from "@lodestar/types"; -import {ETH_TTD_INCREMENT} from "../constants.js"; +import {ChainConfig, ChainForkConfig, createChainForkConfig} from "@lodestar/config"; +import { + CLIQUE_SEALING_PERIOD, + ETH_TTD_INCREMENT, + SIM_ENV_CHAIN_ID, + SIM_ENV_NETWORK_ID, + SIM_TESTS_SECONDS_PER_SLOT, +} from "../constants.js"; import {SimulationEnvironment} from "../SimulationEnvironment.js"; export const logFilesDir = "test-logs"; @@ -10,6 +17,55 @@ export const avg = (arr: number[]): number => { return arr.length === 0 ? 0 : arr.reduce((p, c) => p + c, 0) / arr.length; }; +export function defineSimTestConfig( + opts: Partial & { + cliqueSealingPeriod?: number; + additionalSlotsForTTD?: number; + runTillEpoch: number; + } +): { + estimatedTimeoutMs: number; + forkConfig: ChainForkConfig; +} { + const genesisDelaySeconds = + (process.env.GENESIS_DELAY_SLOTS ? parseInt(process.env.GENESIS_DELAY_SLOTS) : 40) * SIM_TESTS_SECONDS_PER_SLOT; + + const estimatedTimeoutMs = + getEstimatedTimeInSecForRun({ + genesisDelaySeconds, + secondsPerSlot: SIM_TESTS_SECONDS_PER_SLOT, + runTill: opts.runTillEpoch, + // After adding Nethermind its took longer to complete + graceExtraTimeFraction: 0.3, + }) * 1000; + + const ttd = getEstimatedTTD({ + bellatrixForkEpoch: opts.BELLATRIX_FORK_EPOCH ?? Infinity, + secondsPerSlot: opts.SECONDS_PER_SLOT ?? SIM_TESTS_SECONDS_PER_SLOT, + cliqueSealingPeriod: opts.cliqueSealingPeriod ?? CLIQUE_SEALING_PERIOD, + // To make sure bellatrix already started + additionalSlots: opts.additionalSlotsForTTD ?? 2, + }); + + /* eslint-disable @typescript-eslint/naming-convention */ + const forkConfig = createChainForkConfig({ + ...opts, + GENESIS_DELAY: genesisDelaySeconds, + SECONDS_PER_SLOT: opts.SECONDS_PER_SLOT ?? SIM_TESTS_SECONDS_PER_SLOT, + TERMINAL_TOTAL_DIFFICULTY: ttd, + DEPOSIT_CHAIN_ID: SIM_ENV_CHAIN_ID, + DEPOSIT_NETWORK_ID: SIM_ENV_NETWORK_ID, + SECONDS_PER_ETH1_BLOCK: opts.cliqueSealingPeriod ?? CLIQUE_SEALING_PERIOD, + ETH1_FOLLOW_DISTANCE: 1, + }); + /* eslint-enable @typescript-eslint/naming-convention */ + + return { + estimatedTimeoutMs, + forkConfig, + }; +} + export const getEstimatedTimeInSecForRun = ({ genesisDelaySeconds, runTill, @@ -27,43 +83,36 @@ export const getEstimatedTimeInSecForRun = ({ }; export const getEstimatedTTD = ({ - genesisDelaySeconds, cliqueSealingPeriod, secondsPerSlot, additionalSlots, bellatrixForkEpoch, }: { - genesisDelaySeconds: number; cliqueSealingPeriod: number; additionalSlots: number; secondsPerSlot: number; bellatrixForkEpoch: number; }): bigint => { - // Need to investigate why TTD always remain 1 epoch ahead, for now just subtract 1 epoch const secondsTillBellatrix = - genesisDelaySeconds + - (bellatrixForkEpoch - 1) * activePreset.SLOTS_PER_EPOCH * secondsPerSlot + - additionalSlots * secondsPerSlot; + bellatrixForkEpoch * activePreset.SLOTS_PER_EPOCH * secondsPerSlot + additionalSlots * secondsPerSlot; return BigInt(Math.ceil(secondsTillBellatrix / cliqueSealingPeriod) * ETH_TTD_INCREMENT); }; export const getEstimatedShanghaiTime = ({ - genesisDelaySeconds, - eth1GenesisTime, + genesisTime, secondsPerSlot, capellaForkEpoch, additionalSlots, }: { - genesisDelaySeconds: number; - eth1GenesisTime: number; + genesisTime: number; secondsPerSlot: number; capellaForkEpoch: number; additionalSlots: number; }): number => { const secondsTillCapella = capellaForkEpoch * activePreset.SLOTS_PER_EPOCH * secondsPerSlot; - return eth1GenesisTime + genesisDelaySeconds + secondsTillCapella + additionalSlots * secondsPerSlot; + return genesisTime + secondsTillCapella + additionalSlots * secondsPerSlot; }; export const squeezeString = (val: string, length: number, sep = "..."): string => { From 1715ab579482377dce2b52406471b279ffa44061 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 17 Jan 2024 19:49:48 +0100 Subject: [PATCH 42/70] chore: remove old vitest version from yarn lock (#6310) --- yarn.lock | 87 ------------------------------------------------------- 1 file changed, 87 deletions(-) diff --git a/yarn.lock b/yarn.lock index 28ddde61a8cb..a6621b6fbd0c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3711,15 +3711,6 @@ "@vitest/utils" "1.1.0" chai "^4.3.10" -"@vitest/expect@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.2.0.tgz#de93f5c32c2781c41415a8c3a6e48e1c023d6613" - integrity sha512-H+2bHzhyvgp32o7Pgj2h9RTHN0pgYaoi26Oo3mE+dCi1PAqV31kIIVfTbqMO3Bvshd5mIrJLc73EwSRrbol9Lw== - dependencies: - "@vitest/spy" "1.2.0" - "@vitest/utils" "1.2.0" - chai "^4.3.10" - "@vitest/runner@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.1.0.tgz#b3bf60f4a78f4324ca09811dd0f87b721a96b534" @@ -3729,15 +3720,6 @@ p-limit "^5.0.0" pathe "^1.1.1" -"@vitest/runner@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.2.0.tgz#84775f0f5c48620ff1943a45c19863355791c6d9" - integrity sha512-vaJkDoQaNUTroT70OhM0NPznP7H3WyRwt4LvGwCVYs/llLaqhoSLnlIhUClZpbF5RgAee29KRcNz0FEhYcgxqA== - dependencies: - "@vitest/utils" "1.2.0" - p-limit "^5.0.0" - pathe "^1.1.1" - "@vitest/snapshot@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.1.0.tgz#b9924e4303382b43bb2c31061b173e69a6fb3437" @@ -3747,15 +3729,6 @@ pathe "^1.1.1" pretty-format "^29.7.0" -"@vitest/snapshot@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.2.0.tgz#2fcddb5c6e8a9d2fc9f18ea2f8fd39b1b6e691b4" - integrity sha512-P33EE7TrVgB3HDLllrjK/GG6WSnmUtWohbwcQqmm7TAk9AVHpdgf7M3F3qRHKm6vhr7x3eGIln7VH052Smo6Kw== - dependencies: - magic-string "^0.30.5" - pathe "^1.1.1" - pretty-format "^29.7.0" - "@vitest/spy@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.1.0.tgz#7f40697e4fc217ac8c3cc89a865d1751b263f561" @@ -3763,13 +3736,6 @@ dependencies: tinyspy "^2.2.0" -"@vitest/spy@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.2.0.tgz#61104de4c19a3addefff021d884c9e20dc17ebcd" - integrity sha512-MNxSAfxUaCeowqyyGwC293yZgk7cECZU9wGb8N1pYQ0yOn/SIr8t0l9XnGRdQZvNV/ZHBYu6GO/W3tj5K3VN1Q== - dependencies: - tinyspy "^2.2.0" - "@vitest/utils@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.1.0.tgz#d177a5f41bdb484bbb43c8d73a77ca782df068b5" @@ -3779,16 +3745,6 @@ loupe "^2.3.7" pretty-format "^29.7.0" -"@vitest/utils@1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.2.0.tgz#deb9bdc3d094bf47f93a592a6a0b3946aa575e7a" - integrity sha512-FyD5bpugsXlwVpTcGLDf3wSPYy8g541fQt14qtzo8mJ4LdEpDKZ9mQy2+qdJm2TZRpjY5JLXihXCgIxiRJgi5g== - dependencies: - diff-sequences "^29.6.3" - estree-walker "^3.0.3" - loupe "^2.3.7" - pretty-format "^29.7.0" - "@wdio/config@8.27.0": version "8.27.0" resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.27.0.tgz#c738d8108b5161cf3f80bb34d0e1f4d700b1a9ce" @@ -4097,11 +4053,6 @@ acorn-walk@^8.3.0: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== -acorn-walk@^8.3.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" - integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== - acorn@^8.10.0, acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" @@ -15055,17 +15006,6 @@ vite-node@1.1.0: picocolors "^1.0.0" vite "^5.0.0" -vite-node@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.0.tgz#9a359804469203a54ac49daad3065f2fd0bfb9c3" - integrity sha512-ETnQTHeAbbOxl7/pyBck9oAPZZZo+kYnFt1uQDD+hPReOc+wCjXw4r4jHriBRuVDB5isHmPXxrfc1yJnfBERqg== - dependencies: - cac "^6.7.14" - debug "^4.3.4" - pathe "^1.1.1" - picocolors "^1.0.0" - vite "^5.0.0" - vite-plugin-node-polyfills@^0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.18.0.tgz#2ad147960f7a35dbbb1c9f9c1ae928bd0f438c1e" @@ -15099,33 +15039,6 @@ vitest-when@^0.3.0: resolved "https://registry.yarnpkg.com/vitest-when/-/vitest-when-0.3.0.tgz#663d4274f1e7302bd24ec00dda8269d20b2eff04" integrity sha512-wYfmzd+GkvdNNhbeb/40PnKpetUP5I7qxvdbu1OAXRXaLrnLfSrJTa/dMIbqqrc8SA0vhonpw5p0RHDXwhDM1Q== -vitest@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.2.0.tgz#2ddff4a32ed992339655f243525c0e187b5af6d9" - integrity sha512-Ixs5m7BjqvLHXcibkzKRQUvD/XLw0E3rvqaCMlrm/0LMsA0309ZqYvTlPzkhh81VlEyVZXFlwWnkhb6/UMtcaQ== - dependencies: - "@vitest/expect" "1.2.0" - "@vitest/runner" "1.2.0" - "@vitest/snapshot" "1.2.0" - "@vitest/spy" "1.2.0" - "@vitest/utils" "1.2.0" - acorn-walk "^8.3.1" - cac "^6.7.14" - chai "^4.3.10" - debug "^4.3.4" - execa "^8.0.1" - local-pkg "^0.5.0" - magic-string "^0.30.5" - pathe "^1.1.1" - picocolors "^1.0.0" - std-env "^3.5.0" - strip-literal "^1.3.0" - tinybench "^2.5.1" - tinypool "^0.8.1" - vite "^5.0.0" - vite-node "1.2.0" - why-is-node-running "^2.2.2" - vitest@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.1.0.tgz#47ba67c564aa137b53b0197d2a992908e7f5b04d" From f3eb48a918225ddd0ddf0d9eaa0cebdbb4c5953c Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Wed, 17 Jan 2024 22:30:06 +0100 Subject: [PATCH 43/70] fix: ignore already known errors in API (#6321) * Ignore known attestations submitted through API * Ignore known sync committee aggregate * Add log contex to ignored aggregate attestations * Fix typo in submitPoolSyncCommitteeSignatures --- .../src/api/impl/beacon/pool/index.ts | 24 +++++++--- .../src/api/impl/validator/index.ts | 46 +++++++++++-------- 2 files changed, 45 insertions(+), 25 deletions(-) diff --git a/packages/beacon-node/src/api/impl/beacon/pool/index.ts b/packages/beacon-node/src/api/impl/beacon/pool/index.ts index 170c358fe417..09a66eba4d15 100644 --- a/packages/beacon-node/src/api/impl/beacon/pool/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/pool/index.ts @@ -8,7 +8,12 @@ import {validateApiVoluntaryExit} from "../../../../chain/validation/voluntaryEx import {validateApiBlsToExecutionChange} from "../../../../chain/validation/blsToExecutionChange.js"; import {validateApiSyncCommittee} from "../../../../chain/validation/syncCommittee.js"; import {ApiModules} from "../../types.js"; -import {AttestationError, GossipAction, SyncCommitteeError} from "../../../../chain/errors/index.js"; +import { + AttestationError, + AttestationErrorCode, + GossipAction, + SyncCommitteeError, +} from "../../../../chain/errors/index.js"; import {validateGossipFnRetryUnknownRoot} from "../../../../network/processor/gossipHandlers.js"; export function getBeaconPoolApi({ @@ -77,12 +82,17 @@ export function getBeaconPoolApi({ const sentPeers = await network.publishBeaconAttestation(attestation, subnet); metrics?.onPoolSubmitUnaggregatedAttestation(seenTimestampSec, indexedAttestation, subnet, sentPeers); } catch (e) { + const logCtx = {slot: attestation.data.slot, index: attestation.data.index}; + + if (e instanceof AttestationError && e.type.code === AttestationErrorCode.ATTESTATION_ALREADY_KNOWN) { + logger.debug("Ignoring known attestation", logCtx); + // Attestations might already be published by another node as part of a fallback setup or DVT cluster + // and can reach our node by gossip before the api. The error can be ignored and should not result in a 500 response. + return; + } + errors.push(e as Error); - logger.error( - `Error on submitPoolAttestations [${i}]`, - {slot: attestation.data.slot, index: attestation.data.index}, - e as Error - ); + logger.error(`Error on submitPoolAttestations [${i}]`, logCtx, e as Error); if (e instanceof AttestationError && e.action === GossipAction.REJECT) { chain.persistInvalidSszValue(ssz.phase0.Attestation, attestation, "api_reject"); } @@ -224,7 +234,7 @@ export function getBeaconPoolApi({ ); if (errors.length > 1) { - throw Error("Multiple errors on publishAggregateAndProofs\n" + errors.map((e) => e.message).join("\n")); + throw Error("Multiple errors on submitPoolSyncCommitteeSignatures\n" + errors.map((e) => e.message).join("\n")); } else if (errors.length === 1) { throw errors[0]; } diff --git a/packages/beacon-node/src/api/impl/validator/index.ts b/packages/beacon-node/src/api/impl/validator/index.ts index fc5cf953018d..e795d1c5afad 100644 --- a/packages/beacon-node/src/api/impl/validator/index.ts +++ b/packages/beacon-node/src/api/impl/validator/index.ts @@ -36,7 +36,13 @@ import { } from "@lodestar/types"; import {ExecutionStatus} from "@lodestar/fork-choice"; import {toHex, racePromisesWithCutoff, RaceEvent} from "@lodestar/utils"; -import {AttestationError, AttestationErrorCode, GossipAction, SyncCommitteeError} from "../../../chain/errors/index.js"; +import { + AttestationError, + AttestationErrorCode, + GossipAction, + SyncCommitteeError, + SyncCommitteeErrorCode, +} from "../../../chain/errors/index.js"; import {validateApiAggregateAndProof} from "../../../chain/validation/index.js"; import {ZERO_HASH} from "../../../constants/index.js"; import {SyncState} from "../../../sync/index.js"; @@ -1073,20 +1079,18 @@ export function getValidatorApi({ const sentPeers = await network.publishBeaconAggregateAndProof(signedAggregateAndProof); metrics?.onPoolSubmitAggregatedAttestation(seenTimestampSec, indexedAttestation, sentPeers); } catch (e) { + const logCtx = { + slot: signedAggregateAndProof.message.aggregate.data.slot, + index: signedAggregateAndProof.message.aggregate.data.index, + }; + if (e instanceof AttestationError && e.type.code === AttestationErrorCode.AGGREGATOR_ALREADY_KNOWN) { - logger.debug("Ignoring known signedAggregateAndProof"); + logger.debug("Ignoring known signedAggregateAndProof", logCtx); return; // Ok to submit the same aggregate twice } errors.push(e as Error); - logger.error( - `Error on publishAggregateAndProofs [${i}]`, - { - slot: signedAggregateAndProof.message.aggregate.data.slot, - index: signedAggregateAndProof.message.aggregate.data.index, - }, - e as Error - ); + logger.error(`Error on publishAggregateAndProofs [${i}]`, logCtx, e as Error); if (e instanceof AttestationError && e.action === GossipAction.REJECT) { chain.persistInvalidSszValue(ssz.phase0.SignedAggregateAndProof, signedAggregateAndProof, "api_reject"); } @@ -1128,15 +1132,21 @@ export function getValidatorApi({ ); await network.publishContributionAndProof(contributionAndProof); } catch (e) { + const logCtx = { + slot: contributionAndProof.message.contribution.slot, + subcommitteeIndex: contributionAndProof.message.contribution.subcommitteeIndex, + }; + + if ( + e instanceof SyncCommitteeError && + e.type.code === SyncCommitteeErrorCode.SYNC_COMMITTEE_AGGREGATOR_ALREADY_KNOWN + ) { + logger.debug("Ignoring known contributionAndProof", logCtx); + return; // Ok to submit the same aggregate twice + } + errors.push(e as Error); - logger.error( - `Error on publishContributionAndProofs [${i}]`, - { - slot: contributionAndProof.message.contribution.slot, - subcommitteeIndex: contributionAndProof.message.contribution.subcommitteeIndex, - }, - e as Error - ); + logger.error(`Error on publishContributionAndProofs [${i}]`, logCtx, e as Error); if (e instanceof SyncCommitteeError && e.action === GossipAction.REJECT) { chain.persistInvalidSszValue(ssz.altair.SignedContributionAndProof, contributionAndProof, "api_reject"); } From 551fd8e4553d07c835e31e2b7939ab5f18c5f95f Mon Sep 17 00:00:00 2001 From: Phil Ngo <58080811+philknows@users.noreply.github.com> Date: Wed, 17 Jan 2024 20:38:10 -0500 Subject: [PATCH 44/70] docs: add documentation contribution instructions (#6294) * add documentation contribution instructions * docs contribution to include cmd and wordlist * spell check documentation * add wordlist check script * word list correction * incorporate feedback --- CONTRIBUTING.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b5990d2eabbf..fbc23571aa37 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -229,6 +229,20 @@ Run script to download dashboards to `./dashboards` folder node scripts/download_dashboards.mjs ``` +## Contributing to Documentation + +When submitting PRs for documentation updates, build and run the documentation locally to ensure functionality before submission. For first time documentation contributors, install the python dependencies with `yarn docs:install`. Build the documentation locally with `yarn docs:build` and serve with `yarn docs:serve` + +Your locally served documentation will then be accessible at http://localhost:8000. + +If you run into build issues due to circular dependencies, branch switching or other incompatibilities, try cleaning your modules and rebuild your dependencies with: + +```sh +yarn clean && yarn clean:nm && yarn && yarn build +``` + +We also use a spelling [word list](https://github.com/ChainSafe/lodestar/blob/unstable/.wordlist.txt) as part of our documentation checks. If using unrecognized words or abbreviations, please extend the word list to pass checks. Make sure the list is sorted with `./scripts/wordlist_sort.sh` and checked with `./scripts/wordlist_sort_check.sh` for sorting and duplicates. + ## Label Guide Issues and pull requests are subject to the following labeling guidelines. From 8cc5f0477acd729d02b4fe0b76fe1779da0882e6 Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Thu, 18 Jan 2024 23:21:46 +0700 Subject: [PATCH 45/70] feat: implement BufferPool for PersistentCPStateCache (#6269) * feat: implement BufferPool for PersistentCPStateCache * fix: alloc vs allocUnsafe for BufferPool * chore: conform to style guide * feat: use using with Disposable object * Add custom build target for beacon-node unit tests * chore: address PR comments --------- Co-authored-by: Nazar Hussain --- .../src/chain/blocks/importBlock.ts | 42 +-- .../beacon-node/src/chain/regen/interface.ts | 2 +- .../beacon-node/src/chain/regen/queued.ts | 10 +- .../src/chain/stateCache/datastore/db.ts | 4 +- .../src/chain/stateCache/datastore/file.ts | 52 ++++ .../src/chain/stateCache/datastore/types.ts | 4 +- .../stateCache/persistentCheckpointsCache.ts | 281 +++++++++++++----- .../src/metrics/metrics/lodestar.ts | 36 +++ packages/beacon-node/src/util/bufferPool.ts | 89 ++++++ packages/beacon-node/src/util/file.ts | 27 ++ .../persistentCheckpointsCache.test.ts | 10 +- .../test/unit/util/bufferPool.test.ts | 29 ++ .../test/utils/chain/stateCache/datastore.ts | 4 +- packages/beacon-node/vitest.config.ts | 4 + .../state-transition/src/cache/stateCache.ts | 10 +- .../src/util/loadState/loadState.ts | 15 +- .../test/perf/util/serializeState.test.ts | 122 ++++++++ scripts/vitest/plugins/buildTargetPlugin.ts | 15 + 18 files changed, 643 insertions(+), 113 deletions(-) create mode 100644 packages/beacon-node/src/chain/stateCache/datastore/file.ts create mode 100644 packages/beacon-node/src/util/bufferPool.ts create mode 100644 packages/beacon-node/test/unit/util/bufferPool.test.ts create mode 100644 packages/state-transition/test/perf/util/serializeState.test.ts create mode 100644 scripts/vitest/plugins/buildTargetPlugin.ts diff --git a/packages/beacon-node/src/chain/blocks/importBlock.ts b/packages/beacon-node/src/chain/blocks/importBlock.ts index 12b43359fa4e..89ed52b66750 100644 --- a/packages/beacon-node/src/chain/blocks/importBlock.ts +++ b/packages/beacon-node/src/chain/blocks/importBlock.ts @@ -59,10 +59,11 @@ export async function importBlock( ): Promise { const {blockInput, postState, parentBlockSlot, executionStatus} = fullyVerifiedBlock; const {block, source} = blockInput; - const blockRoot = this.config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message); + const {slot: blockSlot} = block.message; + const blockRoot = this.config.getForkTypes(blockSlot).BeaconBlock.hashTreeRoot(block.message); const blockRootHex = toHexString(blockRoot); const currentEpoch = computeEpochAtSlot(this.forkChoice.getTime()); - const blockEpoch = computeEpochAtSlot(block.message.slot); + const blockEpoch = computeEpochAtSlot(blockSlot); const parentEpoch = computeEpochAtSlot(parentBlockSlot); const prevFinalizedEpoch = this.forkChoice.getFinalizedCheckpoint().epoch; const blockDelaySec = (fullyVerifiedBlock.seenTimestampSec - postState.genesisTime) % this.config.SECONDS_PER_SLOT; @@ -87,17 +88,16 @@ export async function importBlock( // This adds the state necessary to process the next block // Some block event handlers require state being in state cache so need to do this before emitting EventType.block - this.regen.addPostState(postState); + this.regen.processState(blockRootHex, postState); this.metrics?.importBlock.bySource.inc({source}); - this.logger.verbose("Added block to forkchoice and state cache", {slot: block.message.slot, root: blockRootHex}); + this.logger.verbose("Added block to forkchoice and state cache", {slot: blockSlot, root: blockRootHex}); // We want to import block asap so call all event handler in the next event loop setTimeout(() => { - const slot = block.message.slot; this.emitter.emit(routes.events.EventType.block, { block: blockRootHex, - slot, + slot: blockSlot, executionOptimistic: blockSummary != null && isOptimisticBlock(blockSummary), }); @@ -106,7 +106,7 @@ export async function importBlock( const {index, kzgCommitment} = blobSidecar; this.emitter.emit(routes.events.EventType.blobSidecar, { blockRoot: blockRootHex, - slot, + slot: blockSlot, index, kzgCommitment: toHexString(kzgCommitment), versionedHash: toHexString(kzgCommitmentToVersionedHash(kzgCommitment)), @@ -171,7 +171,7 @@ export async function importBlock( correctHead, missedSlotVote, blockRootHex, - block.message.slot + blockSlot ); } catch (e) { // a block has a lot of attestations and it may has same error, we don't want to log all of them @@ -185,7 +185,7 @@ export async function importBlock( } } else { // always log other errors - this.logger.warn("Error processing attestation from block", {slot: block.message.slot}, e as Error); + this.logger.warn("Error processing attestation from block", {slot: blockSlot}, e as Error); } } } @@ -193,7 +193,7 @@ export async function importBlock( for (const {error, count} of invalidAttestationErrorsByCode.values()) { this.logger.warn( "Error processing attestations from block", - {slot: block.message.slot, erroredAttestations: count}, + {slot: blockSlot, erroredAttestations: count}, error ); } @@ -214,7 +214,7 @@ export async function importBlock( // all AttesterSlashings are valid before reaching this this.forkChoice.onAttesterSlashing(slashing); } catch (e) { - this.logger.warn("Error processing AttesterSlashing from block", {slot: block.message.slot}, e as Error); + this.logger.warn("Error processing AttesterSlashing from block", {slot: blockSlot}, e as Error); } } } @@ -297,7 +297,7 @@ export async function importBlock( parentBlockSlot ); } catch (e) { - this.logger.verbose("Error lightClientServer.onImportBlock", {slot: block.message.slot}, e as Error); + this.logger.verbose("Error lightClientServer.onImportBlock", {slot: blockSlot}, e as Error); } }, 0); } @@ -351,10 +351,10 @@ export async function importBlock( if (parentEpoch < blockEpoch) { // current epoch and previous epoch are likely cached in previous states this.shufflingCache.processState(postState, postState.epochCtx.nextShuffling.epoch); - this.logger.verbose("Processed shuffling for next epoch", {parentEpoch, blockEpoch, slot: block.message.slot}); + this.logger.verbose("Processed shuffling for next epoch", {parentEpoch, blockEpoch, slot: blockSlot}); } - if (block.message.slot % SLOTS_PER_EPOCH === 0) { + if (blockSlot % SLOTS_PER_EPOCH === 0) { // Cache state to preserve epoch transition work const checkpointState = postState; const cp = getCheckpointFromState(checkpointState); @@ -397,7 +397,7 @@ export async function importBlock( // Send block events, only for recent enough blocks - if (this.clock.currentSlot - block.message.slot < EVENTSTREAM_EMIT_RECENT_BLOCK_SLOTS) { + if (this.clock.currentSlot - blockSlot < EVENTSTREAM_EMIT_RECENT_BLOCK_SLOTS) { // NOTE: Skip looping if there are no listeners from the API if (this.emitter.listenerCount(routes.events.EventType.voluntaryExit)) { for (const voluntaryExit of block.message.body.voluntaryExits) { @@ -417,10 +417,10 @@ export async function importBlock( } // Register stat metrics about the block after importing it - this.metrics?.parentBlockDistance.observe(block.message.slot - parentBlockSlot); + this.metrics?.parentBlockDistance.observe(blockSlot - parentBlockSlot); this.metrics?.proposerBalanceDeltaAny.observe(fullyVerifiedBlock.proposerBalanceDelta); this.metrics?.registerImportedBlock(block.message, fullyVerifiedBlock); - if (this.config.getForkSeq(block.message.slot) >= ForkSeq.altair) { + if (this.config.getForkSeq(blockSlot) >= ForkSeq.altair) { this.metrics?.registerSyncAggregateInBlock( blockEpoch, (block as altair.SignedBeaconBlock).message.body.syncAggregate, @@ -433,18 +433,18 @@ export async function importBlock( // Gossip blocks need to be imported as soon as possible, waiting attestations could be processed // in the next event loop. See https://github.com/ChainSafe/lodestar/issues/4789 setTimeout(() => { - this.reprocessController.onBlockImported({slot: block.message.slot, root: blockRootHex}, advancedSlot); + this.reprocessController.onBlockImported({slot: blockSlot, root: blockRootHex}, advancedSlot); }, 0); if (opts.seenTimestampSec !== undefined) { const recvToImportedBlock = Date.now() / 1000 - opts.seenTimestampSec; this.metrics?.gossipBlock.receivedToBlockImport.observe(recvToImportedBlock); - this.logger.verbose("Imported block", {slot: block.message.slot, recvToImportedBlock}); + this.logger.verbose("Imported block", {slot: blockSlot, recvToImportedBlock}); } this.logger.verbose("Block processed", { - slot: block.message.slot, + slot: blockSlot, root: blockRootHex, - delaySec: this.clock.secFromSlot(block.message.slot), + delaySec: this.clock.secFromSlot(blockSlot), }); } diff --git a/packages/beacon-node/src/chain/regen/interface.ts b/packages/beacon-node/src/chain/regen/interface.ts index e7be64d0eecb..be481de9abc8 100644 --- a/packages/beacon-node/src/chain/regen/interface.ts +++ b/packages/beacon-node/src/chain/regen/interface.ts @@ -39,7 +39,7 @@ export interface IStateRegenerator extends IStateRegeneratorInternal { getClosestHeadState(head: ProtoBlock): CachedBeaconStateAllForks | null; pruneOnCheckpoint(finalizedEpoch: Epoch, justifiedEpoch: Epoch, headStateRoot: RootHex): void; pruneOnFinalized(finalizedEpoch: Epoch): void; - addPostState(postState: CachedBeaconStateAllForks): void; + processState(blockRootHex: RootHex, postState: CachedBeaconStateAllForks): void; addCheckpointState(cp: phase0.Checkpoint, item: CachedBeaconStateAllForks): void; updateHeadState(newHeadStateRoot: RootHex, maybeHeadState: CachedBeaconStateAllForks): void; updatePreComputedCheckpoint(rootHex: RootHex, epoch: Epoch): number | null; diff --git a/packages/beacon-node/src/chain/regen/queued.ts b/packages/beacon-node/src/chain/regen/queued.ts index dfda56cc1eea..928c2e399b9a 100644 --- a/packages/beacon-node/src/chain/regen/queued.ts +++ b/packages/beacon-node/src/chain/regen/queued.ts @@ -4,9 +4,10 @@ import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {CachedBeaconStateAllForks, computeEpochAtSlot} from "@lodestar/state-transition"; import {Logger} from "@lodestar/utils"; import {routes} from "@lodestar/api"; -import {CheckpointHex, CheckpointStateCache, StateContextCache, toCheckpointHex} from "../stateCache/index.js"; +import {CheckpointHex, toCheckpointHex} from "../stateCache/index.js"; import {Metrics} from "../../metrics/index.js"; import {JobItemQueue} from "../../util/queue/index.js"; +import {BlockStateCache, CheckpointStateCache} from "../stateCache/types.js"; import {IStateRegenerator, IStateRegeneratorInternal, RegenCaller, RegenFnName, StateCloneOpts} from "./interface.js"; import {StateRegenerator, RegenModules} from "./regen.js"; import {RegenError, RegenErrorCode} from "./errors.js"; @@ -34,7 +35,7 @@ export class QueuedStateRegenerator implements IStateRegenerator { private readonly regen: StateRegenerator; private readonly forkChoice: IForkChoice; - private readonly stateCache: StateContextCache; + private readonly stateCache: BlockStateCache; private readonly checkpointStateCache: CheckpointStateCache; private readonly metrics: Metrics | null; private readonly logger: Logger; @@ -88,8 +89,11 @@ export class QueuedStateRegenerator implements IStateRegenerator { this.stateCache.deleteAllBeforeEpoch(finalizedEpoch); } - addPostState(postState: CachedBeaconStateAllForks): void { + processState(blockRootHex: RootHex, postState: CachedBeaconStateAllForks): void { this.stateCache.add(postState); + this.checkpointStateCache.processState(blockRootHex, postState).catch((e) => { + this.logger.debug("Error processing block state", {blockRootHex, slot: postState.slot}, e); + }); } addCheckpointState(cp: phase0.Checkpoint, item: CachedBeaconStateAllForks): void { diff --git a/packages/beacon-node/src/chain/stateCache/datastore/db.ts b/packages/beacon-node/src/chain/stateCache/datastore/db.ts index fef38a7f8dd2..c6c9a3ee924b 100644 --- a/packages/beacon-node/src/chain/stateCache/datastore/db.ts +++ b/packages/beacon-node/src/chain/stateCache/datastore/db.ts @@ -1,4 +1,3 @@ -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, ssz} from "@lodestar/types"; import {IBeaconDb} from "../../../db/interface.js"; import {CPStateDatastore, DatastoreKey} from "./types.js"; @@ -9,9 +8,8 @@ import {CPStateDatastore, DatastoreKey} from "./types.js"; export class DbCPStateDatastore implements CPStateDatastore { constructor(private readonly db: IBeaconDb) {} - async write(cpKey: phase0.Checkpoint, state: CachedBeaconStateAllForks): Promise { + async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise { const serializedCheckpoint = checkpointToDatastoreKey(cpKey); - const stateBytes = state.serialize(); await this.db.checkpointState.putBinary(serializedCheckpoint, stateBytes); return serializedCheckpoint; } diff --git a/packages/beacon-node/src/chain/stateCache/datastore/file.ts b/packages/beacon-node/src/chain/stateCache/datastore/file.ts new file mode 100644 index 000000000000..6529d12f84db --- /dev/null +++ b/packages/beacon-node/src/chain/stateCache/datastore/file.ts @@ -0,0 +1,52 @@ +import path from "node:path"; +import {toHexString, fromHexString} from "@chainsafe/ssz"; +import {phase0, ssz} from "@lodestar/types"; +import {ensureDir, readFile, readFileNames, removeFile, writeIfNotExist} from "../../../util/file.js"; +import {CPStateDatastore, DatastoreKey} from "./types.js"; + +const CHECKPOINT_STATES_FOLDER = "checkpoint_states"; +const CHECKPOINT_FILE_NAME_LENGTH = 82; + +/** + * Implementation of CPStateDatastore using file system, this is beneficial for debugging. + */ +export class FileCPStateDatastore implements CPStateDatastore { + private readonly folderPath: string; + + constructor(parentDir: string = ".") { + // by default use the beacon folder `/beacon/checkpoint_states` + this.folderPath = path.join(parentDir, CHECKPOINT_STATES_FOLDER); + } + + async init(): Promise { + try { + await ensureDir(this.folderPath); + } catch (_) { + // do nothing + } + } + + async write(cpKey: phase0.Checkpoint, stateBytes: Uint8Array): Promise { + const serializedCheckpoint = ssz.phase0.Checkpoint.serialize(cpKey); + const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + await writeIfNotExist(filePath, stateBytes); + return serializedCheckpoint; + } + + async remove(serializedCheckpoint: DatastoreKey): Promise { + const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + await removeFile(filePath); + } + + async read(serializedCheckpoint: DatastoreKey): Promise { + const filePath = path.join(this.folderPath, toHexString(serializedCheckpoint)); + return readFile(filePath); + } + + async readKeys(): Promise { + const fileNames = await readFileNames(this.folderPath); + return fileNames + .filter((fileName) => fileName.startsWith("0x") && fileName.length === CHECKPOINT_FILE_NAME_LENGTH) + .map((fileName) => fromHexString(fileName)); + } +} diff --git a/packages/beacon-node/src/chain/stateCache/datastore/types.ts b/packages/beacon-node/src/chain/stateCache/datastore/types.ts index 66ea67f93500..0f81e6ae1e75 100644 --- a/packages/beacon-node/src/chain/stateCache/datastore/types.ts +++ b/packages/beacon-node/src/chain/stateCache/datastore/types.ts @@ -1,4 +1,3 @@ -import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0} from "@lodestar/types"; // With db implementation, persistedKey is serialized data of a checkpoint @@ -6,8 +5,9 @@ export type DatastoreKey = Uint8Array; // Make this generic to support testing export interface CPStateDatastore { - write: (cpKey: phase0.Checkpoint, state: CachedBeaconStateAllForks) => Promise; + write: (cpKey: phase0.Checkpoint, stateBytes: Uint8Array) => Promise; remove: (key: DatastoreKey) => Promise; read: (key: DatastoreKey) => Promise; readKeys: () => Promise; + init?: () => Promise; } diff --git a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts index 8ad5c5098118..b57e51f8f2d6 100644 --- a/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts +++ b/packages/beacon-node/src/chain/stateCache/persistentCheckpointsCache.ts @@ -1,15 +1,24 @@ import {fromHexString, toHexString} from "@chainsafe/ssz"; import {phase0, Epoch, RootHex} from "@lodestar/types"; import {CachedBeaconStateAllForks, computeStartSlotAtEpoch, getBlockRootAtSlot} from "@lodestar/state-transition"; -import {Logger, MapDef} from "@lodestar/utils"; +import {Logger, MapDef, sleep} from "@lodestar/utils"; import {routes} from "@lodestar/api"; import {loadCachedBeaconState} from "@lodestar/state-transition"; +import {INTERVALS_PER_SLOT} from "@lodestar/params"; import {Metrics} from "../../metrics/index.js"; import {IClock} from "../../util/clock.js"; import {ShufflingCache} from "../shufflingCache.js"; +import {BufferPool, BufferWithKey} from "../../util/bufferPool.js"; import {MapTracker} from "./mapMetrics.js"; -import {CheckpointHex, CheckpointStateCache, CacheItemType} from "./types.js"; import {CPStateDatastore, DatastoreKey, datastoreKeyToCheckpoint} from "./datastore/index.js"; +import {CheckpointHex, CacheItemType, CheckpointStateCache} from "./types.js"; + +export type PersistentCheckpointStateCacheOpts = { + /** Keep max n states in memory, persist the rest to disk */ + maxCPStateEpochsInMemory?: number; + /** for testing only */ + processLateBlock?: boolean; +}; type GetHeadStateFn = () => CachedBeaconStateAllForks; @@ -17,14 +26,11 @@ type PersistentCheckpointStateCacheModules = { metrics?: Metrics | null; logger: Logger; clock?: IClock | null; + signal?: AbortSignal; shufflingCache: ShufflingCache; datastore: CPStateDatastore; getHeadState?: GetHeadStateFn; -}; - -type PersistentCheckpointStateCacheOpts = { - // Keep max n states in memory, persist the rest to disk - maxCPStateEpochsInMemory?: number; + bufferPool?: BufferPool; }; /** checkpoint serialized as a string */ @@ -90,15 +96,27 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { private readonly metrics: Metrics["cpStateCache"] | null | undefined; private readonly logger: Logger; private readonly clock: IClock | null | undefined; + private readonly signal: AbortSignal | undefined; private preComputedCheckpoint: string | null = null; private preComputedCheckpointHits: number | null = null; private readonly maxEpochsInMemory: number; + private readonly processLateBlock: boolean; private readonly datastore: CPStateDatastore; private readonly shufflingCache: ShufflingCache; private readonly getHeadState?: GetHeadStateFn; + private readonly bufferPool?: BufferPool; constructor( - {metrics, logger, clock, shufflingCache, datastore, getHeadState}: PersistentCheckpointStateCacheModules, + { + metrics, + logger, + clock, + signal, + shufflingCache, + datastore, + getHeadState, + bufferPool, + }: PersistentCheckpointStateCacheModules, opts: PersistentCheckpointStateCacheOpts ) { this.cache = new MapTracker(metrics?.cpStateCache); @@ -127,20 +145,26 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { } this.logger = logger; this.clock = clock; + this.signal = signal; if (opts.maxCPStateEpochsInMemory !== undefined && opts.maxCPStateEpochsInMemory < 0) { throw new Error("maxEpochsInMemory must be >= 0"); } this.maxEpochsInMemory = opts.maxCPStateEpochsInMemory ?? DEFAULT_MAX_CP_STATE_EPOCHS_IN_MEMORY; + this.processLateBlock = opts.processLateBlock ?? false; // Specify different datastore for testing this.datastore = datastore; this.shufflingCache = shufflingCache; this.getHeadState = getHeadState; + this.bufferPool = bufferPool; } /** * Reload checkpoint state keys from the last run. */ async init(): Promise { + if (this.datastore?.init) { + await this.datastore.init(); + } const persistedKeys = await this.datastore.readKeys(); for (const persistedKey of persistedKeys) { const cp = datastoreKeyToCheckpoint(persistedKey); @@ -177,10 +201,32 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { this.logger.debug("Reload: found seed state", {...logMeta, seedSlot: seedState.slot}); try { + // 80% of validators serialization time comes from memory allocation, this is to avoid it + const sszTimer = this.metrics?.stateReloadValidatorsSszDuration.startTimer(); + // automatically free the buffer pool after this scope + using validatorsBytesWithKey = this.serializeStateValidators(seedState); + let validatorsBytes = validatorsBytesWithKey?.buffer; + if (validatorsBytes == null) { + // fallback logic in case we can't use the buffer pool + this.metrics?.stateReloadValidatorsSszAllocCount.inc(); + validatorsBytes = seedState.validators.serialize(); + } + sszTimer?.(); const timer = this.metrics?.stateReloadDuration.startTimer(); - const newCachedState = loadCachedBeaconState(seedState, stateBytes, { - shufflingGetter: this.shufflingCache.getSync.bind(this.shufflingCache), - }); + const newCachedState = loadCachedBeaconState( + seedState, + stateBytes, + { + shufflingGetter: (shufflingEpoch, decisionRootHex) => { + const shuffling = this.shufflingCache.getSync(shufflingEpoch, decisionRootHex); + if (shuffling == null) { + this.metrics?.stateReloadShufflingCacheMiss.inc(); + } + return shuffling; + }, + }, + validatorsBytes + ); newCachedState.commit(); const stateRoot = toHexString(newCachedState.hashTreeRoot()); timer?.(); @@ -421,7 +467,7 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { * - 1 then we'll persist {root: b1, epoch n-1} checkpoint state to disk. Note that at epoch n there is both {root: b0, epoch: n} and {root: c0, epoch: n} checkpoint states in memory * - 2 then we'll persist {root: b2, epoch n-2} checkpoint state to disk, there are also 2 checkpoint states in memory at epoch n, same to the above (maxEpochsInMemory=1) * - * As of Nov 2023, it takes 1.3s to 1.5s to persist a state on holesky on fast server. TODO: + * As of Jan 2024, it takes 1.2s to persist a holesky state on fast server. TODO: * - improve state serialization time * - or research how to only store diff against the finalized state */ @@ -433,65 +479,36 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { return 0; } - for (const lowestEpoch of sortedEpochs.slice(0, sortedEpochs.length - this.maxEpochsInMemory)) { - const epochBoundarySlot = computeStartSlotAtEpoch(lowestEpoch); - const epochBoundaryRoot = - epochBoundarySlot === state.slot ? fromHexString(blockRootHex) : getBlockRootAtSlot(state, epochBoundarySlot); - const epochBoundaryHex = toHexString(epochBoundaryRoot); - - // for each epoch, usually there are 2 rootHex respective to the 2 checkpoint states: Previous Root Checkpoint State and Current Root Checkpoint State - for (const rootHex of this.epochIndex.get(lowestEpoch) ?? []) { - const cpKey = toCacheKey({epoch: lowestEpoch, rootHex}); - const cacheItem = this.cache.get(cpKey); + const blockSlot = state.slot; + const twoThirdsSlot = (2 * state.config.SECONDS_PER_SLOT) / INTERVALS_PER_SLOT; + // we always have clock in production, fallback value is only for test + const secFromSlot = this.clock?.secFromSlot(blockSlot) ?? twoThirdsSlot; + const secToTwoThirdsSlot = twoThirdsSlot - secFromSlot; + if (secToTwoThirdsSlot > 0) { + // 2/3 of slot is the most free time of every slot, take that chance to persist checkpoint states + // normally it should only persist checkpoint states at 2/3 of slot 0 of epoch + await sleep(secToTwoThirdsSlot * 1000, this.signal); + } else if (!this.processLateBlock) { + // normally the block persist happens at 2/3 of slot 0 of epoch, if it's already late then just skip to allow other tasks to run + // there are plenty of chances in the same epoch to persist checkpoint states, also if block is late it could be reorged + this.logger.verbose("Skip persist checkpoint states", {blockSlot, root: blockRootHex}); + return 0; + } - if (cacheItem !== undefined && isInMemoryCacheItem(cacheItem)) { - // this is state in memory, we don't care if the checkpoint state is already persisted - let {persistedKey} = cacheItem; - const {state} = cacheItem; - const logMeta = { - stateSlot: state.slot, - rootHex, - epochBoundaryHex, - persistedKey: persistedKey ? toHexString(persistedKey) : "", - }; - - if (rootHex === epochBoundaryHex) { - if (persistedKey) { - // no need to persist - this.logger.verbose("Pruned checkpoint state from memory but no need to persist", logMeta); - } else { - // persist and do not update epochIndex - this.metrics?.statePersistSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); - const timer = this.metrics?.statePersistDuration.startTimer(); - const cpPersist = {epoch: lowestEpoch, root: epochBoundaryRoot}; - persistedKey = await this.datastore.write(cpPersist, state); - timer?.(); - persistCount++; - this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", { - ...logMeta, - persistedKey: toHexString(persistedKey), - }); - } - // overwrite cpKey, this means the state is deleted from memory - this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey}); - } else { - if (persistedKey) { - // persisted file will be eventually deleted by the archive task - // this also means the state is deleted from memory - this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey}); - // do not update epochIndex - } else { - // delete the state from memory - this.cache.delete(cpKey); - this.epochIndex.get(lowestEpoch)?.delete(rootHex); - } - this.metrics?.statePruneFromMemoryCount.inc(); - this.logger.verbose("Pruned checkpoint state from memory", logMeta); - } - } - } + const persistEpochs = sortedEpochs.slice(0, sortedEpochs.length - this.maxEpochsInMemory); + for (const lowestEpoch of persistEpochs) { + // usually there is only 0 or 1 epoch to persist in this loop + persistCount += await this.processPastEpoch(blockRootHex, state, lowestEpoch); } + if (persistCount > 0) { + this.logger.verbose("Persisted checkpoint states", { + slot: blockSlot, + root: blockRootHex, + persistCount, + persistEpochs: persistEpochs.length, + }); + } return persistCount; } @@ -575,6 +592,85 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { return Array.from(this.cache.keys()); } + /** + * Prune or persist checkpoint states in an epoch, see the description in `processState()` function + */ + private async processPastEpoch( + blockRootHex: RootHex, + state: CachedBeaconStateAllForks, + epoch: Epoch + ): Promise { + let persistCount = 0; + const epochBoundarySlot = computeStartSlotAtEpoch(epoch); + const epochBoundaryRoot = + epochBoundarySlot === state.slot ? fromHexString(blockRootHex) : getBlockRootAtSlot(state, epochBoundarySlot); + const epochBoundaryHex = toHexString(epochBoundaryRoot); + + // for each epoch, usually there are 2 rootHex respective to the 2 checkpoint states: Previous Root Checkpoint State and Current Root Checkpoint State + for (const rootHex of this.epochIndex.get(epoch) ?? []) { + const cpKey = toCacheKey({epoch: epoch, rootHex}); + const cacheItem = this.cache.get(cpKey); + + if (cacheItem !== undefined && isInMemoryCacheItem(cacheItem)) { + // this is state in memory, we don't care if the checkpoint state is already persisted + let {persistedKey} = cacheItem; + const {state} = cacheItem; + const logMeta = { + stateSlot: state.slot, + rootHex, + epochBoundaryHex, + persistedKey: persistedKey ? toHexString(persistedKey) : "", + }; + + if (rootHex === epochBoundaryHex) { + if (persistedKey) { + // no need to persist + this.logger.verbose("Pruned checkpoint state from memory but no need to persist", logMeta); + } else { + // persist and do not update epochIndex + this.metrics?.statePersistSecFromSlot.observe(this.clock?.secFromSlot(this.clock?.currentSlot ?? 0) ?? 0); + const cpPersist = {epoch: epoch, root: epochBoundaryRoot}; + { + const timer = this.metrics?.statePersistDuration.startTimer(); + // automatically free the buffer pool after this scope + using stateBytesWithKey = this.serializeState(state); + let stateBytes = stateBytesWithKey?.buffer; + if (stateBytes == null) { + // fallback logic to use regular way to get state ssz bytes + this.metrics?.persistedStateAllocCount.inc(); + stateBytes = state.serialize(); + } + persistedKey = await this.datastore.write(cpPersist, stateBytes); + timer?.(); + } + persistCount++; + this.logger.verbose("Pruned checkpoint state from memory and persisted to disk", { + ...logMeta, + persistedKey: toHexString(persistedKey), + }); + } + // overwrite cpKey, this means the state is deleted from memory + this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey}); + } else { + if (persistedKey) { + // persisted file will be eventually deleted by the archive task + // this also means the state is deleted from memory + this.cache.set(cpKey, {type: CacheItemType.persisted, value: persistedKey}); + // do not update epochIndex + } else { + // delete the state from memory + this.cache.delete(cpKey); + this.epochIndex.get(epoch)?.delete(rootHex); + } + this.metrics?.statePruneFromMemoryCount.inc(); + this.logger.verbose("Pruned checkpoint state from memory", logMeta); + } + } + } + + return persistCount; + } + /** * Delete all items of an epoch from disk and memory */ @@ -602,9 +698,56 @@ export class PersistentCheckpointStateCache implements CheckpointStateCache { rootHexes: Array.from(rootHexes).join(","), }); } + + /* + * It's not sustainable to allocate ~240MB for each state every epoch, so we use buffer pool to reuse the memory. + * As monitored on holesky as of Jan 2024: + * - This does not increase heap allocation while gc time is the same + * - It helps stabilize persist time and save ~300ms in average (1.5s vs 1.2s) + * - It also helps the state reload to save ~500ms in average (4.3s vs 3.8s) + * - Also `serializeState.test.ts` perf test shows a lot of differences allocating ~240MB once vs per state serialization + */ + private serializeState(state: CachedBeaconStateAllForks): BufferWithKey | null { + const size = state.type.tree_serializedSize(state.node); + if (this.bufferPool) { + const bufferWithKey = this.bufferPool.alloc(size); + if (bufferWithKey) { + const stateBytes = bufferWithKey.buffer; + const dataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); + state.type.tree_serializeToBytes({uint8Array: stateBytes, dataView}, 0, state.node); + return bufferWithKey; + } + } + + return null; + } + + /** + * Serialize validators to bytes leveraging the buffer pool to save memory allocation. + * - As monitored on holesky as of Jan 2024, it helps save ~500ms state reload time (4.3s vs 3.8s) + * - Also `serializeState.test.ts` perf test shows a lot of differences allocating validators bytes once vs every time, + * This is 2x - 3x faster than allocating memory every time. + * TODO: consider serializing validators manually like in `serializeState.test.ts` perf test, this could be 3x faster than this + */ + private serializeStateValidators(state: CachedBeaconStateAllForks): BufferWithKey | null { + // const validatorsSszTimer = this.metrics?.stateReloadValidatorsSszDuration.startTimer(); + const type = state.type.fields.validators; + const size = type.tree_serializedSize(state.validators.node); + if (this.bufferPool) { + const bufferWithKey = this.bufferPool.alloc(size); + if (bufferWithKey) { + const validatorsBytes = bufferWithKey.buffer; + const dataView = new DataView(validatorsBytes.buffer, validatorsBytes.byteOffset, validatorsBytes.byteLength); + type.tree_serializeToBytes({uint8Array: validatorsBytes, dataView}, 0, state.validators.node); + return bufferWithKey; + } + } + + return null; + } } -function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex { +export function toCheckpointHex(checkpoint: phase0.Checkpoint): CheckpointHex { return { epoch: checkpoint.epoch, rootHex: toHexString(checkpoint.root), diff --git a/packages/beacon-node/src/metrics/metrics/lodestar.ts b/packages/beacon-node/src/metrics/metrics/lodestar.ts index f6b143913346..284f4e75c064 100644 --- a/packages/beacon-node/src/metrics/metrics/lodestar.ts +++ b/packages/beacon-node/src/metrics/metrics/lodestar.ts @@ -1086,6 +1086,25 @@ export function createLodestarMetrics( }), }, + bufferPool: { + length: register.gauge({ + name: "lodestar_buffer_pool_length", + help: "Buffer pool length", + }), + hits: register.counter({ + name: "lodestar_buffer_pool_hits_total", + help: "Total number of buffer pool hits", + }), + misses: register.counter({ + name: "lodestar_buffer_pool_misses_total", + help: "Total number of buffer pool misses", + }), + grows: register.counter({ + name: "lodestar_buffer_pool_grows_total", + help: "Total number of buffer pool length increases", + }), + }, + cpStateCache: { lookups: register.gauge({ name: "lodestar_cp_state_cache_lookups_total", @@ -1136,6 +1155,19 @@ export function createLodestarMetrics( help: "Histogram of time to persist state to db since the clock slot", buckets: [0, 2, 4, 6, 8, 10, 12], }), + stateReloadValidatorsSszDuration: register.histogram({ + name: "lodestar_cp_state_cache_state_reload_validators_ssz_seconds", + help: "Histogram of time to serialize validators", + buckets: [0.1, 0.2, 0.5, 1], + }), + stateReloadValidatorsSszAllocCount: register.counter({ + name: "lodestar_cp_state_cache_state_reload_validators_ssz_alloc_count", + help: "Total number time to allocate memory for validators serialization", + }), + stateReloadShufflingCacheMiss: register.counter({ + name: "lodestar_cp_state_cache_state_reload_shuffling_cache_miss_count", + help: "Total number of shuffling cache misses when loading a state", + }), stateReloadDuration: register.histogram({ name: "lodestar_cp_state_cache_state_reload_seconds", help: "Histogram of time to load state from db", @@ -1160,6 +1192,10 @@ export function createLodestarMetrics( name: "lodestar_cp_state_cache_persisted_state_remove_count", help: "Total number of persisted states removed", }), + persistedStateAllocCount: register.counter({ + name: "lodestar_cp_state_cache_persisted_state_alloc_count", + help: "Total number time to allocate memory for persisted state", + }), }, balancesCache: { diff --git a/packages/beacon-node/src/util/bufferPool.ts b/packages/beacon-node/src/util/bufferPool.ts new file mode 100644 index 000000000000..f9e18a6d64a5 --- /dev/null +++ b/packages/beacon-node/src/util/bufferPool.ts @@ -0,0 +1,89 @@ +import {Metrics} from "../metrics/metrics.js"; + +/** + * If consumer wants more memory than available, we grow the buffer by this ratio. + */ +const GROW_RATIO = 1.1; + +/** + * A simple implementation to manage a single buffer. + * This is initially used for state serialization at every epoch and for state reload. + * We can enhance and use this for other purposes in the future. + */ +export class BufferPool { + private buffer: Uint8Array; + private inUse = false; + private currentKey: number; + private readonly metrics: Metrics["bufferPool"] | null = null; + + constructor(size: number, metrics: Metrics | null = null) { + this.buffer = new Uint8Array(Math.floor(size * GROW_RATIO)); + this.currentKey = 0; + if (metrics) { + this.metrics = metrics.bufferPool; + metrics.bufferPool.length.addCollect(() => { + metrics.bufferPool.length.set(this.buffer.length); + }); + } + } + + get length(): number { + return this.buffer.length; + } + + /** + * Returns a buffer of the given size with all 0. + * If the buffer is already in use, return null. + * Grow the buffer if the requested size is larger than the current buffer. + */ + alloc(size: number): BufferWithKey | null { + return this.doAlloc(size, false); + } + + /** + * Same to alloc() but the buffer is not zeroed. + */ + allocUnsafe(size: number): BufferWithKey | null { + return this.doAlloc(size, true); + } + + private doAlloc(size: number, isUnsafe = false): BufferWithKey | null { + if (this.inUse) { + this.metrics?.misses.inc(); + return null; + } + this.inUse = true; + this.metrics?.hits.inc(); + this.currentKey += 1; + if (size > this.buffer.length) { + this.metrics?.grows.inc(); + this.buffer = new Uint8Array(Math.floor(size * GROW_RATIO)); + } + const bytes = this.buffer.subarray(0, size); + if (!isUnsafe) { + bytes.fill(0); + } + return new BufferWithKey(bytes, this.currentKey, this); + } + + /** + * Marks the buffer as free. + */ + free(key: number): void { + if (key === this.currentKey) { + this.inUse = false; + } + } +} + +export class BufferWithKey implements Disposable { + constructor( + readonly buffer: Uint8Array, + private readonly key: number, + private readonly pool: BufferPool + ) {} + + [Symbol.dispose](): void { + this.pool.free(this.key); + } +} diff --git a/packages/beacon-node/src/util/file.ts b/packages/beacon-node/src/util/file.ts index af78ca8b6126..c194fb07a3b8 100644 --- a/packages/beacon-node/src/util/file.ts +++ b/packages/beacon-node/src/util/file.ts @@ -23,3 +23,30 @@ export async function writeIfNotExist(filepath: string, bytes: Uint8Array): Prom return true; } } + +/** Remove a file if it exists */ +export async function removeFile(path: string): Promise { + try { + await promisify(fs.unlink)(path); + return true; + } catch (_) { + // may not exists + return false; + } +} + +export async function readFile(path: string): Promise { + try { + return await fs.promises.readFile(path); + } catch (_) { + return null; + } +} + +export async function readFileNames(folderPath: string): Promise { + try { + return await fs.promises.readdir(folderPath); + } catch (_) { + return []; + } +} diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index 83a2dddd65dd..18bdfac89793 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -88,7 +88,7 @@ describe("PersistentCheckpointStateCache", function () { const datastore = getTestDatastore(fileApisBuffer); cache = new PersistentCheckpointStateCache( {datastore, logger: testLogger(), shufflingCache: new ShufflingCache()}, - {maxCPStateEpochsInMemory: 2} + {maxCPStateEpochsInMemory: 2, processLateBlock: true} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -156,7 +156,7 @@ describe("PersistentCheckpointStateCache", function () { const datastore = getTestDatastore(fileApisBuffer); cache = new PersistentCheckpointStateCache( {datastore, logger: testLogger(), shufflingCache: new ShufflingCache()}, - {maxCPStateEpochsInMemory: 2} + {maxCPStateEpochsInMemory: 2, processLateBlock: true} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -228,7 +228,7 @@ describe("PersistentCheckpointStateCache", function () { const datastore = getTestDatastore(fileApisBuffer); cache = new PersistentCheckpointStateCache( {datastore, logger: testLogger(), shufflingCache: new ShufflingCache()}, - {maxCPStateEpochsInMemory: 2} + {maxCPStateEpochsInMemory: 2, processLateBlock: true} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -527,7 +527,7 @@ describe("PersistentCheckpointStateCache", function () { const datastore = getTestDatastore(fileApisBuffer); cache = new PersistentCheckpointStateCache( {datastore, logger: testLogger(), shufflingCache: new ShufflingCache()}, - {maxCPStateEpochsInMemory: 1} + {maxCPStateEpochsInMemory: 1, processLateBlock: true} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); @@ -792,7 +792,7 @@ describe("PersistentCheckpointStateCache", function () { const datastore = getTestDatastore(fileApisBuffer); cache = new PersistentCheckpointStateCache( {datastore, logger: testLogger(), shufflingCache: new ShufflingCache()}, - {maxCPStateEpochsInMemory: 0} + {maxCPStateEpochsInMemory: 0, processLateBlock: true} ); cache.add(cp0a, states["cp0a"]); cache.add(cp0b, states["cp0b"]); diff --git a/packages/beacon-node/test/unit/util/bufferPool.test.ts b/packages/beacon-node/test/unit/util/bufferPool.test.ts new file mode 100644 index 000000000000..2c789c19f74d --- /dev/null +++ b/packages/beacon-node/test/unit/util/bufferPool.test.ts @@ -0,0 +1,29 @@ +import {describe, it, expect} from "vitest"; +import {BufferPool} from "../../../src/util/bufferPool.js"; + +describe("BufferPool", () => { + const pool = new BufferPool(100); + + it("should increase length", () => { + expect(pool.length).toEqual(110); + using mem = pool.alloc(200); + if (mem === null) { + throw Error("Expected non-null mem"); + } + expect(pool.length).toEqual(220); + }); + + it("should not allow alloc if in use", () => { + { + using mem = pool.alloc(20); + if (mem === null) { + throw Error("Expected non-null mem"); + } + // in the same scope we can't allocate again + expect(pool.alloc(20)).toEqual(null); + } + + // out of the scope we can allocate again + expect(pool.alloc(20)).not.toEqual(null); + }); +}); diff --git a/packages/beacon-node/test/utils/chain/stateCache/datastore.ts b/packages/beacon-node/test/utils/chain/stateCache/datastore.ts index 8a944f4c2d88..73eab697de96 100644 --- a/packages/beacon-node/test/utils/chain/stateCache/datastore.ts +++ b/packages/beacon-node/test/utils/chain/stateCache/datastore.ts @@ -3,11 +3,11 @@ import {CPStateDatastore, checkpointToDatastoreKey} from "../../../../src/chain/ export function getTestDatastore(fileApisBuffer: Map): CPStateDatastore { const datastore: CPStateDatastore = { - write: (cp, state) => { + write: (cp, stateBytes) => { const persistentKey = checkpointToDatastoreKey(cp); const stringKey = toHexString(persistentKey); if (!fileApisBuffer.has(stringKey)) { - fileApisBuffer.set(stringKey, state.serialize()); + fileApisBuffer.set(stringKey, stateBytes); } return Promise.resolve(persistentKey); }, diff --git a/packages/beacon-node/vitest.config.ts b/packages/beacon-node/vitest.config.ts index 1df0de848936..2a2b2c65304c 100644 --- a/packages/beacon-node/vitest.config.ts +++ b/packages/beacon-node/vitest.config.ts @@ -1,9 +1,13 @@ import {defineConfig, mergeConfig} from "vitest/config"; import vitestConfig from "../../vitest.base.config"; +import {buildTargetPlugin} from "../../scripts/vitest/plugins/buildTargetPlugin.js"; export default mergeConfig( vitestConfig, defineConfig({ + // We need to change the build target to test code which is based on `using` keyword + // Note this target is not fully supported for the browsers + plugins: [buildTargetPlugin("es2022")], test: { globalSetup: ["./test/globalSetup.ts"], }, diff --git a/packages/state-transition/src/cache/stateCache.ts b/packages/state-transition/src/cache/stateCache.ts index b01ca0c409b2..8b45152a3646 100644 --- a/packages/state-transition/src/cache/stateCache.ts +++ b/packages/state-transition/src/cache/stateCache.ts @@ -164,9 +164,15 @@ export function createCachedBeaconState( export function loadCachedBeaconState( cachedSeedState: T, stateBytes: Uint8Array, - opts?: EpochCacheOpts + opts?: EpochCacheOpts, + seedValidatorsBytes?: Uint8Array ): T { - const {state: migratedState, modifiedValidators} = loadState(cachedSeedState.config, cachedSeedState, stateBytes); + const {state: migratedState, modifiedValidators} = loadState( + cachedSeedState.config, + cachedSeedState, + stateBytes, + seedValidatorsBytes + ); const {pubkey2index, index2pubkey} = cachedSeedState.epochCtx; // Get the validators sub tree once for all the loop const validators = migratedState.validators; diff --git a/packages/state-transition/src/util/loadState/loadState.ts b/packages/state-transition/src/util/loadState/loadState.ts index 83377101609d..dc9f8fe4fcab 100644 --- a/packages/state-transition/src/util/loadState/loadState.ts +++ b/packages/state-transition/src/util/loadState/loadState.ts @@ -20,7 +20,8 @@ type MigrateStateOutput = {state: BeaconStateAllForks; modifiedValidators: numbe export function loadState( config: ChainForkConfig, seedState: BeaconStateAllForks, - stateBytes: Uint8Array + stateBytes: Uint8Array, + seedValidatorsBytes?: Uint8Array ): MigrateStateOutput { // casting only to make typescript happy const stateType = getStateTypeFromBytes(config, stateBytes) as typeof ssz.capella.BeaconState; @@ -42,7 +43,8 @@ export function loadState( const modifiedValidators = loadValidators( migratedState, seedState, - stateBytes.subarray(validatorsRange.start, validatorsRange.end) + stateBytes.subarray(validatorsRange.start, validatorsRange.end), + seedValidatorsBytes ); // inactivityScores are rarely changed @@ -128,7 +130,7 @@ function loadInactivityScores( } /** - * As of Sep 2021, common validators of 2 mainnet states are rarely changed. However, the benchmark shows that + * As of Sep 2023, common validators of 2 mainnet states are rarely changed. However, the benchmark shows that * 10k modified validators is not an issue. (see packages/state-transition/test/perf/util/loadState/findModifiedValidators.test.ts) * * This method loads validators from bytes given a seed state so that they share the same base tree. This gives some benefits: @@ -159,7 +161,8 @@ function loadInactivityScores( function loadValidators( migratedState: BeaconStateAllForks, seedState: BeaconStateAllForks, - newValidatorsBytes: Uint8Array + newValidatorsBytes: Uint8Array, + seedStateValidatorsBytes?: Uint8Array ): number[] { const seedValidatorCount = seedState.validators.length; const newValidatorCount = Math.floor(newValidatorsBytes.length / VALIDATOR_BYTES_SIZE); @@ -167,7 +170,9 @@ function loadValidators( const minValidatorCount = Math.min(seedValidatorCount, newValidatorCount); // migrated state starts with the same validators to seed state migratedState.validators = seedState.validators.clone(); - const seedValidatorsBytes = seedState.validators.serialize(); + // 80% of validators serialization time comes from memory allocation + // seedStateValidatorsBytes is an optimization at beacon-node side to avoid memory allocation here + const seedValidatorsBytes = seedStateValidatorsBytes ?? seedState.validators.serialize(); const modifiedValidators: number[] = []; findModifiedValidators( isMoreValidator ? seedValidatorsBytes : seedValidatorsBytes.subarray(0, minValidatorCount * VALIDATOR_BYTES_SIZE), diff --git a/packages/state-transition/test/perf/util/serializeState.test.ts b/packages/state-transition/test/perf/util/serializeState.test.ts new file mode 100644 index 000000000000..5bd6c6b38e6a --- /dev/null +++ b/packages/state-transition/test/perf/util/serializeState.test.ts @@ -0,0 +1,122 @@ +import {itBench, setBenchOpts} from "@dapplion/benchmark"; +import {ssz} from "@lodestar/types"; +import {generatePerfTestCachedStateAltair} from "../util.js"; + +/** + * This shows different statistics between allocating memory once vs every time. + * Due to gc, the test is not consistent so skipping it for CI. + */ +describe.skip("serialize state and validators", function () { + this.timeout(0); + + setBenchOpts({ + // increasing this may have different statistics due to gc time + minMs: 60_000, + }); + const valicatorCount = 1_500_000; + const seedState = generatePerfTestCachedStateAltair({vc: 1_500_000, goBackOneSlot: false}); + + /** + * Allocate memory every time, on a Mac M1: + * - 700ms to 750ms + * - Used to see 2.8s + * Allocate memory once, may test multiple times but seems consistent: + * - 430ms to 480ms + */ + const stateType = ssz.altair.BeaconState; + const rootNode = seedState.node; + const stateBytes = new Uint8Array(stateType.tree_serializedSize(rootNode)); + const stateDataView = new DataView(stateBytes.buffer, stateBytes.byteOffset, stateBytes.byteLength); + itBench({ + id: `serialize state ${valicatorCount} validators, alloc once`, + fn: () => { + stateBytes.fill(0); + stateType.tree_serializeToBytes({uint8Array: stateBytes, dataView: stateDataView}, 0, rootNode); + }, + }); + + itBench({ + id: `serialize altair state ${valicatorCount} validators`, + fn: () => { + seedState.serialize(); + }, + }); + + /** + * Allocate memory once, this takes 450ms - 500ms on a Mac M1. + */ + const validatorsType = seedState.type.fields.validators; + const validatorsSize = validatorsType.tree_serializedSize(seedState.validators.node); + const validatorsBytes = new Uint8Array(validatorsSize); + const validatorsDataView = new DataView( + validatorsBytes.buffer, + validatorsBytes.byteOffset, + validatorsBytes.byteLength + ); + itBench({ + id: `serialize state validators ${valicatorCount} validators, alloc once`, + fn: () => { + validatorsBytes.fill(0); + validatorsType.tree_serializeToBytes( + {uint8Array: validatorsBytes, dataView: validatorsDataView}, + 0, + seedState.validators.node + ); + }, + }); + + /** + * Allocate memory every time, this takes 640ms to more than 1s on a Mac M1. + */ + itBench({ + id: `serialize state validators ${valicatorCount} validators`, + fn: () => { + seedState.validators.serialize(); + }, + }); + + /** + * Allocating once and populate validators nodes once, this takes 120ms - 150ms on a Mac M1, + * this is 3x faster than the previous approach. + */ + const NUMBER_2_POW_32 = 2 ** 32; + const output = new Uint8Array(121 * 1_500_000); + const dataView = new DataView(output.buffer, output.byteOffset, output.byteLength); + // this caches validators nodes which is what happen after we run a state transition + const validators = seedState.validators.getAllReadonlyValues(); + itBench({ + id: `serialize ${valicatorCount} validators manually`, + fn: () => { + let offset = 0; + for (const validator of validators) { + output.set(validator.pubkey, offset); + offset += 48; + output.set(validator.withdrawalCredentials, offset); + offset += 32; + const {effectiveBalance, activationEligibilityEpoch, activationEpoch, exitEpoch, withdrawableEpoch} = validator; + dataView.setUint32(offset, effectiveBalance & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, (effectiveBalance / NUMBER_2_POW_32) & 0xffffffff, true); + offset += 4; + output[offset] = validator.slashed ? 1 : 0; + offset += 1; + dataView.setUint32(offset, activationEligibilityEpoch & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, (activationEligibilityEpoch / NUMBER_2_POW_32) & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, activationEpoch & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, (activationEpoch / NUMBER_2_POW_32) & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, exitEpoch & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, (exitEpoch / NUMBER_2_POW_32) & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, withdrawableEpoch & 0xffffffff, true); + offset += 4; + dataView.setUint32(offset, (withdrawableEpoch / NUMBER_2_POW_32) & 0xffffffff, true); + offset += 4; + } + }, + }); +}); diff --git a/scripts/vitest/plugins/buildTargetPlugin.ts b/scripts/vitest/plugins/buildTargetPlugin.ts new file mode 100644 index 000000000000..40b6c0a9a833 --- /dev/null +++ b/scripts/vitest/plugins/buildTargetPlugin.ts @@ -0,0 +1,15 @@ +/* eslint-disable import/no-extraneous-dependencies */ +import {UserConfig, ConfigEnv, Plugin} from "vite"; + +export function buildTargetPlugin(target: string): Plugin { + return { + name: "buildTargetPlugin", + config(_config: UserConfig, _env: ConfigEnv) { + return { + esbuild: { + target, + }, + }; + }, + }; +} From ea4cdad801904773a050b4e238ba3683859aa35a Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 18 Jan 2024 14:29:16 -0800 Subject: [PATCH 46/70] fix: make light client events spec compliant (#6309) * fix: make eventstream spec compliant * fix: lints * fix: rely on version for light-client event serialization * fix: align lightClientUpdate event to existing pattern * fix: use top level fromJSON * fix: remove useless config * chore: cleanup unused event * Update test data to match spec examples * Determine fork based on attested header slot * Remove unrelated ssz types update --------- Co-authored-by: Nico Flaig --- packages/api/src/beacon/client/events.ts | 5 +- packages/api/src/beacon/client/index.ts | 2 +- packages/api/src/beacon/routes/events.ts | 61 +++++------------ packages/api/src/beacon/server/events.ts | 5 +- packages/api/src/beacon/server/index.ts | 2 +- .../beacon/genericServerTest/events.test.ts | 5 +- .../api/test/unit/beacon/oapiSpec.test.ts | 2 +- .../api/test/unit/beacon/testData/events.ts | 65 ++++++++++++++++--- .../src/chain/lightClient/index.ts | 17 +++-- packages/beacon-node/src/network/network.ts | 8 ++- packages/light-client/src/transport/rest.ts | 4 +- .../light-client/test/unit/sync.node.test.ts | 5 +- 12 files changed, 103 insertions(+), 78 deletions(-) diff --git a/packages/api/src/beacon/client/events.ts b/packages/api/src/beacon/client/events.ts index 4be5078735e4..1517d4bf3a56 100644 --- a/packages/api/src/beacon/client/events.ts +++ b/packages/api/src/beacon/client/events.ts @@ -1,4 +1,3 @@ -import {ChainForkConfig} from "@lodestar/config"; import {Api, BeaconEvent, routesData, getEventSerdes} from "../routes/events.js"; import {stringifyQuery, urlJoin} from "../../utils/client/format.js"; import {getEventSource} from "../../utils/client/eventSource.js"; @@ -7,8 +6,8 @@ import {HttpStatusCode} from "../../utils/client/httpStatusCode.js"; /** * REST HTTP client for events routes */ -export function getClient(config: ChainForkConfig, baseUrl: string): Api { - const eventSerdes = getEventSerdes(config); +export function getClient(baseUrl: string): Api { + const eventSerdes = getEventSerdes(); return { eventstream: async (topics, signal, onEvent) => { diff --git a/packages/api/src/beacon/client/index.ts b/packages/api/src/beacon/client/index.ts index 2dc0200dbda0..9fbe17bf337a 100644 --- a/packages/api/src/beacon/client/index.ts +++ b/packages/api/src/beacon/client/index.ts @@ -28,7 +28,7 @@ export function getClient(opts: HttpClientOptions, modules: ClientModules): Api beacon: beacon.getClient(config, httpClient), config: configApi.getClient(config, httpClient), debug: debug.getClient(config, httpClient), - events: events.getClient(config, httpClient.baseUrl), + events: events.getClient(httpClient.baseUrl), lightclient: lightclient.getClient(config, httpClient), lodestar: lodestar.getClient(config, httpClient), node: node.getClient(config, httpClient), diff --git a/packages/api/src/beacon/routes/events.ts b/packages/api/src/beacon/routes/events.ts index 105da89fced5..41a8e2e9cad9 100644 --- a/packages/api/src/beacon/routes/events.ts +++ b/packages/api/src/beacon/routes/events.ts @@ -1,7 +1,6 @@ import {ContainerType, ValueOf} from "@chainsafe/ssz"; import {Epoch, phase0, capella, Slot, ssz, StringType, RootHex, altair, UintNum64, allForks} from "@lodestar/types"; -import {ChainForkConfig} from "@lodestar/config"; -import {isForkExecution, ForkName} from "@lodestar/params"; +import {isForkExecution, ForkName, isForkLightClient} from "@lodestar/params"; import {RouteDef, TypeJson, WithVersion} from "../../utils/index.js"; import {HttpStatusCode} from "../../utils/client/httpStatusCode.js"; @@ -48,8 +47,6 @@ export enum EventType { lightClientOptimisticUpdate = "light_client_optimistic_update", /** New or better finality update available */ lightClientFinalityUpdate = "light_client_finality_update", - /** New or better light client update available */ - lightClientUpdate = "light_client_update", /** Payload attributes for block proposal */ payloadAttributes = "payload_attributes", /** The node has received a valid blobSidecar (from P2P or API) */ @@ -67,7 +64,6 @@ export const eventTypes: {[K in EventType]: K} = { [EventType.contributionAndProof]: EventType.contributionAndProof, [EventType.lightClientOptimisticUpdate]: EventType.lightClientOptimisticUpdate, [EventType.lightClientFinalityUpdate]: EventType.lightClientFinalityUpdate, - [EventType.lightClientUpdate]: EventType.lightClientUpdate, [EventType.payloadAttributes]: EventType.payloadAttributes, [EventType.blobSidecar]: EventType.blobSidecar, }; @@ -107,9 +103,8 @@ export type EventData = { executionOptimistic: boolean; }; [EventType.contributionAndProof]: altair.SignedContributionAndProof; - [EventType.lightClientOptimisticUpdate]: allForks.LightClientOptimisticUpdate; - [EventType.lightClientFinalityUpdate]: allForks.LightClientFinalityUpdate; - [EventType.lightClientUpdate]: allForks.LightClientUpdate; + [EventType.lightClientOptimisticUpdate]: {version: ForkName; data: allForks.LightClientOptimisticUpdate}; + [EventType.lightClientFinalityUpdate]: {version: ForkName; data: allForks.LightClientFinalityUpdate}; [EventType.payloadAttributes]: {version: ForkName; data: allForks.SSEPayloadAttributes}; [EventType.blobSidecar]: BlobSidecarSSE; }; @@ -146,9 +141,12 @@ export type ReqTypes = { // It doesn't make sense to define a getReqSerializers() here given the exotic argument of eventstream() // The request is very simple: (topics) => {query: {topics}}, and the test will ensure compatibility server - client -export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: TypeJson} { - const getLightClientTypeFromHeader = (data: allForks.LightClientHeader): allForks.AllForksLightClientSSZTypes => { - return config.getLightClientForkTypes(data.beacon.slot); +export function getTypeByEvent(): {[K in EventType]: TypeJson} { + const getLightClientType = (fork: ForkName): allForks.AllForksLightClientSSZTypes => { + if (!isForkLightClient(fork)) { + throw Error(`Invalid fork=${fork} for lightclient fork types`); + } + return ssz.allForksLightClient[fork]; }; return { @@ -208,45 +206,16 @@ export function getTypeByEvent(config: ChainForkConfig): {[K in EventType]: Type ), [EventType.blobSidecar]: blobSidecarSSE, - [EventType.lightClientOptimisticUpdate]: { - toJson: (data) => - getLightClientTypeFromHeader((data as unknown as allForks.LightClientOptimisticUpdate).attestedHeader)[ - "LightClientOptimisticUpdate" - ].toJson(data), - fromJson: (data) => - getLightClientTypeFromHeader( - // eslint-disable-next-line @typescript-eslint/naming-convention - (data as {attested_header: allForks.LightClientHeader}).attested_header - )["LightClientOptimisticUpdate"].fromJson(data), - }, - [EventType.lightClientFinalityUpdate]: { - toJson: (data) => - getLightClientTypeFromHeader((data as unknown as allForks.LightClientFinalityUpdate).attestedHeader)[ - "LightClientFinalityUpdate" - ].toJson(data), - fromJson: (data) => - getLightClientTypeFromHeader( - // eslint-disable-next-line @typescript-eslint/naming-convention - (data as {attested_header: allForks.LightClientHeader}).attested_header - )["LightClientFinalityUpdate"].fromJson(data), - }, - [EventType.lightClientUpdate]: { - toJson: (data) => - getLightClientTypeFromHeader((data as unknown as allForks.LightClientUpdate).attestedHeader)[ - "LightClientUpdate" - ].toJson(data), - fromJson: (data) => - getLightClientTypeFromHeader( - // eslint-disable-next-line @typescript-eslint/naming-convention - (data as {attested_header: allForks.LightClientHeader}).attested_header - )["LightClientUpdate"].fromJson(data), - }, + [EventType.lightClientOptimisticUpdate]: WithVersion( + (fork) => getLightClientType(fork).LightClientOptimisticUpdate + ), + [EventType.lightClientFinalityUpdate]: WithVersion((fork) => getLightClientType(fork).LightClientFinalityUpdate), }; } // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -export function getEventSerdes(config: ChainForkConfig) { - const typeByEvent = getTypeByEvent(config); +export function getEventSerdes() { + const typeByEvent = getTypeByEvent(); return { toJson: (event: BeaconEvent): unknown => { diff --git a/packages/api/src/beacon/server/events.ts b/packages/api/src/beacon/server/events.ts index 834b6b67fca4..6d780ed1bf70 100644 --- a/packages/api/src/beacon/server/events.ts +++ b/packages/api/src/beacon/server/events.ts @@ -1,10 +1,9 @@ -import {ChainForkConfig} from "@lodestar/config"; import {Api, ReqTypes, routesData, getEventSerdes, eventTypes} from "../routes/events.js"; import {ApiError, ServerRoutes} from "../../utils/server/index.js"; import {ServerApi} from "../../interfaces.js"; -export function getRoutes(config: ChainForkConfig, api: ServerApi): ServerRoutes { - const eventSerdes = getEventSerdes(config); +export function getRoutes(api: ServerApi): ServerRoutes { + const eventSerdes = getEventSerdes(); return { // Non-JSON route. Server Sent Events (SSE) diff --git a/packages/api/src/beacon/server/index.ts b/packages/api/src/beacon/server/index.ts index b935a5432a3c..da77dfad32af 100644 --- a/packages/api/src/beacon/server/index.ts +++ b/packages/api/src/beacon/server/index.ts @@ -37,7 +37,7 @@ export function registerRoutes( beacon: () => beacon.getRoutes(config, api.beacon), config: () => configApi.getRoutes(config, api.config), debug: () => debug.getRoutes(config, api.debug), - events: () => events.getRoutes(config, api.events), + events: () => events.getRoutes(api.events), lightclient: () => lightclient.getRoutes(config, api.lightclient), lodestar: () => lodestar.getRoutes(config, api.lodestar), node: () => node.getRoutes(config, api.node), diff --git a/packages/api/test/unit/beacon/genericServerTest/events.test.ts b/packages/api/test/unit/beacon/genericServerTest/events.test.ts index 48ff8ad3d157..3e1c02396710 100644 --- a/packages/api/test/unit/beacon/genericServerTest/events.test.ts +++ b/packages/api/test/unit/beacon/genericServerTest/events.test.ts @@ -1,6 +1,5 @@ import {describe, it, expect, beforeEach, afterEach} from "vitest"; import {sleep} from "@lodestar/utils"; -import {config} from "@lodestar/config/default"; import {Api, routesData, EventType, BeaconEvent} from "../../../../src/beacon/routes/events.js"; import {getClient} from "../../../../src/beacon/client/events.js"; import {getRoutes} from "../../../../src/beacon/server/events.js"; @@ -11,7 +10,7 @@ import {eventTestData} from "../testData/events.js"; describe("beacon / events", () => { const {baseUrl, server} = getTestServer(); const mockApi = getMockApi(routesData); - for (const route of Object.values(getRoutes(config, mockApi))) { + for (const route of Object.values(getRoutes(mockApi))) { registerRoute(server, route); } @@ -53,7 +52,7 @@ describe("beacon / events", () => { }); // Capture them on the client - const client = getClient(config, baseUrl); + const client = getClient(baseUrl); void client.eventstream(topicsToRequest, controller.signal, (event) => { eventsReceived.push(event); if (eventsReceived.length >= eventsToSend.length) resolve(); diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 1a300eba6f36..15a10bfeb6f7 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -204,7 +204,7 @@ describe("eventstream event data", () => { } }); - const eventSerdes = routes.events.getEventSerdes(config); + const eventSerdes = routes.events.getEventSerdes(); const knownTopics = new Set(Object.values(routes.events.eventTypes)); for (const [topic, {value}] of Object.entries(eventstreamExamples ?? {}).filter( diff --git a/packages/api/test/unit/beacon/testData/events.ts b/packages/api/test/unit/beacon/testData/events.ts index af33f4a2b011..7bfac9a59a88 100644 --- a/packages/api/test/unit/beacon/testData/events.ts +++ b/packages/api/test/unit/beacon/testData/events.ts @@ -4,7 +4,6 @@ import {Api, EventData, EventType, blobSidecarSSE} from "../../../../src/beacon/ import {GenericServerTestCases} from "../../../utils/genericServerTest.js"; const abortController = new AbortController(); -const root = new Uint8Array(32); /* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/naming-convention */ @@ -93,18 +92,64 @@ export const eventTestData: EventData = { "0xac118511474a94f857300b315c50585c32a713e4452e26a6bb98cdb619936370f126ed3b6bb64469259ee92e69791d9e12d324ce6fd90081680ce72f39d85d50b0ff977260a8667465e613362c6d6e6e745e1f9323ec1d6f16041c4e358839ac", }), [EventType.lightClientOptimisticUpdate]: { - syncAggregate: ssz.altair.SyncAggregate.defaultValue(), - attestedHeader: ssz.altair.LightClientHeader.defaultValue(), - signatureSlot: ssz.Slot.defaultValue(), + version: ForkName.altair, + data: ssz.altair.LightClientOptimisticUpdate.fromJson({ + attested_header: { + beacon: { + slot: "1", + proposer_index: "1", + parent_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + state_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + body_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + }, + }, + sync_aggregate: { + sync_committee_bits: + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffbffffffffffffffffffffbffffffffffffff", + sync_committee_signature: + "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + }, + signature_slot: "1", + }), }, [EventType.lightClientFinalityUpdate]: { - attestedHeader: ssz.altair.LightClientHeader.defaultValue(), - finalizedHeader: ssz.altair.LightClientHeader.defaultValue(), - finalityBranch: [root], - syncAggregate: ssz.altair.SyncAggregate.defaultValue(), - signatureSlot: ssz.Slot.defaultValue(), + version: ForkName.altair, + data: ssz.altair.LightClientFinalityUpdate.fromJson({ + attested_header: { + beacon: { + slot: "1", + proposer_index: "1", + parent_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + state_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + body_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + }, + }, + finalized_header: { + beacon: { + slot: "1", + proposer_index: "1", + parent_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + state_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + body_root: "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + }, + }, + finality_branch: [ + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + "0xcf8e0d4e9587369b2301d0790347320302cc0943d5a1884560367e8208d920f2", + ], + sync_aggregate: { + sync_committee_bits: + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffbffffffffffffffffffffbffffffffffffff", + sync_committee_signature: + "0x1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505cc411d61252fb6cb3fa0017b679f8bb2305b26a285fa2737f175668d0dff91cc1b66ac1fb663c9bc59509846d6ec05345bd908eda73e670af888da41af171505", + }, + signature_slot: "1", + }), }, - [EventType.lightClientUpdate]: ssz.altair.LightClientUpdate.defaultValue(), [EventType.payloadAttributes]: { version: ForkName.bellatrix, data: ssz.bellatrix.SSEPayloadAttributes.defaultValue(), diff --git a/packages/beacon-node/src/chain/lightClient/index.ts b/packages/beacon-node/src/chain/lightClient/index.ts index 1a09652dc233..75d094036f2d 100644 --- a/packages/beacon-node/src/chain/lightClient/index.ts +++ b/packages/beacon-node/src/chain/lightClient/index.ts @@ -494,9 +494,15 @@ export class LightClientServer { return; } + // Fork of LightClientOptimisticUpdate and LightClientFinalityUpdate is based off on attested header's fork + const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); + // Emit update // Note: Always emit optimistic update even if we have emitted one with higher or equal attested_header.slot - this.emitter.emit(routes.events.EventType.lightClientOptimisticUpdate, headerUpdate); + this.emitter.emit(routes.events.EventType.lightClientOptimisticUpdate, { + version: attestedFork, + data: headerUpdate, + }); // Persist latest best update for getLatestHeadUpdate() // TODO: Once SyncAggregate are constructed from P2P too, count bits to decide "best" @@ -515,8 +521,6 @@ export class LightClientServer { finalizedHeader.beacon.slot > this.finalized.finalizedHeader.beacon.slot || syncAggregateParticipation > sumBits(this.finalized.syncAggregate.syncCommitteeBits)) ) { - // Fork of LightClientFinalityUpdate is based off on attested header's fork - const attestedFork = this.config.getForkName(attestedHeader.beacon.slot); if (this.config.getForkName(finalizedHeader.beacon.slot) !== attestedFork) { finalizedHeader = upgradeLightClientHeader(this.config, attestedFork, finalizedHeader); } @@ -529,8 +533,11 @@ export class LightClientServer { }; this.metrics?.lightclientServer.onSyncAggregate.inc({event: "update_latest_finalized_update"}); - // Note: Ignores gossip rule to always emit finaly_update with higher finalized_header.slot, for simplicity - this.emitter.emit(routes.events.EventType.lightClientFinalityUpdate, this.finalized); + // Note: Ignores gossip rule to always emit finality_update with higher finalized_header.slot, for simplicity + this.emitter.emit(routes.events.EventType.lightClientFinalityUpdate, { + version: attestedFork, + data: this.finalized, + }); } } diff --git a/packages/beacon-node/src/network/network.ts b/packages/beacon-node/src/network/network.ts index 609ee2d44ba1..f4b57fe0c658 100644 --- a/packages/beacon-node/src/network/network.ts +++ b/packages/beacon-node/src/network/network.ts @@ -105,8 +105,12 @@ export class Network implements INetwork { this.events.on(NetworkEvent.peerConnected, this.onPeerConnected); this.events.on(NetworkEvent.peerDisconnected, this.onPeerDisconnected); this.chain.emitter.on(routes.events.EventType.head, this.onHead); - this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, this.onLightClientFinalityUpdate); - this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, this.onLightClientOptimisticUpdate); + this.chain.emitter.on(routes.events.EventType.lightClientFinalityUpdate, ({data}) => + this.onLightClientFinalityUpdate(data) + ); + this.chain.emitter.on(routes.events.EventType.lightClientOptimisticUpdate, ({data}) => + this.onLightClientOptimisticUpdate(data) + ); } static async init({ diff --git a/packages/light-client/src/transport/rest.ts b/packages/light-client/src/transport/rest.ts index 765e55d7f5c5..ebbd8e52f691 100644 --- a/packages/light-client/src/transport/rest.ts +++ b/packages/light-client/src/transport/rest.ts @@ -80,11 +80,11 @@ export class LightClientRestTransport extends (EventEmitter as {new (): RestEven (event) => { switch (event.type) { case routes.events.EventType.lightClientOptimisticUpdate: - this.eventEmitter.emit(routes.events.EventType.lightClientOptimisticUpdate, event.message); + this.eventEmitter.emit(routes.events.EventType.lightClientOptimisticUpdate, event.message.data); break; case routes.events.EventType.lightClientFinalityUpdate: - this.eventEmitter.emit(routes.events.EventType.lightClientFinalityUpdate, event.message); + this.eventEmitter.emit(routes.events.EventType.lightClientFinalityUpdate, event.message.data); break; } } diff --git a/packages/light-client/test/unit/sync.node.test.ts b/packages/light-client/test/unit/sync.node.test.ts index 168bfeceb5f9..75073c80070b 100644 --- a/packages/light-client/test/unit/sync.node.test.ts +++ b/packages/light-client/test/unit/sync.node.test.ts @@ -155,7 +155,10 @@ describe("sync", () => { }; lightclientServerApi.latestHeadUpdate = headUpdate; - eventsServerApi.emit({type: routes.events.EventType.lightClientOptimisticUpdate, message: headUpdate}); + eventsServerApi.emit({ + type: routes.events.EventType.lightClientOptimisticUpdate, + message: {version: config.getForkName(headUpdate.attestedHeader.beacon.slot), data: headUpdate}, + }); testLogger.debug("Emitted EventType.lightClientOptimisticUpdate", {slot}); } }); From 2db7120f3534faf5c023954f4065912dd0c2691f Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Fri, 19 Jan 2024 14:57:15 +0700 Subject: [PATCH 47/70] feat: forkchoice filter change (#6288) * fix: cache justifiedTotalActiveBalanceByIncrement and implement getProposerScore() * feat: confirmation rule prerequisite for forkchoice * chore: no need to change unrealizedJustified in ForkChoiceStore * fix: beacon-node perf test * fix: spec test v1.4.0-beta.6 * fix: ignore whisk for now --- .../opPools/aggregatedAttestationPool.test.ts | 6 ++++ .../test/spec/presets/ssz_static.test.ts | 9 ++++-- .../test/spec/specTestVersioning.ts | 2 +- .../fork-choice/src/forkChoice/forkChoice.ts | 32 +++---------------- .../fork-choice/src/forkChoice/interface.ts | 4 +++ packages/fork-choice/src/forkChoice/store.ts | 22 +++++++++---- .../fork-choice/src/protoArray/protoArray.ts | 16 ++++------ .../fork-choice/test/perf/forkChoice/util.ts | 2 ++ .../perf/protoArray/computeDeltas.test.ts | 10 ------ .../test/unit/forkChoice/forkChoice.test.ts | 1 + 10 files changed, 48 insertions(+), 56 deletions(-) diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index 309a5c29a6b0..d2317de42c5e 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -103,11 +103,17 @@ describe("getAttestationsForBlock", () => { ); } + let totalBalance = 0; + for (let i = 0; i < originalState.epochCtx.effectiveBalanceIncrements.length; i++) { + totalBalance += originalState.epochCtx.effectiveBalanceIncrements[i]; + } + const fcStore: IForkChoiceStore = { currentSlot: originalState.slot, justified: { checkpoint: {...justifiedCheckpoint, rootHex: toHexString(justifiedCheckpoint.root)}, balances: originalState.epochCtx.effectiveBalanceIncrements, + totalBalance, }, unrealizedJustified: { checkpoint: {...justifiedCheckpoint, rootHex: toHexString(justifiedCheckpoint.root)}, diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index a23a7d388f55..bcab25acde4c 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -31,8 +31,12 @@ type Types = Record>; // const sszStatic = - (skippedTypes?: string[]) => + (skippedFork: string, skippedTypes?: string[]) => (fork: ForkName, typeName: string, testSuite: string, testSuiteDirpath: string): void => { + if (fork === skippedFork) { + return; + } + // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts if (skippedTypes?.includes(typeName)) { return; @@ -72,6 +76,7 @@ specTestIterator(path.join(ethereumConsensusSpecsTests.outputDir, "tests", ACTIV // eslint-disable-next-line @typescript-eslint/naming-convention ssz_static: { type: RunnerType.custom, - fn: sszStatic(), + // starting from v1.4.0-beta.6, there is "whisk" fork in ssz_static tests but we ignore them + fn: sszStatic("whisk"), }, }); diff --git a/packages/beacon-node/test/spec/specTestVersioning.ts b/packages/beacon-node/test/spec/specTestVersioning.ts index c8a65357bf02..37167c9bd5a1 100644 --- a/packages/beacon-node/test/spec/specTestVersioning.ts +++ b/packages/beacon-node/test/spec/specTestVersioning.ts @@ -15,7 +15,7 @@ import {DownloadTestsOptions} from "@lodestar/spec-test-util/downloadTests"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); export const ethereumConsensusSpecsTests: DownloadTestsOptions = { - specVersion: "v1.4.0-beta.5", + specVersion: "v1.4.0-beta.6", // Target directory is the host package root: 'packages/*/spec-tests' outputDir: path.join(__dirname, "../../spec-tests"), specTestsRepoUrl: "https://github.com/ethereum/consensus-spec-tests", diff --git a/packages/fork-choice/src/forkChoice/forkChoice.ts b/packages/fork-choice/src/forkChoice/forkChoice.ts index 32732e45fb6e..374bc65542ee 100644 --- a/packages/fork-choice/src/forkChoice/forkChoice.ts +++ b/packages/fork-choice/src/forkChoice/forkChoice.ts @@ -201,7 +201,7 @@ export class ForkChoice implements IForkChoice { if (this.opts?.proposerBoostEnabled && this.proposerBoostRoot) { const proposerBoostScore = this.justifiedProposerBoostScore ?? - computeProposerBoostScoreFromBalances(this.fcStore.justified.balances, { + getProposerScore(this.fcStore.justified.totalBalance, { slotsPerEpoch: SLOTS_PER_EPOCH, proposerScoreBoost: this.config.PROPOSER_SCORE_BOOST, }); @@ -1262,32 +1262,10 @@ export function assertValidTerminalPowBlock( } } -function computeProposerBoostScore( - { - justifiedTotalActiveBalanceByIncrement, - justifiedActiveValidators, - }: {justifiedTotalActiveBalanceByIncrement: number; justifiedActiveValidators: number}, +export function getProposerScore( + justifiedTotalActiveBalanceByIncrement: number, config: {slotsPerEpoch: number; proposerScoreBoost: number} ): number { - const avgBalanceByIncrement = Math.floor(justifiedTotalActiveBalanceByIncrement / justifiedActiveValidators); - const committeeSize = Math.floor(justifiedActiveValidators / config.slotsPerEpoch); - const committeeWeight = committeeSize * avgBalanceByIncrement; - const proposerScore = Math.floor((committeeWeight * config.proposerScoreBoost) / 100); - return proposerScore; -} - -export function computeProposerBoostScoreFromBalances( - justifiedBalances: EffectiveBalanceIncrements, - config: {slotsPerEpoch: number; proposerScoreBoost: number} -): number { - let justifiedTotalActiveBalanceByIncrement = 0, - justifiedActiveValidators = 0; - for (let i = 0; i < justifiedBalances.length; i++) { - if (justifiedBalances[i] > 0) { - justifiedActiveValidators += 1; - // justified balances here are by increment - justifiedTotalActiveBalanceByIncrement += justifiedBalances[i]; - } - } - return computeProposerBoostScore({justifiedTotalActiveBalanceByIncrement, justifiedActiveValidators}, config); + const committeeWeight = Math.floor(justifiedTotalActiveBalanceByIncrement / config.slotsPerEpoch); + return Math.floor((committeeWeight * config.proposerScoreBoost) / 100); } diff --git a/packages/fork-choice/src/forkChoice/interface.ts b/packages/fork-choice/src/forkChoice/interface.ts index 6d26f17d493b..fffbc3e4007f 100644 --- a/packages/fork-choice/src/forkChoice/interface.ts +++ b/packages/fork-choice/src/forkChoice/interface.ts @@ -19,6 +19,10 @@ export type CheckpointHexWithBalance = { balances: EffectiveBalanceIncrements; }; +export type CheckpointHexWithTotalBalance = CheckpointHexWithBalance & { + totalBalance: number; +}; + export enum EpochDifference { current = 0, previous = 1, diff --git a/packages/fork-choice/src/forkChoice/store.ts b/packages/fork-choice/src/forkChoice/store.ts index da831550a584..faf700241fa8 100644 --- a/packages/fork-choice/src/forkChoice/store.ts +++ b/packages/fork-choice/src/forkChoice/store.ts @@ -1,7 +1,7 @@ import {toHexString} from "@chainsafe/ssz"; import {EffectiveBalanceIncrements, CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {phase0, Slot, RootHex, ValidatorIndex} from "@lodestar/types"; -import {CheckpointHexWithBalance} from "./interface.js"; +import {CheckpointHexWithTotalBalance, CheckpointHexWithBalance} from "./interface.js"; /** * Stores checkpoints in a hybrid format: @@ -37,7 +37,8 @@ export type JustifiedBalancesGetter = ( */ export interface IForkChoiceStore { currentSlot: Slot; - justified: CheckpointHexWithBalance; + get justified(): CheckpointHexWithTotalBalance; + set justified(justified: CheckpointHexWithBalance); unrealizedJustified: CheckpointHexWithBalance; finalizedCheckpoint: CheckpointWithHex; unrealizedFinalizedCheckpoint: CheckpointWithHex; @@ -49,7 +50,7 @@ export interface IForkChoiceStore { * IForkChoiceStore implementer which emits forkChoice events on updated justified and finalized checkpoints. */ export class ForkChoiceStore implements IForkChoiceStore { - private _justified: CheckpointHexWithBalance; + private _justified: CheckpointHexWithTotalBalance; unrealizedJustified: CheckpointHexWithBalance; private _finalizedCheckpoint: CheckpointWithHex; unrealizedFinalizedCheckpoint: CheckpointWithHex; @@ -66,9 +67,10 @@ export class ForkChoiceStore implements IForkChoiceStore { onFinalized: (cp: CheckpointWithHex) => void; } ) { - const justified: CheckpointHexWithBalance = { + const justified = { checkpoint: toCheckpointWithHex(justifiedCheckpoint), balances: justifiedBalances, + totalBalance: computeTotalBalance(justifiedBalances), }; this._justified = justified; this.unrealizedJustified = justified; @@ -76,11 +78,11 @@ export class ForkChoiceStore implements IForkChoiceStore { this.unrealizedFinalizedCheckpoint = this._finalizedCheckpoint; } - get justified(): CheckpointHexWithBalance { + get justified(): CheckpointHexWithTotalBalance { return this._justified; } set justified(justified: CheckpointHexWithBalance) { - this._justified = justified; + this._justified = {...justified, totalBalance: computeTotalBalance(justified.balances)}; this.events?.onJustified(justified.checkpoint); } @@ -108,3 +110,11 @@ export function toCheckpointWithHex(checkpoint: phase0.Checkpoint): CheckpointWi export function equalCheckpointWithHex(a: CheckpointWithHex, b: CheckpointWithHex): boolean { return a.epoch === b.epoch && a.rootHex === b.rootHex; } + +export function computeTotalBalance(balances: EffectiveBalanceIncrements): number { + let totalBalance = 0; + for (let i = 0; i < balances.length; i++) { + totalBalance += balances[i]; + } + return totalBalance; +} diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index b2c030e17540..62f50b03771c 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -723,22 +723,18 @@ export class ProtoArray { return false; } const currentEpoch = computeEpochAtSlot(currentSlot); - const previousEpoch = currentEpoch - 1; // If block is from a previous epoch, filter using unrealized justification & finalization information // If block is from the current epoch, filter using the head state's justification & finalization information const isFromPrevEpoch = computeEpochAtSlot(node.slot) < currentEpoch; const votingSourceEpoch = isFromPrevEpoch ? node.unrealizedJustifiedEpoch : node.justifiedEpoch; - // The voting source should be at the same height as the store's justified checkpoint - let correctJustified = votingSourceEpoch === this.justifiedEpoch || this.justifiedEpoch === 0; - - // If this is a pulled-up block from the current epoch, also check that - // the unrealized justification is higher than the store's justified checkpoint, and - // the voting source is not more than two epochs ago. - if (!correctJustified && currentEpoch > GENESIS_EPOCH && this.justifiedEpoch === previousEpoch) { - correctJustified = node.unrealizedJustifiedEpoch >= previousEpoch && votingSourceEpoch + 2 >= currentEpoch; - } + // The voting source should be at the same height as the store's justified checkpoint or + // not more than two epochs ago + const correctJustified = + this.justifiedEpoch === GENESIS_EPOCH || + votingSourceEpoch === this.justifiedEpoch || + votingSourceEpoch + 2 >= currentEpoch; const correctFinalized = this.finalizedEpoch === 0 || this.isFinalizedRootOrDescendant(node); return correctJustified && correctFinalized; diff --git a/packages/fork-choice/test/perf/forkChoice/util.ts b/packages/fork-choice/test/perf/forkChoice/util.ts index 4669b03db6d6..1ad97d5b6c54 100644 --- a/packages/fork-choice/test/perf/forkChoice/util.ts +++ b/packages/fork-choice/test/perf/forkChoice/util.ts @@ -1,6 +1,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; import {ExecutionStatus, ForkChoice, IForkChoiceStore, ProtoBlock, ProtoArray} from "../../../src/index.js"; +import {computeTotalBalance} from "../../../src/forkChoice/store.js"; const genesisSlot = 0; const genesisEpoch = 0; @@ -39,6 +40,7 @@ export function initializeForkChoice(opts: Opts): ForkChoice { justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisRoot), rootHex: genesisRoot}, balances, + totalBalance: computeTotalBalance(balances), }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(genesisRoot), rootHex: genesisRoot}, diff --git a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts index 1843ef91c22a..9b51f640d949 100644 --- a/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/perf/protoArray/computeDeltas.test.ts @@ -2,7 +2,6 @@ import {itBench, setBenchOpts} from "@dapplion/benchmark"; import {EffectiveBalanceIncrements, getEffectiveBalanceIncrementsZeroed} from "@lodestar/state-transition"; import {VoteTracker} from "../../../src/protoArray/interface.js"; import {computeDeltas} from "../../../src/protoArray/computeDeltas.js"; -import {computeProposerBoostScoreFromBalances} from "../../../src/forkChoice/forkChoice.js"; describe("computeDeltas", () => { let oldBalances: EffectiveBalanceIncrements; @@ -51,13 +50,4 @@ describe("computeDeltas", () => { }); } } - - for (const numValidator of numValidators) { - itBench({ - id: `computeProposerBoostScoreFromBalances ${numValidator} validators`, - fn: () => { - computeProposerBoostScoreFromBalances(newBalances, {slotsPerEpoch: 32, proposerScoreBoost: 70}); - }, - }); - } }); diff --git a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts index fe11532dbb6f..93aa28f8f2e5 100644 --- a/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts +++ b/packages/fork-choice/test/unit/forkChoice/forkChoice.test.ts @@ -51,6 +51,7 @@ describe("Forkchoice", function () { justified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, balances: new Uint8Array([32]), + totalBalance: 32, }, unrealizedJustified: { checkpoint: {epoch: genesisEpoch, root: fromHexString(finalizedRoot), rootHex: finalizedRoot}, From 3215bdd75d298efb60a7c107b40a62cdbabb2ba9 Mon Sep 17 00:00:00 2001 From: g11tech Date: Fri, 19 Jan 2024 21:18:31 +0530 Subject: [PATCH 48/70] feat: schedule deneb fork on testnets (#6223) --- packages/config/src/chainConfig/networks/holesky.ts | 3 +++ packages/config/src/chainConfig/networks/sepolia.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/config/src/chainConfig/networks/holesky.ts b/packages/config/src/chainConfig/networks/holesky.ts index 2e59f4fcb5a6..e255369ccbaa 100644 --- a/packages/config/src/chainConfig/networks/holesky.ts +++ b/packages/config/src/chainConfig/networks/holesky.ts @@ -31,6 +31,9 @@ export const holeskyChainConfig: ChainConfig = { // Capella CAPELLA_FORK_VERSION: b("0x04017000"), CAPELLA_FORK_EPOCH: 256, + // Deneb + DENEB_FORK_VERSION: b("0x05017000"), + DENEB_FORK_EPOCH: 29696, // # 28,000,000,000 Gwei to ensure quicker ejection EJECTION_BALANCE: 28000000000, diff --git a/packages/config/src/chainConfig/networks/sepolia.ts b/packages/config/src/chainConfig/networks/sepolia.ts index a54a8d093db1..c81fda37b4c6 100644 --- a/packages/config/src/chainConfig/networks/sepolia.ts +++ b/packages/config/src/chainConfig/networks/sepolia.ts @@ -30,6 +30,9 @@ export const sepoliaChainConfig: ChainConfig = { // Capella CAPELLA_FORK_VERSION: b("0x90000072"), CAPELLA_FORK_EPOCH: 56832, + // Deneb + DENEB_FORK_VERSION: b("0x90000073"), + DENEB_FORK_EPOCH: 132608, // Deposit contract // --------------------------------------------------------------- From c423687aa95c428fc3c781dc92129a8b3074babb Mon Sep 17 00:00:00 2001 From: tuyennhv Date: Sat, 20 Jan 2024 02:31:41 +0700 Subject: [PATCH 49/70] feat: log agent version when client is not known (#6314) * feat: log agent version when client is not known * chore: add test case for getKnownClientFromAgentVersion --- packages/beacon-node/src/network/peers/client.ts | 11 +++++++++-- packages/beacon-node/src/network/peers/peerManager.ts | 4 ++-- packages/beacon-node/src/network/peers/peersData.ts | 4 ++-- .../src/network/reqresp/ReqRespBeaconNode.ts | 3 ++- .../test/unit/network/peers/client.test.ts | 11 ++++++++--- 5 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/beacon-node/src/network/peers/client.ts b/packages/beacon-node/src/network/peers/client.ts index d75880f07a58..4b84233f6833 100644 --- a/packages/beacon-node/src/network/peers/client.ts +++ b/packages/beacon-node/src/network/peers/client.ts @@ -7,7 +7,13 @@ export enum ClientKind { Unknown = "Unknown", } -export function clientFromAgentVersion(agentVersion: string): ClientKind { +/** + * Get known client from agent version. + * If client is not known, don't return ClientKind.Unknown here. + * For metrics it'll have fallback logic to use ClientKind.Unknown + * For logs, we want to print out agentVersion instead for debugging purposes. + */ +export function getKnownClientFromAgentVersion(agentVersion: string): ClientKind | null { const slashIndex = agentVersion.indexOf("/"); const agent = slashIndex >= 0 ? agentVersion.slice(0, slashIndex) : agentVersion; const agentLC = agent.toLowerCase(); @@ -16,5 +22,6 @@ export function clientFromAgentVersion(agentVersion: string): ClientKind { if (agentLC === "prysm") return ClientKind.Prysm; if (agentLC === "nimbus") return ClientKind.Nimbus; if (agentLC === "lodestar" || agentLC === "js-libp2p") return ClientKind.Lodestar; - return ClientKind.Unknown; + + return null; } diff --git a/packages/beacon-node/src/network/peers/peerManager.ts b/packages/beacon-node/src/network/peers/peerManager.ts index 5100987566e2..94af8f06ea03 100644 --- a/packages/beacon-node/src/network/peers/peerManager.ts +++ b/packages/beacon-node/src/network/peers/peerManager.ts @@ -19,7 +19,7 @@ import {NetworkCoreMetrics} from "../core/metrics.js"; import {LodestarDiscv5Opts} from "../discv5/types.js"; import {PeerDiscovery, SubnetDiscvQueryMs} from "./discover.js"; import {PeersData, PeerData} from "./peersData.js"; -import {clientFromAgentVersion, ClientKind} from "./client.js"; +import {getKnownClientFromAgentVersion, ClientKind} from "./client.js"; import { getConnectedPeerIds, hasSomeConnectedPeer, @@ -615,7 +615,7 @@ export class PeerManager { if (agentVersionBytes) { const agentVersion = new TextDecoder().decode(agentVersionBytes) || "N/A"; peerData.agentVersion = agentVersion; - peerData.agentClient = clientFromAgentVersion(agentVersion); + peerData.agentClient = getKnownClientFromAgentVersion(agentVersion); } }, {retries: 3, retryDelay: 1000} diff --git a/packages/beacon-node/src/network/peers/peersData.ts b/packages/beacon-node/src/network/peers/peersData.ts index 5487a9a44159..4f96548c73e4 100644 --- a/packages/beacon-node/src/network/peers/peersData.ts +++ b/packages/beacon-node/src/network/peers/peersData.ts @@ -38,8 +38,8 @@ export class PeersData { return this.connectedPeers.get(peerIdStr)?.agentVersion ?? "NA"; } - getPeerKind(peerIdStr: string): ClientKind { - return this.connectedPeers.get(peerIdStr)?.agentClient ?? ClientKind.Unknown; + getPeerKind(peerIdStr: string): ClientKind | null { + return this.connectedPeers.get(peerIdStr)?.agentClient ?? null; } getEncodingPreference(peerIdStr: string): Encoding | null { diff --git a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts index 962962ab8842..5aea63fb9fe3 100644 --- a/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts +++ b/packages/beacon-node/src/network/reqresp/ReqRespBeaconNode.ts @@ -88,7 +88,8 @@ export class ReqRespBeaconNode extends ReqResp { metrics?.reqResp.rateLimitErrors.inc({method}); }, getPeerLogMetadata(peerId) { - return peersData.getPeerKind(peerId); + // this logs the whole agent version for unknown client which is good for debugging + return peersData.getPeerKind(peerId) ?? peersData.getAgentVersion(peerId); }, } ); diff --git a/packages/beacon-node/test/unit/network/peers/client.test.ts b/packages/beacon-node/test/unit/network/peers/client.test.ts index 75ab4cbfb826..a179d42157cd 100644 --- a/packages/beacon-node/test/unit/network/peers/client.test.ts +++ b/packages/beacon-node/test/unit/network/peers/client.test.ts @@ -1,8 +1,8 @@ import {describe, it, expect} from "vitest"; -import {clientFromAgentVersion, ClientKind} from "../../../../src/network/peers/client.js"; +import {getKnownClientFromAgentVersion, ClientKind} from "../../../../src/network/peers/client.js"; describe("clientFromAgentVersion", () => { - const testCases: {name: string; agentVersion: string; client: ClientKind}[] = [ + const testCases: {name: string; agentVersion: string; client: ClientKind | null}[] = [ { name: "lighthouse", agentVersion: "Lighthouse/v2.0.1-fff01b2/x86_64-linux", @@ -28,11 +28,16 @@ describe("clientFromAgentVersion", () => { agentVersion: "js-libp2p/0.32.4", client: ClientKind.Lodestar, }, + { + name: "unknown client", + agentVersion: "strange-client-agent-version", + client: null, + }, ]; for (const {name, agentVersion, client} of testCases) { it(name, () => { - expect(clientFromAgentVersion(agentVersion)).toBe(client); + expect(getKnownClientFromAgentVersion(agentVersion)).toBe(client); }); } }); From 0f375fa87213216f8e767eef5a201f19862a6408 Mon Sep 17 00:00:00 2001 From: g11tech Date: Sat, 20 Jan 2024 18:35:36 +0530 Subject: [PATCH 50/70] feat: improve batch validator exit UX (#6327) --- .../cli/src/cmds/validator/voluntaryExit.ts | 90 ++++++++++++------- packages/cli/src/util/errors.ts | 9 ++ 2 files changed, 69 insertions(+), 30 deletions(-) diff --git a/packages/cli/src/cmds/validator/voluntaryExit.ts b/packages/cli/src/cmds/validator/voluntaryExit.ts index 770843c6445b..c3c0360a8264 100644 --- a/packages/cli/src/cmds/validator/voluntaryExit.ts +++ b/packages/cli/src/cmds/validator/voluntaryExit.ts @@ -6,12 +6,12 @@ import { computeStartSlotAtEpoch, getCurrentSlot, } from "@lodestar/state-transition"; -import {createBeaconConfig} from "@lodestar/config"; -import {phase0, ssz} from "@lodestar/types"; +import {createBeaconConfig, BeaconConfig} from "@lodestar/config"; +import {phase0, ssz, ValidatorIndex, Epoch} from "@lodestar/types"; import {toHex} from "@lodestar/utils"; import {externalSignerPostSignature, SignableMessageType, Signer, SignerType} from "@lodestar/validator"; import {Api, ApiError, getClient} from "@lodestar/api"; -import {CliCommand, ensure0xPrefix, YargsError} from "../../util/index.js"; +import {CliCommand, ensure0xPrefix, YargsError, wrapError} from "../../util/index.js"; import {GlobalArgs} from "../../options/index.js"; import {getBeaconConfigFromArgs} from "../../config/index.js"; import {IValidatorCliArgs} from "./options.js"; @@ -115,39 +115,69 @@ ${validatorsToExit.map((v) => `${v.pubkey} ${v.index} ${v.status}`).join("\n")}` } } - for (const [i, {index, signer, pubkey}] of validatorsToExit.entries()) { - const slot = computeStartSlotAtEpoch(exitEpoch); - const domain = config.getDomainForVoluntaryExit(slot); - const voluntaryExit: phase0.VoluntaryExit = {epoch: exitEpoch, validatorIndex: index}; - const signingRoot = computeSigningRoot(ssz.phase0.VoluntaryExit, voluntaryExit, domain); - - let signature; - switch (signer.type) { - case SignerType.Local: - signature = signer.secretKey.sign(signingRoot); - break; - case SignerType.Remote: { - const signatureHex = await externalSignerPostSignature(config, signer.url, pubkey, signingRoot, slot, { - data: voluntaryExit, - type: SignableMessageType.VOLUNTARY_EXIT, - }); - signature = bls.Signature.fromHex(signatureHex); - break; + const alreadySubmitted = []; + for (const [i, validatorToExit] of validatorsToExit.entries()) { + const {err} = await wrapError(processVoluntaryExit({config, client}, exitEpoch, validatorToExit)); + const {pubkey, index} = validatorToExit; + if (err === null) { + console.log(`Submitted voluntary exit for ${pubkey} (${index}) ${i + 1}/${signersToExit.length}`); + } else { + if (err.message.includes("ALREADY_EXISTS")) { + alreadySubmitted.push(validatorToExit); + } else { + console.log( + `Voluntary exit errored for ${pubkey} (${index}) ${i + 1}/${signersToExit.length}: ${err.message}` + ); } - default: - throw new YargsError(`Unexpected signer type for ${pubkey}`); } - ApiError.assert( - await client.beacon.submitPoolVoluntaryExit({ - message: voluntaryExit, - signature: signature.toBytes(), - }) - ); - console.log(`Submitted voluntary exit for ${pubkey} ${i + 1}/${signersToExit.length}`); + } + + if (alreadySubmitted.length > 0) { + console.log(`Voluntary exit already submitted for ${alreadySubmitted.length}/${signersToExit.length}`); + for (const validatorToExit of alreadySubmitted) { + const {index, pubkey} = validatorToExit; + console.log(` - ${pubkey} (${index})`); + } } }, }; +async function processVoluntaryExit( + {config, client}: {config: BeaconConfig; client: Api}, + exitEpoch: Epoch, + validatorToExit: {index: ValidatorIndex; signer: Signer; pubkey: string} +): Promise { + const {index, signer, pubkey} = validatorToExit; + const slot = computeStartSlotAtEpoch(exitEpoch); + const domain = config.getDomainForVoluntaryExit(slot); + const voluntaryExit: phase0.VoluntaryExit = {epoch: exitEpoch, validatorIndex: index}; + const signingRoot = computeSigningRoot(ssz.phase0.VoluntaryExit, voluntaryExit, domain); + + let signature; + switch (signer.type) { + case SignerType.Local: + signature = signer.secretKey.sign(signingRoot); + break; + case SignerType.Remote: { + const signatureHex = await externalSignerPostSignature(config, signer.url, pubkey, signingRoot, slot, { + data: voluntaryExit, + type: SignableMessageType.VOLUNTARY_EXIT, + }); + signature = bls.Signature.fromHex(signatureHex); + break; + } + default: + throw new YargsError(`Unexpected signer type for ${pubkey}`); + } + + ApiError.assert( + await client.beacon.submitPoolVoluntaryExit({ + message: voluntaryExit, + signature: signature.toBytes(), + }) + ); +} + type SignerPubkey = {signer: Signer; pubkey: string}; function selectSignersToExit(args: VoluntaryExitArgs, signers: Signer[]): SignerPubkey[] { diff --git a/packages/cli/src/util/errors.ts b/packages/cli/src/util/errors.ts index 8f492842f4c8..3b462b4d68e3 100644 --- a/packages/cli/src/util/errors.ts +++ b/packages/cli/src/util/errors.ts @@ -2,3 +2,12 @@ * Expected error that shouldn't print a stack trace */ export class YargsError extends Error {} + +export type Result = {err: null; result: T} | {err: Error}; +export async function wrapError(promise: Promise): Promise> { + try { + return {err: null, result: await promise}; + } catch (err) { + return {err: err as Error}; + } +} From 6f35ac6bbeab4bbad857e127092474f16b7fcd32 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 22 Jan 2024 09:34:28 +0100 Subject: [PATCH 51/70] fix: use incrementing counter for prover request ids (#6333) --- packages/prover/src/utils/rpc.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/prover/src/utils/rpc.ts b/packages/prover/src/utils/rpc.ts index fcd933675cab..a566c2df913d 100644 --- a/packages/prover/src/utils/rpc.ts +++ b/packages/prover/src/utils/rpc.ts @@ -27,6 +27,8 @@ export class ELRpc { private handler: ELRequestHandler; private logger: Logger; + private requestId = 0; + constructor(handler: ELRequestHandler, logger: Logger) { this.handler = handler; this.logger = logger; @@ -99,7 +101,6 @@ export class ELRpc { } getRequestId(): string { - // TODO: Find better way to generate random id - return (Math.random() * 100000000000000000).toFixed(0); + return (++this.requestId).toString(); } } From 5bcc8754cec68db7321d07a4aeeb7976d7f06c4c Mon Sep 17 00:00:00 2001 From: NC Date: Mon, 22 Jan 2024 23:47:42 +0800 Subject: [PATCH 52/70] fix: correct total block value in publish block log (#6336) * Fix consensusBlockValue unit in debug log * lint --- packages/validator/src/services/block.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/validator/src/services/block.ts b/packages/validator/src/services/block.ts index 72b3dbbae2e7..dd7cea13c293 100644 --- a/packages/validator/src/services/block.ts +++ b/packages/validator/src/services/block.ts @@ -11,7 +11,7 @@ import { } from "@lodestar/types"; import {ChainForkConfig} from "@lodestar/config"; import {ForkPreBlobs, ForkBlobs, ForkSeq, ForkExecution} from "@lodestar/params"; -import {ETH_TO_WEI, extendError, gweiToWei, prettyBytes} from "@lodestar/utils"; +import {ETH_TO_WEI, extendError, prettyBytes} from "@lodestar/utils"; import {Api, ApiError, routes} from "@lodestar/api"; import {IClock, LoggerVc} from "../util/index.js"; import {PubkeyHex} from "../types.js"; @@ -223,7 +223,7 @@ export class BlockProposingService { executionPayloadValue: `${formatBigDecimal(response.executionPayloadValue, ETH_TO_WEI, MAX_DECIMAL_FACTOR)} ETH`, consensusBlockValue: `${formatBigDecimal(response.consensusBlockValue, ETH_TO_WEI, MAX_DECIMAL_FACTOR)} ETH`, totalBlockValue: `${formatBigDecimal( - response.executionPayloadValue + gweiToWei(response.consensusBlockValue), + response.executionPayloadValue + response.consensusBlockValue, ETH_TO_WEI, MAX_DECIMAL_FACTOR )} ETH`, From 5b129f0f00228712cffba02b0dcc4eb31ec20e53 Mon Sep 17 00:00:00 2001 From: Nazar Hussain Date: Mon, 22 Jan 2024 18:35:20 +0100 Subject: [PATCH 53/70] chore: cleanup mocha/chai/sinon usage across the repo (#6311) * Cleanup mocha/chai usage * Split the config files for each package * Fix types * Fix lint errors * Sort the lint rules * Fix types * Cleanup sinon usage * Fix tests * Fix lint error * Add vitest word to dictionary * Fix the test iteration * Fix e2e tests * Sort the words * Fix sim test assertion * Fix data import * Fix import order for mocks * Fix import order * Fix e2e tests * Add contribution guide * Fix the lint error * Add src to dictionary * Remove eslint-disable for skipped tests * Fix assertions * Update CONTRIBUTING.md Co-authored-by: Matthew Keil --------- Co-authored-by: Matthew Keil --- .c8rc.json | 21 - .eslintrc.js | 35 +- .mocharc.yaml | 4 - .nycrc.json | 17 - .wordlist.txt | 3 + CONTRIBUTING.md | 18 +- .../contribution/testing/integration-tests.md | 2 +- karma.base.config.js | 12 - package.json | 40 +- packages/api/package.json | 2 +- packages/api/test/utils/utils.ts | 1 - packages/api/vitest.config.ts | 2 +- packages/beacon-node/package.json | 16 +- .../beacon-node/test/__mocks__/apiMocks.ts | 44 - .../test/__mocks__/mockedBeaconDb.ts | 66 - .../test/__mocks__/mockedNetwork.ts | 12 - .../api/impl/beacon/state/endpoint.test.ts | 2 +- .../e2e/doppelganger/doppelganger.test.ts | 32 +- .../e2e/eth1/eth1MergeBlockTracker.test.ts | 4 - .../test/e2e/network/gossipsub.test.ts | 5 +- .../beacon-node/test/e2e/network/mdns.test.ts | 9 +- .../test/e2e/network/network.test.ts | 7 +- .../e2e/network/peers/peerManager.test.ts | 36 +- .../test/e2e/network/reqresp.test.ts | 51 +- .../{__mocks__ => mocks}/beaconSyncMock.ts | 14 +- .../test/{utils => }/mocks/clock.ts | 2 +- .../test/{__mocks__ => mocks}/loggerMock.ts | 4 +- .../{__mocks__ => mocks}/mockedBeaconChain.ts | 138 +- .../beacon-node/test/mocks/mockedBeaconDb.ts | 75 + .../test/{__mocks__ => mocks}/mockedBls.ts | 0 .../beacon-node/test/mocks/mockedNetwork.ts | 22 + packages/beacon-node/test/mocks/regenMocks.ts | 10 + .../beacon-node/test/mocks/shufflingMock.ts | 10 + .../opPools/aggregatedAttestationPool.test.ts | 6 - .../peers/enrSubnetsDeserialize.test.ts | 2 +- .../scripts/el-interop/gethdocker/README.md | 2 +- packages/beacon-node/test/setup.ts | 6 - .../beacon-node/test/sim/4844-interop.test.ts | 27 +- .../test/sim/merge-interop.test.ts | 30 +- .../beacon-node/test/sim/mergemock.test.ts | 18 +- .../test/sim/withdrawal-interop.test.ts | 27 +- .../beacon-node/test/spec/bls/index.test.ts | 10 +- .../spec/presets/epoch_processing.test.ts | 2 +- .../test/spec/presets/fork_choice.test.ts | 16 +- .../test/spec/presets/genesis.test.ts | 2 +- .../test/spec/presets/merkle.test.ts | 4 +- .../test/spec/presets/rewards.test.ts | 2 +- .../test/spec/presets/ssz_static.test.ts | 1 + .../test/spec/utils/runValidSszTest.ts | 4 +- .../network/gossip/scoringParameters.test.ts | 92 +- .../unit-mainnet/network/subnets/util.test.ts | 4 +- .../test/unit/api/impl/beacon/beacon.test.ts | 30 +- .../beacon/blocks/getBlockHeaders.test.ts | 96 +- .../unit/api/impl/beacon/state/utils.test.ts | 2 +- .../impl/validator/duties/proposer.test.ts | 74 +- .../validator/produceAttestationData.test.ts | 37 +- .../api/impl/validator/produceBlockV2.test.ts | 98 +- .../api/impl/validator/produceBlockV3.test.ts | 61 +- .../unit/chain/archive/blockArchiver.test.ts | 4 +- .../blocks/verifyBlocksSanityChecks.test.ts | 4 +- .../test/unit/chain/bls/bls.test.ts | 4 +- .../unit/chain/forkChoice/forkChoice.test.ts | 6 +- .../opPools/aggregatedAttestationPool.test.ts | 6 +- .../test/unit/chain/prepareNextSlot.test.ts | 33 +- .../seenCache/seenGossipBlockInput.test.ts | 15 +- .../test/unit/chain/shufflingCache.test.ts | 14 +- .../stateCache/fifoBlockStateCache.test.ts | 6 +- .../persistentCheckpointsCache.test.ts | 156 +- .../unit/chain/validation/attestation.test.ts | 591 ----- ...hufflingForAttestationVerification.test.ts | 150 ++ .../attestation/validateAttestation.test.ts | 316 +++ ...idateGossipAttestationsSameAttData.test.ts | 128 + .../chain/validation/attesterSlashing.test.ts | 2 +- .../test/unit/chain/validation/block.test.ts | 6 +- .../validation/blsToExecutionChange.test.ts | 3 +- .../lightClientFinalityUpdate.test.ts | 2 +- .../lightClientOptimisticUpdate.test.ts | 2 +- .../chain/validation/proposerSlashing.test.ts | 2 +- .../chain/validation/syncCommittee.test.ts | 2 +- .../chain/validation/voluntaryExit.test.ts | 2 +- .../test/unit/db/api/repository.test.ts | 6 +- .../unit/eth1/eth1DepositDataTracker.test.ts | 2 +- .../test/unit/monitoring/service.test.ts | 2 +- .../unit/network/peers/priorization.test.ts | 2 + .../test/unit/network/peers/score.test.ts | 6 +- .../network/subnets/attnetsService.test.ts | 6 +- .../test/unit/sync/backfill/verify.test.ts | 4 +- .../test/unit/sync/range/batch.test.ts | 2 +- .../test/unit/sync/unknownBlock.test.ts | 6 +- .../test/unit/util/dependentRoot.test.ts | 19 +- .../beacon-node/test/unit/util/kzg.test.ts | 4 +- packages/beacon-node/test/utils/api.ts | 36 + packages/beacon-node/test/utils/logger.ts | 6 +- .../beacon-node/test/utils/mocks/chain.ts | 33 - packages/beacon-node/test/utils/mocks/db.ts | 72 - .../beacon-node/test/utils/mocks/logger.ts | 15 - packages/beacon-node/test/utils/network.ts | 121 +- .../test/utils/networkWithMockDb.ts | 109 + .../beacon-node/test/utils/sinon/matcher.ts | 8 - packages/beacon-node/test/utils/state.ts | 21 + packages/beacon-node/test/utils/stub/index.ts | 9 - packages/beacon-node/test/utils/types.ts | 14 - packages/beacon-node/vitest.config.e2e.ts | 11 + packages/beacon-node/vitest.config.spec.ts | 10 +- packages/beacon-node/vitest.config.ts | 2 +- packages/cli/package.json | 4 +- packages/cli/test/sim/endpoints.test.ts | 20 +- packages/cli/test/utils.ts | 6 +- packages/cli/vitest.config.e2e.ts | 11 + packages/cli/vitest.config.ts | 2 +- packages/config/package.json | 2 +- packages/config/vitest.config.ts | 2 +- packages/db/package.json | 2 +- packages/db/vitest.config.ts | 2 +- packages/flare/package.json | 2 +- packages/flare/vitest.config.ts | 2 +- packages/fork-choice/package.json | 2 +- .../unit/protoArray/computeDeltas.test.ts | 46 - packages/fork-choice/vitest.config.ts | 2 +- packages/light-client/package.json | 2 +- packages/light-client/test/utils/utils.ts | 2 +- packages/light-client/vitest.config.ts | 2 +- packages/logger/package.json | 4 +- packages/logger/test/unit/browser.test.ts | 2 +- packages/logger/test/unit/env.node.test.ts | 2 +- packages/logger/vitest.config.e2e.ts | 11 + packages/logger/vitest.config.ts | 2 +- packages/params/package.json | 4 +- packages/params/test/e2e/setPresetOk.ts | 6 +- .../params/test/unit/activePreset.test.ts | 13 +- .../test/unit/applicationDomains.test.ts | 2 +- packages/params/vitest.config.e2e.ts | 11 + packages/params/vitest.config.ts | 2 +- packages/prover/package.json | 4 +- .../unit/proof_provider/payload_store.test.ts | 13 +- packages/prover/vitest.config.e2e.ts | 11 + packages/prover/vitest.config.ts | 2 +- packages/reqresp/package.json | 2 +- packages/reqresp/test/fixtures/encoders.ts | 2 +- .../test/unit/encoders/requestDecode.test.ts | 2 +- .../test/unit/encoders/responseDecode.test.ts | 9 +- .../unit/rate_limiter/rateLimiterGRCA.test.ts | 5 - packages/reqresp/test/utils/errors.ts | 6 +- packages/reqresp/test/utils/index.ts | 22 +- packages/reqresp/vitest.config.ts | 2 +- packages/spec-test-util/README.md | 2 +- packages/spec-test-util/package.json | 8 +- .../test/e2e/single/index.test.ts | 1 - packages/spec-test-util/vitest.config.e2e.ts | 11 + packages/spec-test-util/vitest.config.ts | 2 +- packages/state-transition/package.json | 2 +- .../test/perf/sanityCheck.test.ts | 2 - .../test/utils/beforeValue.ts | 2 +- packages/state-transition/test/utils/types.ts | 5 - packages/state-transition/vitest.config.ts | 2 +- packages/test-utils/.mocharc.yaml | 4 - packages/test-utils/.nycrc.json | 3 - packages/test-utils/README.md | 2 +- packages/test-utils/package.json | 17 +- .../test-utils/src/{mocha.ts => doubles.ts} | 58 +- packages/test-utils/src/sinon.ts | 23 - packages/types/package.json | 6 +- packages/types/test/constants/blobs.test.ts | 2 +- packages/types/vitest.config.ts | 2 +- packages/utils/package.json | 2 +- packages/utils/test/unit/err.test.ts | 16 +- packages/utils/test/utils/chai.ts | 9 - packages/utils/vitest.config.ts | 2 +- packages/validator/package.json | 4 +- .../validator/test/e2e/web3signer.test.ts | 1 - packages/validator/test/setup.ts | 6 - .../test/unit/services/attestation.test.ts | 4 +- .../test/unit/services/syncCommittee.test.ts | 2 +- .../validator/test/unit/utils/clock.test.ts | 13 +- packages/validator/test/utils/logger.ts | 6 +- packages/validator/vitest.config.e2e.ts | 11 + packages/validator/vitest.config.spec.ts | 2 +- packages/validator/vitest.config.ts | 2 +- tsconfig.build.json | 6 +- vitest.base.e2e.config.ts | 19 + vitest.base.spec.config.ts | 22 + ...se.config.ts => vitest.base.unit.config.ts | 1 + webpack.test.config.js | 66 - yarn.lock | 2124 ++--------------- 184 files changed, 2049 insertions(+), 4022 deletions(-) delete mode 100644 .c8rc.json delete mode 100644 .mocharc.yaml delete mode 100644 .nycrc.json delete mode 100644 karma.base.config.js delete mode 100644 packages/beacon-node/test/__mocks__/apiMocks.ts delete mode 100644 packages/beacon-node/test/__mocks__/mockedBeaconDb.ts delete mode 100644 packages/beacon-node/test/__mocks__/mockedNetwork.ts rename packages/beacon-node/test/{__mocks__ => mocks}/beaconSyncMock.ts (51%) rename packages/beacon-node/test/{utils => }/mocks/clock.ts (96%) rename packages/beacon-node/test/{__mocks__ => mocks}/loggerMock.ts (70%) rename packages/beacon-node/test/{__mocks__ => mocks}/mockedBeaconChain.ts (51%) create mode 100644 packages/beacon-node/test/mocks/mockedBeaconDb.ts rename packages/beacon-node/test/{__mocks__ => mocks}/mockedBls.ts (100%) create mode 100644 packages/beacon-node/test/mocks/mockedNetwork.ts create mode 100644 packages/beacon-node/test/mocks/regenMocks.ts create mode 100644 packages/beacon-node/test/mocks/shufflingMock.ts delete mode 100644 packages/beacon-node/test/setup.ts delete mode 100644 packages/beacon-node/test/unit/chain/validation/attestation.test.ts create mode 100644 packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts create mode 100644 packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts create mode 100644 packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts create mode 100644 packages/beacon-node/test/utils/api.ts delete mode 100644 packages/beacon-node/test/utils/mocks/chain.ts delete mode 100644 packages/beacon-node/test/utils/mocks/db.ts delete mode 100644 packages/beacon-node/test/utils/mocks/logger.ts create mode 100644 packages/beacon-node/test/utils/networkWithMockDb.ts delete mode 100644 packages/beacon-node/test/utils/sinon/matcher.ts delete mode 100644 packages/beacon-node/test/utils/stub/index.ts create mode 100644 packages/beacon-node/vitest.config.e2e.ts create mode 100644 packages/cli/vitest.config.e2e.ts create mode 100644 packages/logger/vitest.config.e2e.ts create mode 100644 packages/params/vitest.config.e2e.ts create mode 100644 packages/prover/vitest.config.e2e.ts create mode 100644 packages/spec-test-util/vitest.config.e2e.ts delete mode 100644 packages/state-transition/test/utils/types.ts delete mode 100644 packages/test-utils/.mocharc.yaml delete mode 100644 packages/test-utils/.nycrc.json rename packages/test-utils/src/{mocha.ts => doubles.ts} (55%) delete mode 100644 packages/test-utils/src/sinon.ts delete mode 100644 packages/utils/test/utils/chai.ts delete mode 100644 packages/validator/test/setup.ts create mode 100644 packages/validator/vitest.config.e2e.ts create mode 100644 vitest.base.e2e.config.ts create mode 100644 vitest.base.spec.config.ts rename vitest.base.config.ts => vitest.base.unit.config.ts (96%) delete mode 100644 webpack.test.config.js diff --git a/.c8rc.json b/.c8rc.json deleted file mode 100644 index 51d1ef9902c4..000000000000 --- a/.c8rc.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "all": true, - "cache": false, - "extension": [".ts", ".js", ".jsx", ".tsx"], - "include": [ - "**/packages/**" - ], - "exclude": [ - "**/node_modules/**", - "**/test/**" - ], - "instrument": true, - "sourceMap": true, - "check-coverage": true, - "reporter": [ - "html", - "lcov", - "text", - "text-summary" - ] -} diff --git a/.eslintrc.js b/.eslintrc.js index 411eba578366..8eeda9a0446f 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -4,6 +4,7 @@ module.exports = { browser: true, es6: true, node: true, + // Performance tests still use mocha mocha: true, }, globals: { @@ -110,7 +111,11 @@ module.exports = { "error", { groups: ["builtin", "external", "internal", "parent", "sibling", "index"], - pathGroups: [{pattern: "@lodestar/**", group: "internal"}], + pathGroups: [ + {pattern: "@lodestar/**", group: "internal"}, + // We want mocks to be imported before any internal code + {pattern: "**/mocks/**", group: "internal"}, + ], pathGroupsExcludedImportTypes: ["builtin"], }, ], @@ -201,24 +206,18 @@ module.exports = { }, { files: ["**/test/**/*.test.ts"], - plugins: ["mocha", "chai-expect"], - extends: ["plugin:mocha/recommended", "plugin:chai-expect/recommended"], + plugins: ["vitest"], + extends: ["plugin:vitest/recommended"], rules: { - // We observed that having multiple top level "describe" save valuable indentation - // https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/max-top-level-suites.md - "mocha/max-top-level-suites": "off", - // We need to disable because we disabled "mocha/no-setup-in-describe" rule - // TODO: Move all setup code to before/beforeEach and then disable async describe - // https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-async-describe.md - "mocha/no-async-describe": "off", - // Use of arrow functions are very common - "mocha/no-mocha-arrows": "off", - // It's common to call function inside describe block - // https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-setup-in-describe.md - "mocha/no-setup-in-describe": "off", - // We use to split before in small isolated tasks - // https://github.com/lo1tuma/eslint-plugin-mocha/blob/master/docs/rules/no-sibling-hooks.md - "mocha/no-sibling-hooks": "off", + "vitest/consistent-test-it": ["error", {fn: "it", withinDescribe: "it"}], + // We use a lot dynamic assertions so tests may not have usage of expect + "vitest/expect-expect": "off", + "vitest/no-disabled-tests": "warn", + "vitest/no-focused-tests": "error", + "vitest/prefer-called-with": "error", + "vitest/prefer-spy-on": "error", + // Our usage contains dynamic test title, this rule enforce static string value + "vitest/valid-title": "off", }, }, { diff --git a/.mocharc.yaml b/.mocharc.yaml deleted file mode 100644 index 1d24429fe466..000000000000 --- a/.mocharc.yaml +++ /dev/null @@ -1,4 +0,0 @@ -extension: ["ts"] -colors: true -node-option: - - "loader=ts-node/esm" diff --git a/.nycrc.json b/.nycrc.json deleted file mode 100644 index e0c09781c849..000000000000 --- a/.nycrc.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "cache": false, - "extension": [".ts"], - "exclude": [ - "**/*.d.ts", - "**/*.js", - "**/lib/**", - "**/coverage/**", - "**/scripts/**", - "**/test/**", - "**/types/**", - "**/bin/**", - "**/node_modules/**" - ], - "all": false, - "reporter": ["lcovonly"] -} diff --git a/.wordlist.txt b/.wordlist.txt index 5982de7b50dc..9e9b2773bd66 100644 --- a/.wordlist.txt +++ b/.wordlist.txt @@ -84,6 +84,7 @@ UPnP UTF VM Vitalik +Vitest Wagyu api async @@ -174,6 +175,7 @@ scalability secp sepolia sharding +src ssz stakers subnet @@ -188,6 +190,7 @@ util utils validator validators +vitest wip xcode yaml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fbc23571aa37..a4e67c4d226b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,15 +39,25 @@ Contributing to tests: - Do not pull unpinned versions from DockerHub (use deterministic tag) or Github (checkout commit not branch). - Carefully design tests that depend on timing sensitive events like p2p network e2e tests. Consider that Github runners are significantly less powerful than your development environment. +### Common Issues + +**Error: [vitest] Cannot mock "../../src/db/repositories/index.js" because it is already loaded by "src/db/beacon.ts"** + +If you observe any error in tests with matching to above error message, that implies you are loading the mocks in the wrong order. The correct order is to import the mocks first and then the actual module. We suggest to import the mocks on very top before any local modules. + +**✖ Error: Cannot find package 'async_hooks' imported from** + +If you observe following error running any of the test files that means you are running a file which itself or any dependency of that file imports `vitest`, but you are not running that file with `vitest` runner. Try running it with `yarn vitest` command, not with `node` command. + ### Debugging Spec Tests - To fix errors always focus on passing all minimal tests first without running mainnet tests. -- Spec tests often compare full expected vs actual states in JSON format. To better understand the diff it's convenient to use mocha's option `--inline-diffs`. -- A single logical error can cause many spec tests to fail. To focus on a single test at a time you can use mocha's option `--bail` to stop at the first failed test -- To then run only that failed test you can run against a specific file as use mocha's option `--grep` to run only one case +- Spec tests often compare full expected vs actual states in JSON format. +- A single logical error can cause many spec tests to fail. To focus on a single test at a time you can use vitest's option `--bail` to stop at the first failed test +- To then run only that failed test you can run against a specific file as use vitest's filters to run only one case ```sh -LODESTAR_PRESET=minimal ../../node_modules/.bin/mocha --config .mocharc.spec.yml test/spec/phase0/sanity.test.ts --inline-diffs --bail --grep "attestation" +LODESTAR_PRESET=minimal yarn vitest --run --config vitest.config.spec.ts test/spec/phase0/sanity.test.ts ``` ## Docker diff --git a/docs/pages/contribution/testing/integration-tests.md b/docs/pages/contribution/testing/integration-tests.md index b45110033460..dcf0201e4949 100644 --- a/docs/pages/contribution/testing/integration-tests.md +++ b/docs/pages/contribution/testing/integration-tests.md @@ -13,7 +13,7 @@ There are two ENV variables that are required to run this test: The command to run this test is: -`EL_BINARY_DIR=g11tech/geth:withdrawals EL_SCRIPT_DIR=gethdocker yarn mocha test/sim/withdrawal-interop.test.ts` +`EL_BINARY_DIR=g11tech/geth:withdrawals EL_SCRIPT_DIR=gethdocker yarn vitest --run test/sim/withdrawal-interop.test.ts` The images used by this test during CI are: diff --git a/karma.base.config.js b/karma.base.config.js deleted file mode 100644 index 0a4795593142..000000000000 --- a/karma.base.config.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - basePath: "", - frameworks: ["webpack", "mocha", "chai"], - files: ["test/unit/**/!(*.node).test.ts"], - exclude: [], - preprocessors: { - "test/**/*.ts": ["webpack"], - }, - reporters: ["spec"], - browsers: ["ChromeHeadless", "Electron", "FirefoxHeadless"], - singleRun: true, -}; diff --git a/package.json b/package.json index b422c2a604aa..93b364359a38 100644 --- a/package.json +++ b/package.json @@ -47,69 +47,45 @@ "devDependencies": { "@chainsafe/eslint-plugin-node": "^11.2.3", "@dapplion/benchmark": "^0.2.4", - "@types/chai": "^4.3.6", - "@types/chai-as-promised": "^7.1.6", - "@types/mocha": "^10.0.1", + "@types/mocha": "^10.0.6", "@types/node": "^20.6.5", - "@types/sinon": "^10.0.16", - "@types/sinon-chai": "^3.2.9", "@typescript-eslint/eslint-plugin": "6.7.2", "@typescript-eslint/parser": "6.7.2", - "@vitest/coverage-v8": "^1.1.0", - "@vitest/browser": "^1.1.0", - "c8": "^8.0.1", - "chai": "^4.3.8", - "chai-as-promised": "^7.1.1", + "@vitest/coverage-v8": "^1.2.1", + "@vitest/browser": "^1.2.1", "codecov": "^3.8.3", "crypto-browserify": "^3.12.0", "electron": "^26.2.2", "eslint": "^8.50.0", "eslint-import-resolver-typescript": "^3.6.1", - "eslint-plugin-chai-expect": "^3.0.0", "eslint-plugin-import": "^2.28.1", - "eslint-plugin-mocha": "^10.2.0", "eslint-plugin-prettier": "^5.0.0", + "eslint-plugin-vitest": "^0.3.20", "https-browserify": "^1.0.0", "jsdom": "^23.0.1", - "karma": "^6.4.2", - "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^3.2.0", - "karma-cli": "^2.0.0", - "karma-electron": "^7.3.0", - "karma-firefox-launcher": "^2.1.2", - "karma-mocha": "^2.0.1", - "karma-spec-reporter": "^0.0.36", - "karma-webpack": "^5.0.0", "lerna": "^7.3.0", "libp2p": "1.1.1", "mocha": "^10.2.0", "node-gyp": "^9.4.0", "npm-run-all": "^4.1.5", - "nyc": "^15.1.0", "path-browserify": "^1.0.1", "prettier": "^3.0.3", "process": "^0.11.10", - "resolve-typescript-plugin": "^2.0.1", - "sinon": "^16.0.0", - "sinon-chai": "^3.7.0", "stream-browserify": "^3.0.0", "stream-http": "^3.2.0", "supertest": "^6.3.3", - "ts-loader": "^9.4.4", "ts-node": "^10.9.1", "typescript": "^5.2.2", "typescript-docs-verifier": "^2.5.0", - "vite-plugin-node-polyfills": "^0.18.0", + "vite-plugin-node-polyfills": "^0.19.0", "vite-plugin-top-level-await": "^1.4.1", - "vitest": "^1.1.0", - "vitest-when": "^0.3.0", + "vitest": "^1.2.1", + "vitest-when": "^0.3.1", "wait-port": "^1.1.0", - "webdriverio": "^8.27.0", - "webpack": "^5.88.2" + "webdriverio": "^8.28.0" }, "resolutions": { "dns-over-http-resolver": "^2.1.1", - "chai": "^4.3.10", "loupe": "^2.3.6", "vite": "^5.0.0" } diff --git a/packages/api/package.json b/packages/api/package.json index b7708ac5aa26..e1a52c47b489 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -65,7 +65,7 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "dependencies": { diff --git a/packages/api/test/utils/utils.ts b/packages/api/test/utils/utils.ts index 8faa2c90d187..cca89c8e4fd5 100644 --- a/packages/api/test/utils/utils.ts +++ b/packages/api/test/utils/utils.ts @@ -38,7 +38,6 @@ export function getTestServer(): {baseUrl: string; server: FastifyInstance} { return {baseUrl, server}; } -/** Type helper to get a Sinon mock object type with Api */ export function getMockApi>( routeIds: Record ): MockedObject> & ServerApi { diff --git a/packages/api/vitest.config.ts b/packages/api/vitest.config.ts index 9f325a6477e2..c4a84957259d 100644 --- a/packages/api/vitest.config.ts +++ b/packages/api/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 54c21fe032ab..3ddde8540670 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -77,15 +77,15 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", - "test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/ --coverage", - "test:unit:mainnet": "LODESTAR_PRESET=mainnet nyc --cache-dir .nyc_output/.cache -e .ts mocha 'test/unit-mainnet/**/*.test.ts'", + "test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/", + "test:unit:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/unit-mainnet", "test:unit": "wrapper() { yarn test:unit:minimal $@ && yarn test:unit:mainnet $@; }; wrapper", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --poolOptions.threads.singleThread true --dir test/e2e", - "test:sim": "mocha 'test/sim/**/*.test.ts'", - "test:sim:merge-interop": "mocha 'test/sim/merge-interop.test.ts'", - "test:sim:mergemock": "mocha 'test/sim/mergemock.test.ts'", - "test:sim:withdrawals": "mocha 'test/sim/withdrawal-interop.test.ts'", - "test:sim:blobs": "mocha 'test/sim/4844-interop.test.ts'", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --config vitest.config.e2e.ts --dir test/e2e", + "test:sim": "vitest --run test/sim/**/*.test.ts", + "test:sim:merge-interop": "vitest --run test/sim/merge-interop.test.ts", + "test:sim:mergemock": "vitest --run test/sim/mergemock.test.ts", + "test:sim:withdrawals": "vitest --run test/sim/withdrawal-interop.test.ts", + "test:sim:blobs": "vitest --run test/sim/4844-interop.test.ts", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", "test:spec:bls": "vitest --run --config vitest.config.spec.ts --dir test/spec/bls/", "test:spec:general": "vitest --run --config vitest.config.spec.ts --dir test/spec/general/", diff --git a/packages/beacon-node/test/__mocks__/apiMocks.ts b/packages/beacon-node/test/__mocks__/apiMocks.ts deleted file mode 100644 index 0f0316ed7435..000000000000 --- a/packages/beacon-node/test/__mocks__/apiMocks.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* eslint-disable @typescript-eslint/naming-convention */ -import {config} from "@lodestar/config/default"; -import {ChainForkConfig} from "@lodestar/config"; -import {getBeaconBlockApi} from "../../src/api/impl/beacon/blocks/index.js"; -import {getMockedBeaconChain, MockedBeaconChain} from "./mockedBeaconChain.js"; -import {MockedBeaconSync, getMockedBeaconSync} from "./beaconSyncMock.js"; -import {MockedBeaconDb, getMockedBeaconDb} from "./mockedBeaconDb.js"; -import {MockedNetwork, getMockedNetwork} from "./mockedNetwork.js"; - -export type ApiImplTestModules = { - forkChoiceStub: MockedBeaconChain["forkChoice"]; - chainStub: MockedBeaconChain; - syncStub: MockedBeaconSync; - dbStub: MockedBeaconDb; - networkStub: MockedNetwork; - blockApi: ReturnType; - config: ChainForkConfig; -}; - -export function setupApiImplTestServer(): ApiImplTestModules { - const chainStub = getMockedBeaconChain(); - const forkChoiceStub = chainStub.forkChoice; - const syncStub = getMockedBeaconSync(); - const dbStub = getMockedBeaconDb(); - const networkStub = getMockedNetwork(); - - const blockApi = getBeaconBlockApi({ - chain: chainStub, - config, - db: dbStub, - network: networkStub, - metrics: null, - }); - - return { - forkChoiceStub, - chainStub, - syncStub, - dbStub, - networkStub, - blockApi, - config, - }; -} diff --git a/packages/beacon-node/test/__mocks__/mockedBeaconDb.ts b/packages/beacon-node/test/__mocks__/mockedBeaconDb.ts deleted file mode 100644 index cb760cd055b8..000000000000 --- a/packages/beacon-node/test/__mocks__/mockedBeaconDb.ts +++ /dev/null @@ -1,66 +0,0 @@ -import {vi, MockedObject} from "vitest"; -import {LevelDbController} from "@lodestar/db"; -import {config as minimalConfig} from "@lodestar/config/default"; -import {BeaconDb} from "../../src/db/index.js"; -import { - AttesterSlashingRepository, - BlockArchiveRepository, - BlockRepository, - DepositEventRepository, - DepositDataRootRepository, - Eth1DataRepository, - ProposerSlashingRepository, - StateArchiveRepository, - VoluntaryExitRepository, - BLSToExecutionChangeRepository, - BlobSidecarsRepository, - BlobSidecarsArchiveRepository, -} from "../../src/db/repositories/index.js"; - -vi.mock("@lodestar/db"); -vi.mock("../../src/db/repositories/index.js"); - -export class MockedBeaconDb extends BeaconDb { - db!: MockedObject; - - block: MockedObject; - blockArchive: MockedObject; - - blobSidecars: MockedObject; - blobSidecarsArchive: MockedObject; - - stateArchive: MockedObject; - - voluntaryExit: MockedObject; - blsToExecutionChange: MockedObject; - proposerSlashing: MockedObject; - attesterSlashing: MockedObject; - depositEvent: MockedObject; - - depositDataRoot: MockedObject; - eth1Data: MockedObject; - - constructor(config = minimalConfig) { - // eslint-disable-next-line - super(config, {} as any); - this.block = vi.mocked(new BlockRepository({} as any, {} as any)); - this.blockArchive = vi.mocked(new BlockArchiveRepository({} as any, {} as any)); - this.stateArchive = vi.mocked(new StateArchiveRepository({} as any, {} as any)); - - this.voluntaryExit = vi.mocked(new VoluntaryExitRepository({} as any, {} as any)); - this.blsToExecutionChange = vi.mocked(new BLSToExecutionChangeRepository({} as any, {} as any)); - this.proposerSlashing = vi.mocked(new ProposerSlashingRepository({} as any, {} as any)); - this.attesterSlashing = vi.mocked(new AttesterSlashingRepository({} as any, {} as any)); - this.depositEvent = vi.mocked(new DepositEventRepository({} as any, {} as any)); - - this.depositDataRoot = vi.mocked(new DepositDataRootRepository({} as any, {} as any)); - this.eth1Data = vi.mocked(new Eth1DataRepository({} as any, {} as any)); - - this.blobSidecars = vi.mocked(new BlobSidecarsRepository({} as any, {} as any)); - this.blobSidecarsArchive = vi.mocked(new BlobSidecarsArchiveRepository({} as any, {} as any)); - } -} - -export function getMockedBeaconDb(): MockedBeaconDb { - return new MockedBeaconDb(); -} diff --git a/packages/beacon-node/test/__mocks__/mockedNetwork.ts b/packages/beacon-node/test/__mocks__/mockedNetwork.ts deleted file mode 100644 index 969dff5e6355..000000000000 --- a/packages/beacon-node/test/__mocks__/mockedNetwork.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {vi, MockedObject} from "vitest"; -import {Network} from "../../src/network/index.js"; - -export type MockedNetwork = MockedObject; - -vi.mock("../../src/network/index.js"); - -export function getMockedNetwork(): MockedNetwork { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - return vi.mocked(new Network()) as MockedNetwork; -} diff --git a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts index 81932a3d446d..182d7b3430b4 100644 --- a/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts +++ b/packages/beacon-node/test/e2e/api/impl/beacon/state/endpoint.test.ts @@ -43,7 +43,7 @@ describe("beacon state api", function () { await bn.close(); }); - describe("getEpochCommittees", async () => { + describe("getEpochCommittees", () => { it("should return all committees for the given state", async () => { const res = await client.getEpochCommittees("head"); ApiError.assert(res); diff --git a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts index 4bc98cfa16dc..8a1d1585ec2d 100644 --- a/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts +++ b/packages/beacon-node/test/e2e/doppelganger/doppelganger.test.ts @@ -91,9 +91,11 @@ describe.skip("doppelganger / doppelganger test", function () { const beaconBlock = ssz.allForks.phase0.BeaconBlock.defaultValue(); await expect( - validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot), + validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot) + ).resolves.toBeWithMessage( + undefined, "Signing should be possible if starting at genesis since doppelganger should be off" - ).to.eventually.be.fulfilled; + ); await expect( validatorUnderTest.validatorStore.signAttestation( @@ -105,9 +107,11 @@ describe.skip("doppelganger / doppelganger test", function () { bn.chain.clock.currentSlot ), bn.chain.clock.currentEpoch - ), + ) + ).resolves.toBeWithMessage( + undefined, "Signing should be possible if starting at genesis since doppelganger should be off" - ).to.eventually.be.fulfilled; + ); }); it("should shut down validator if same key is active and started after genesis", async function () { @@ -241,18 +245,18 @@ describe.skip("doppelganger / doppelganger test", function () { await expect( validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot) - ).to.eventually.be.rejectedWith(`Doppelganger state for key ${pubKey} is not safe`); + ).rejects.toThrow(`Doppelganger state for key ${pubKey} is not safe`); await expect( validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot) - ).to.eventually.be.rejectedWith(`Doppelganger state for key ${pubKey} is not safe`); + ).rejects.toThrow(`Doppelganger state for key ${pubKey} is not safe`); await waitForEvent(bn.chain.clock, ClockEvent.epoch, timeout); + // Signing should be possible after doppelganger check has elapsed await expect( - validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot), - "Signing should be possible after doppelganger check has elapsed" - ).to.eventually.be.fulfilled; + validatorUnderTest.validatorStore.signBlock(fromHexString(pubKey), beaconBlock, bn.chain.clock.currentSlot) + ).resolves.toBeUndefined(); }); it("should not sign attestations if doppelganger period has not passed and started after genesis", async function () { @@ -282,7 +286,7 @@ describe.skip("doppelganger / doppelganger test", function () { ), bn.chain.clock.currentEpoch ) - ).to.eventually.be.rejectedWith(`Doppelganger state for key ${pubKey} is not safe`); + ).rejects.toThrow(`Doppelganger state for key ${pubKey} is not safe`); await expect( validatorUnderTest.validatorStore.signAttestation( @@ -290,10 +294,11 @@ describe.skip("doppelganger / doppelganger test", function () { generateAttestationData(bn.chain.clock.currentSlot, bn.chain.clock.currentEpoch), bn.chain.clock.currentEpoch ) - ).to.eventually.be.rejectedWith(`Doppelganger state for key ${pubKey} is not safe`); + ).rejects.toThrow(`Doppelganger state for key ${pubKey} is not safe`); await waitForEvent(bn.chain.clock, ClockEvent.epoch, timeout); + // Signing should be possible after doppelganger check has elapsed await expect( validatorUnderTest.validatorStore.signAttestation( createAttesterDuty(fromHexString(pubKey), bn.chain.clock.currentSlot, committeeIndex, validatorIndex), @@ -304,9 +309,8 @@ describe.skip("doppelganger / doppelganger test", function () { bn.chain.clock.currentSlot ), bn.chain.clock.currentEpoch - ), - "Signing should be possible after doppelganger check has elapsed" - ).to.eventually.be.fulfilled; + ) + ).resolves.toBeUndefined(); }); }); diff --git a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts index 85eecb7c742e..ae3e0c707542 100644 --- a/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts +++ b/packages/beacon-node/test/e2e/eth1/eth1MergeBlockTracker.test.ts @@ -110,8 +110,6 @@ describe.skip("eth1 / Eth1MergeBlockTracker", function () { // Given the total difficulty offset the block that has TTD is the `difficultyOffset`nth block const mergeBlock = await eth1MergeBlockTracker.getTerminalPowBlock(); if (!mergeBlock) throw Error("mergeBlock not found"); - // Chai does not support bigint comparison - // eslint-disable-next-line chai-expect/no-inner-compare // "mergeBlock.totalDifficulty is not >= TTD" expect(mergeBlock.totalDifficulty).toBeGreaterThanOrEqual(terminalTotalDifficulty); }); @@ -146,8 +144,6 @@ describe.skip("eth1 / Eth1MergeBlockTracker", function () { // Given the total difficulty offset the block that has TTD is the `difficultyOffset`nth block const mergeBlock = await eth1MergeBlockTracker.getTerminalPowBlock(); if (!mergeBlock) throw Error("mergeBlock not found"); - // Chai does not support bigint comparison - // eslint-disable-next-line chai-expect/no-inner-compare // "mergeBlock.totalDifficulty is not >= TTD" expect(mergeBlock.totalDifficulty).toBeGreaterThanOrEqual(terminalTotalDifficulty); }); diff --git a/packages/beacon-node/test/e2e/network/gossipsub.test.ts b/packages/beacon-node/test/e2e/network/gossipsub.test.ts index 1c7a57650eca..0ffab720598c 100644 --- a/packages/beacon-node/test/e2e/network/gossipsub.test.ts +++ b/packages/beacon-node/test/e2e/network/gossipsub.test.ts @@ -5,7 +5,8 @@ import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {ssz} from "@lodestar/types"; import {Network} from "../../../src/network/index.js"; import {GossipType, GossipHandlers, GossipHandlerParamGeneric} from "../../../src/network/gossip/index.js"; -import {connect, onPeerConnect, getNetworkForTest} from "../../utils/network.js"; +import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; +import {connect, onPeerConnect} from "../../utils/network.js"; describe( "gossipsub / main thread", @@ -23,8 +24,6 @@ describe( {timeout: 10_000} ); -/* eslint-disable mocha/no-top-level-hooks */ - function runTests({useWorker}: {useWorker: boolean}): void { const afterEachCallbacks: (() => Promise | void)[] = []; afterEach(async () => { diff --git a/packages/beacon-node/test/e2e/network/mdns.test.ts b/packages/beacon-node/test/e2e/network/mdns.test.ts index 91cbab09bae9..d8e148e191fe 100644 --- a/packages/beacon-node/test/e2e/network/mdns.test.ts +++ b/packages/beacon-node/test/e2e/network/mdns.test.ts @@ -6,24 +6,21 @@ import {SignableENR} from "@chainsafe/enr"; import {createBeaconConfig} from "@lodestar/config"; import {config} from "@lodestar/config/default"; import {ssz} from "@lodestar/types"; - import {computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; +import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; import {Network, NetworkInitModules, getReqRespHandlers} from "../../../src/network/index.js"; import {defaultNetworkOptions, NetworkOptions} from "../../../src/network/options.js"; -import {zeroProtoBlock} from "../../utils/mocks/chain.js"; import {createNetworkModules, onPeerConnect} from "../../utils/network.js"; -import {generateState} from "../../utils/state.js"; +import {generateState, zeroProtoBlock} from "../../utils/state.js"; import {testLogger} from "../../utils/logger.js"; import {GossipHandlers} from "../../../src/network/gossip/index.js"; import {memoOnce} from "../../utils/cache.js"; -import {getMockedBeaconChain} from "../../__mocks__/mockedBeaconChain.js"; -import {getMockedBeaconDb} from "../../__mocks__/mockedBeaconDb.js"; let port = 9000; const mu = "/ip4/127.0.0.1/tcp/0"; // https://github.com/ChainSafe/lodestar/issues/5967 -// eslint-disable-next-line mocha/no-skipped-tests describe.skip("mdns", function () { const afterEachCallbacks: (() => Promise | void)[] = []; afterEach(async () => { diff --git a/packages/beacon-node/test/e2e/network/network.test.ts b/packages/beacon-node/test/e2e/network/network.test.ts index 2a727481118b..40bf6b7e14af 100644 --- a/packages/beacon-node/test/e2e/network/network.test.ts +++ b/packages/beacon-node/test/e2e/network/network.test.ts @@ -5,7 +5,8 @@ import {phase0} from "@lodestar/types"; import {sleep} from "@lodestar/utils"; import {Network, NetworkEvent, ReqRespMethod} from "../../../src/network/index.js"; import {GoodByeReasonCode} from "../../../src/constants/index.js"; -import {connect, disconnect, onPeerConnect, onPeerDisconnect, getNetworkForTest} from "../../utils/network.js"; +import {connect, disconnect, onPeerConnect, onPeerDisconnect} from "../../utils/network.js"; +import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {getValidPeerId} from "../../utils/peer.js"; describe( @@ -24,8 +25,6 @@ describe( {timeout: 10_000} ); -/* eslint-disable mocha/no-top-level-hooks */ - function runTests({useWorker}: {useWorker: boolean}): void { const afterEachCallbacks: (() => Promise | void)[] = []; @@ -98,7 +97,7 @@ function runTests({useWorker}: {useWorker: boolean}): void { // Current implementation of discv5 consumer doesn't allow to deterministically force a peer to be found // a random find node lookup can yield no results if there are too few peers in the DHT - // it.skip("should connect to new peer by subnet", async function () {}); + it.todo("should connect to new peer by subnet", async function () {}); it("Should goodbye peers on stop", async function () { const [netA, netB] = await createTestNodesAB(); diff --git a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts index 5ef836761cb6..8eb0ecdd1ba4 100644 --- a/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts +++ b/packages/beacon-node/test/e2e/network/peers/peerManager.test.ts @@ -1,7 +1,6 @@ -import {describe, it, afterEach, expect} from "vitest"; +import {describe, it, afterEach, expect, vi} from "vitest"; import {Connection} from "@libp2p/interface"; import {CustomEvent} from "@libp2p/interface"; -import sinon from "sinon"; import {BitArray} from "@chainsafe/ssz"; import {config} from "@lodestar/config/default"; import {altair, phase0, ssz} from "@lodestar/types"; @@ -11,7 +10,8 @@ import {ReqRespMethod} from "../../../../src/network/reqresp/ReqRespBeaconNode.j import {PeerRpcScoreStore, PeerManager, IReqRespBeaconNodePeerManager} from "../../../../src/network/peers/index.js"; import {Eth2Gossipsub, getConnectionsMap, NetworkEvent, NetworkEventBus} from "../../../../src/network/index.js"; import {PeersData} from "../../../../src/network/peers/peersData.js"; -import {createNode, getAttnets, getSyncnets} from "../../../utils/network.js"; +import {createNode} from "../../../utils/network.js"; +import {getAttnets, getSyncnets} from "../../../utils/network.js"; import {generateState} from "../../../utils/state.js"; import {waitForEvent} from "../../../utils/events/resolver.js"; import {testLogger} from "../../../utils/logger.js"; @@ -102,10 +102,10 @@ describe("network / peers / PeerManager", function () { // Create a real event emitter with stubbed methods class ReqRespFake implements IReqRespBeaconNodePeerManager { - sendStatus = sinon.stub(); - sendMetadata = sinon.stub(); - sendGoodbye = sinon.stub(); - sendPing = sinon.stub(); + sendStatus = vi.fn(); + sendMetadata = vi.fn(); + sendGoodbye = vi.fn(); + sendPing = vi.fn(); } it("Should request metadata on receivedPing of unknown peer", async () => { @@ -126,7 +126,7 @@ describe("network / peers / PeerManager", function () { const metadata: phase0.Metadata = {seqNumber, attnets: BitArray.fromBitLen(0)}; // Simulate peer1 responding with its metadata - reqResp.sendMetadata.resolves(metadata); + reqResp.sendMetadata.mockResolvedValue(metadata); // We get a ping by peer1, don't have it's metadata so it gets requested networkEventBus.emit(NetworkEvent.reqRespRequest, { @@ -134,20 +134,20 @@ describe("network / peers / PeerManager", function () { peer: peerId1, }); - expect(reqResp.sendMetadata.callCount).toBe(1); - expect(reqResp.sendMetadata.getCall(0).args[0]).toBe(peerId1); + expect(reqResp.sendMetadata).toHaveBeenCalledOnce(); + expect(reqResp.sendMetadata).toHaveBeenNthCalledWith(1, peerId1); // Allow requestMetadata promise to resolve await sleep(0); // We get another ping by peer1, but with an already known seqNumber - reqResp.sendMetadata.reset(); + reqResp.sendMetadata.mockReset(); networkEventBus.emit(NetworkEvent.reqRespRequest, { request: {method: ReqRespMethod.Ping, body: seqNumber}, peer: peerId1, }); - expect(reqResp.sendMetadata.callCount).toBe(0); + expect(reqResp.sendMetadata).not.toHaveBeenCalledOnce(); }); const libp2pConnectionOutboud = { @@ -187,9 +187,9 @@ describe("network / peers / PeerManager", function () { // Simulate peer1 returning a PING and STATUS message const remoteStatus = statusCache.get(); const remoteMetadata: altair.Metadata = {seqNumber: BigInt(1), attnets: getAttnets(), syncnets: getSyncnets()}; - reqResp.sendPing.resolves(remoteMetadata.seqNumber); - reqResp.sendStatus.resolves(remoteStatus); - reqResp.sendMetadata.resolves(remoteMetadata); + reqResp.sendPing.mockResolvedValue(remoteMetadata.seqNumber); + reqResp.sendStatus.mockResolvedValue(remoteStatus); + reqResp.sendMetadata.mockResolvedValue(remoteMetadata); // Simualate a peer connection, get() should return truthy getConnectionsMap(libp2p).set(peerId1.toString(), [libp2pConnectionOutboud]); @@ -207,9 +207,9 @@ describe("network / peers / PeerManager", function () { // 2. Call reqResp.sendStatus // 3. Receive ping result (1) and call reqResp.sendMetadata // 4. Receive status result (2) assert peer relevance and emit `PeerManagerEvent.peerConnected` - expect(reqResp.sendPing.callCount).toBe(1); - expect(reqResp.sendStatus.callCount).toBe(1); - expect(reqResp.sendMetadata.callCount).toBe(1); + expect(reqResp.sendPing).toHaveBeenCalledOnce(); + expect(reqResp.sendStatus).toHaveBeenCalledOnce(); + expect(reqResp.sendMetadata).toHaveBeenCalledOnce(); expect(peerManager["connectedPeers"].get(peerId1.toString())?.metadata).toEqual(remoteMetadata); }); diff --git a/packages/beacon-node/test/e2e/network/reqresp.test.ts b/packages/beacon-node/test/e2e/network/reqresp.test.ts index ee573973131d..855dc7046203 100644 --- a/packages/beacon-node/test/e2e/network/reqresp.test.ts +++ b/packages/beacon-node/test/e2e/network/reqresp.test.ts @@ -7,13 +7,13 @@ import {allForks, altair, phase0, Root, ssz} from "@lodestar/types"; import {sleep as _sleep} from "@lodestar/utils"; import {Network, ReqRespBeaconNodeOpts} from "../../../src/network/index.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; -import {connect, getNetworkForTest, getPeerIdOf, onPeerConnect} from "../../utils/network.js"; +import {connect, getPeerIdOf, onPeerConnect} from "../../utils/network.js"; +import {getNetworkForTest} from "../../utils/networkWithMockDb.js"; import {arrToSource} from "../../unit/network/reqresp/utils.js"; import {GetReqRespHandlerFn, ReqRespMethod} from "../../../src/network/reqresp/types.js"; import {PeerIdStr} from "../../../src/util/peerId.js"; /* eslint-disable - mocha/no-top-level-hooks, require-yield, @typescript-eslint/naming-convention, @typescript-eslint/explicit-function-return-type @@ -84,53 +84,6 @@ function runTests({useWorker}: {useWorker: boolean}): void { return [netA, netB, await getPeerIdOf(netA), await getPeerIdOf(netB)]; } - // it("should send/receive a ping message", async function () { - // const [netA, netB] = await createAndConnectPeers(); - - // // Modify the metadata to make the seqNumber non-zero - // netB.metadata.attnets = BitArray.fromBitLen(0); - // netB.metadata.attnets = BitArray.fromBitLen(0); - // const expectedPong = netB.metadata.seqNumber; - // expect(expectedPong.toString()).to.deep.equal("2", "seqNumber"); - - // const pong = await netA.reqResp.ping(peerIdB); - // expect(pong.toString()).to.deep.equal(expectedPong.toString(), "Wrong response body"); - // }); - - // it("should send/receive a metadata message - altair", async function () { - // const [netA, netB] = await createAndConnectPeers(); - - // const metadata: altair.Metadata = { - // seqNumber: netB.metadata.seqNumber, - // attnets: netB.metadata.attnets, - // syncnets: netB.metadata.syncnets, - // }; - - // const receivedMetadata = await netA.reqResp.metadata(peerIdB); - // expect(receivedMetadata).to.deep.equal(metadata, "Wrong response body"); - // }); - - // it("should send/receive a status message", async function () { - // const status: phase0.Status = { - // forkDigest: Buffer.alloc(4, 0), - // finalizedRoot: Buffer.alloc(32, 0), - // finalizedEpoch: 0, - // headRoot: Buffer.alloc(32, 0), - // headSlot: 0, - // }; - // const statusNetA: phase0.Status = {...status, finalizedEpoch: 1}; - // const statusNetB: phase0.Status = {...status, finalizedEpoch: 2}; - - // const [netA, netB] = await createAndConnectPeers({ - // onStatus: async function* onRequest() { - // yield {data: ssz.phase0.Status.serialize(statusNetB), fork: ForkName.phase0}; - // }, - // }); - - // const receivedStatus = await netA.reqResp.status(peerIdB, statusNetA); - // expect(receivedStatus).to.deep.equal(statusNetB, "Wrong response body"); - // }); - it("should send/receive signed blocks", async function () { const req: phase0.BeaconBlocksByRangeRequest = {startSlot: 0, step: 1, count: 2}; const blocks: phase0.SignedBeaconBlock[] = []; diff --git a/packages/beacon-node/test/__mocks__/beaconSyncMock.ts b/packages/beacon-node/test/mocks/beaconSyncMock.ts similarity index 51% rename from packages/beacon-node/test/__mocks__/beaconSyncMock.ts rename to packages/beacon-node/test/mocks/beaconSyncMock.ts index 6f0e2bd36d62..00164afc5d63 100644 --- a/packages/beacon-node/test/__mocks__/beaconSyncMock.ts +++ b/packages/beacon-node/test/mocks/beaconSyncMock.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {MockedObject, vi} from "vitest"; +import {Mocked, vi} from "vitest"; import {BeaconSync} from "../../src/sync/index.js"; -export type MockedBeaconSync = MockedObject; +export type MockedBeaconSync = Mocked; -vi.mock("../../src/sync/index.js", async (requireActual) => { - const mod = await requireActual(); +vi.mock("../../src/sync/index.js", async (importActual) => { + const mod = await importActual(); const BeaconSync = vi.fn().mockImplementation(() => { const sync = {}; @@ -21,7 +21,7 @@ vi.mock("../../src/sync/index.js", async (requireActual) => { }); export function getMockedBeaconSync(): MockedBeaconSync { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - return vi.mocked(new BeaconSync({})) as MockedBeaconSync; + return vi.mocked(new BeaconSync({} as any, {} as any)); } + +vi.resetModules(); diff --git a/packages/beacon-node/test/utils/mocks/clock.ts b/packages/beacon-node/test/mocks/clock.ts similarity index 96% rename from packages/beacon-node/test/utils/mocks/clock.ts rename to packages/beacon-node/test/mocks/clock.ts index e4aeb21c1e90..155334909560 100644 --- a/packages/beacon-node/test/utils/mocks/clock.ts +++ b/packages/beacon-node/test/mocks/clock.ts @@ -1,7 +1,7 @@ import EventEmitter from "node:events"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {Epoch, Slot} from "@lodestar/types"; -import {IClock} from "../../../src/util/clock.js"; +import {IClock} from "../../src/util/clock.js"; /** * Mock clock that does not progress time unless calling setSlot() diff --git a/packages/beacon-node/test/__mocks__/loggerMock.ts b/packages/beacon-node/test/mocks/loggerMock.ts similarity index 70% rename from packages/beacon-node/test/__mocks__/loggerMock.ts rename to packages/beacon-node/test/mocks/loggerMock.ts index bafd81230dea..ee25ede93475 100644 --- a/packages/beacon-node/test/__mocks__/loggerMock.ts +++ b/packages/beacon-node/test/mocks/loggerMock.ts @@ -1,7 +1,7 @@ -import {vi, MockedObject} from "vitest"; +import {vi, Mocked} from "vitest"; import {Logger} from "@lodestar/logger"; -export type MockedLogger = MockedObject; +export type MockedLogger = Mocked; export function getMockedLogger(): MockedLogger { return { diff --git a/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts b/packages/beacon-node/test/mocks/mockedBeaconChain.ts similarity index 51% rename from packages/beacon-node/test/__mocks__/mockedBeaconChain.ts rename to packages/beacon-node/test/mocks/mockedBeaconChain.ts index c72d22471ce8..21881875ba61 100644 --- a/packages/beacon-node/test/__mocks__/mockedBeaconChain.ts +++ b/packages/beacon-node/test/mocks/mockedBeaconChain.ts @@ -1,54 +1,110 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import {vi, MockedObject, Mock} from "vitest"; -import {ForkChoice} from "@lodestar/fork-choice"; +import {vi, Mocked, Mock} from "vitest"; import {config as defaultConfig} from "@lodestar/config/default"; import {ChainForkConfig} from "@lodestar/config"; -import {BeaconChain} from "../../src/chain/index.js"; -import {ExecutionEngineHttp} from "../../src/execution/engine/http.js"; +import {ForkChoice, ProtoBlock, EpochDifference} from "@lodestar/fork-choice"; +import {Logger} from "@lodestar/utils"; +import {BeaconChain} from "../../src/chain/chain.js"; +import {ChainEventEmitter} from "../../src/chain/emitter.js"; +import {ExecutionEngineHttp} from "../../src/execution/engine/index.js"; import {ExecutionBuilderHttp} from "../../src/execution/builder/http.js"; import {Eth1ForBlockProduction} from "../../src/eth1/index.js"; -import {OpPool} from "../../src/chain/opPools/opPool.js"; -import {AggregatedAttestationPool} from "../../src/chain/opPools/aggregatedAttestationPool.js"; +import {OpPool, AggregatedAttestationPool} from "../../src/chain/opPools/index.js"; import {BeaconProposerCache} from "../../src/chain/beaconProposerCache.js"; -import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; import {LightClientServer} from "../../src/chain/lightClient/index.js"; import {Clock} from "../../src/util/clock.js"; +import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; import {ShufflingCache} from "../../src/chain/shufflingCache.js"; import {getMockedLogger} from "./loggerMock.js"; -export type MockedBeaconChain = MockedObject & { +export type MockedBeaconChain = Mocked & { + logger: Mocked; getHeadState: Mock<[]>; - forkChoice: MockedObject; - executionEngine: MockedObject; - executionBuilder: MockedObject; - eth1: MockedObject; - opPool: MockedObject; - aggregatedAttestationPool: MockedObject; - beaconProposerCache: MockedObject; - shufflingCache: MockedObject; - regen: MockedObject; + forkChoice: MockedForkChoice; + executionEngine: Mocked; + executionBuilder: Mocked; + eth1: Mocked; + opPool: Mocked; + aggregatedAttestationPool: Mocked; + beaconProposerCache: Mocked; + shufflingCache: Mocked; + regen: Mocked; bls: { verifySignatureSets: Mock<[boolean]>; verifySignatureSetsSameMessage: Mock<[boolean]>; close: Mock; canAcceptWork: Mock<[boolean]>; }; - lightClientServer: MockedObject; + lightClientServer: Mocked; }; -vi.mock("@lodestar/fork-choice"); -vi.mock("../../src/execution/engine/http.js"); -vi.mock("../../src/execution/builder/http.js"); + +vi.mock("@lodestar/fork-choice", async (importActual) => { + const mod = await importActual(); + + const ForkChoice = vi.fn().mockImplementation(() => { + return { + updateTime: vi.fn(), + getJustifiedBlock: vi.fn(), + getFinalizedBlock: vi.fn(), + getHead: vi.fn(), + getHeadRoot: vi.fn(), + getDependentRoot: vi.fn(), + getBlockHex: vi.fn(), + getAllAncestorBlocks: vi.fn(), + getAllNonAncestorBlocks: vi.fn(), + iterateAncestorBlocks: vi.fn(), + getBlockSummariesByParentRoot: vi.fn(), + getCanonicalBlockAtSlot: vi.fn(), + getFinalizedCheckpoint: vi.fn(), + hasBlockHex: vi.fn(), + getBlockSummariesAtSlot: vi.fn(), + }; + }); + + return { + ...mod, + ForkChoice, + }; +}); + +vi.mock("../../src/chain/regen/index.js"); vi.mock("../../src/eth1/index.js"); -vi.mock("../../src/chain/opPools/opPool.js"); -vi.mock("../../src/chain/opPools/aggregatedAttestationPool.js"); vi.mock("../../src/chain/beaconProposerCache.js"); vi.mock("../../src/chain/shufflingCache.js"); -vi.mock("../../src/chain/regen/index.js"); vi.mock("../../src/chain/lightClient/index.js"); -vi.mock("../../src/chain/index.js", async (requireActual) => { - const mod = await requireActual(); + +vi.mock("../../src/chain/opPools/index.js", async (importActual) => { + const mod = await importActual(); + + const OpPool = vi.fn().mockImplementation(() => { + return { + hasSeenBlsToExecutionChange: vi.fn(), + hasSeenVoluntaryExit: vi.fn(), + hasSeenProposerSlashing: vi.fn(), + hasSeenAttesterSlashing: vi.fn(), + getSlashingsAndExits: vi.fn(), + }; + }); + + const AggregatedAttestationPool = vi.fn().mockImplementation(() => { + return { + getAttestationsForBlock: vi.fn(), + }; + }); + + return { + ...mod, + OpPool, + AggregatedAttestationPool, + }; +}); + +vi.mock("../../src/chain/chain.js", async (importActual) => { + const mod = await importActual(); const BeaconChain = vi.fn().mockImplementation(({clock, genesisTime, config}: MockedBeaconChainOptions) => { + const logger = getMockedLogger(); + return { config, opts: {}, @@ -61,15 +117,12 @@ vi.mock("../../src/chain/index.js", async (requireActual) => { currentSlotWithGossipDisparity: undefined, isCurrentSlotGivenGossipDisparity: vi.fn(), }, - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - forkChoice: new ForkChoice(), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - executionEngine: new ExecutionEngineHttp(), - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-expect-error - executionBuilder: new ExecutionBuilderHttp(), + forkChoice: getMockedForkChoice(), + executionEngine: { + notifyForkchoiceUpdate: vi.fn(), + getPayload: vi.fn(), + }, + executionBuilder: {}, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error eth1: new Eth1ForBlockProduction(), @@ -90,7 +143,7 @@ vi.mock("../../src/chain/index.js", async (requireActual) => { processBlock: vi.fn(), regenStateForAttestationVerification: vi.fn(), close: vi.fn(), - logger: getMockedLogger(), + logger, regen: new QueuedStateRegenerator({} as any), lightClientServer: new LightClientServer({} as any, {} as any), bls: { @@ -99,7 +152,7 @@ vi.mock("../../src/chain/index.js", async (requireActual) => { close: vi.fn().mockResolvedValue(true), canAcceptWork: vi.fn().mockReturnValue(true), }, - emitter: new mod.ChainEventEmitter(), + emitter: new ChainEventEmitter(), }; }); @@ -125,3 +178,14 @@ export function getMockedBeaconChain(opts?: Partial): config: config ?? defaultConfig, }) as MockedBeaconChain; } + +export type MockedForkChoice = Mocked; + +export function getMockedForkChoice(): MockedForkChoice { + // ForkChoice package is mocked globally + return vi.mocked(new ForkChoice({} as any, {} as any, {} as any, {} as any)); +} + +// To avoid loading the package in test while mocked, exporting frequently used types and constants +export type {ProtoBlock}; +export {EpochDifference}; diff --git a/packages/beacon-node/test/mocks/mockedBeaconDb.ts b/packages/beacon-node/test/mocks/mockedBeaconDb.ts new file mode 100644 index 000000000000..4f5f494a0f40 --- /dev/null +++ b/packages/beacon-node/test/mocks/mockedBeaconDb.ts @@ -0,0 +1,75 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +import {vi, Mocked} from "vitest"; +import {config as minimalConfig} from "@lodestar/config/default"; +import { + AttesterSlashingRepository, + BlockArchiveRepository, + BlockRepository, + DepositEventRepository, + DepositDataRootRepository, + Eth1DataRepository, + ProposerSlashingRepository, + StateArchiveRepository, + VoluntaryExitRepository, + BLSToExecutionChangeRepository, + BlobSidecarsRepository, + BlobSidecarsArchiveRepository, +} from "../../src/db/repositories/index.js"; +import {BeaconDb} from "../../src/db/index.js"; + +export type MockedBeaconDb = Mocked & { + block: Mocked; + blockArchive: Mocked; + + blobSidecars: Mocked; + blobSidecarsArchive: Mocked; + + stateArchive: Mocked; + + voluntaryExit: Mocked; + blsToExecutionChange: Mocked; + proposerSlashing: Mocked; + attesterSlashing: Mocked; + depositEvent: Mocked; + + depositDataRoot: Mocked; + eth1Data: Mocked; +}; + +vi.mock("../../src/db/repositories/index.js"); + +vi.mock("../../src/db/index.js", async (importActual) => { + const mod = await importActual(); + + const mockedBeaconDb = vi.fn().mockImplementation(() => { + return { + block: vi.mocked(new BlockRepository({} as any, {} as any)), + blockArchive: vi.mocked(new BlockArchiveRepository({} as any, {} as any)), + stateArchive: vi.mocked(new StateArchiveRepository({} as any, {} as any)), + + voluntaryExit: vi.mocked(new VoluntaryExitRepository({} as any, {} as any)), + blsToExecutionChange: vi.mocked(new BLSToExecutionChangeRepository({} as any, {} as any)), + proposerSlashing: vi.mocked(new ProposerSlashingRepository({} as any, {} as any)), + attesterSlashing: vi.mocked(new AttesterSlashingRepository({} as any, {} as any)), + depositEvent: vi.mocked(new DepositEventRepository({} as any, {} as any)), + + depositDataRoot: vi.mocked(new DepositDataRootRepository({} as any, {} as any)), + eth1Data: vi.mocked(new Eth1DataRepository({} as any, {} as any)), + + blobSidecars: vi.mocked(new BlobSidecarsRepository({} as any, {} as any)), + blobSidecarsArchive: vi.mocked(new BlobSidecarsArchiveRepository({} as any, {} as any)), + }; + }); + + return { + ...mod, + // eslint-disable-next-line @typescript-eslint/naming-convention + BeaconDb: mockedBeaconDb, + }; +}); + +export function getMockedBeaconDb(): MockedBeaconDb { + return new BeaconDb(minimalConfig, {} as any) as MockedBeaconDb; +} + +vi.resetModules(); diff --git a/packages/beacon-node/test/__mocks__/mockedBls.ts b/packages/beacon-node/test/mocks/mockedBls.ts similarity index 100% rename from packages/beacon-node/test/__mocks__/mockedBls.ts rename to packages/beacon-node/test/mocks/mockedBls.ts diff --git a/packages/beacon-node/test/mocks/mockedNetwork.ts b/packages/beacon-node/test/mocks/mockedNetwork.ts new file mode 100644 index 000000000000..ddf70aa1b5aa --- /dev/null +++ b/packages/beacon-node/test/mocks/mockedNetwork.ts @@ -0,0 +1,22 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import {vi, Mocked} from "vitest"; +import {Network, INetwork} from "../../src/network/index.js"; + +vi.mock("../../src/network/index.js", async (importActual) => { + const mod = await importActual(); + + const Network = vi.fn().mockImplementation(() => { + return {}; + }); + + return { + ...mod, + Network, + }; +}); + +export type MockedNetwork = Mocked; + +export function getMockedNetwork(): MockedNetwork { + return new Network({} as any) as unknown as MockedNetwork; +} diff --git a/packages/beacon-node/test/mocks/regenMocks.ts b/packages/beacon-node/test/mocks/regenMocks.ts new file mode 100644 index 000000000000..39f7fa382760 --- /dev/null +++ b/packages/beacon-node/test/mocks/regenMocks.ts @@ -0,0 +1,10 @@ +import {vi, Mocked} from "vitest"; +import {QueuedStateRegenerator} from "../../src/chain/regen/index.js"; + +export type MockedQueuedStateRegenerator = Mocked; + +vi.mock("../../src/chain/regen/index.js"); + +export function getMockedQueuedStateRegenerator(): MockedQueuedStateRegenerator { + return vi.mocked(new QueuedStateRegenerator({} as any)); +} diff --git a/packages/beacon-node/test/mocks/shufflingMock.ts b/packages/beacon-node/test/mocks/shufflingMock.ts new file mode 100644 index 000000000000..76482f760872 --- /dev/null +++ b/packages/beacon-node/test/mocks/shufflingMock.ts @@ -0,0 +1,10 @@ +import {vi, Mocked} from "vitest"; +import {ShufflingCache} from "../../src/chain/shufflingCache.js"; + +export type MockedShufflingCache = Mocked; + +vi.mock("../../src/chain/shufflingCache.js"); + +export function getMockedShufflingCache(): MockedShufflingCache { + return vi.mocked(new ShufflingCache({} as any)); +} diff --git a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts index d2317de42c5e..5dd73bafa3f0 100644 --- a/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/perf/chain/opPools/aggregatedAttestationPool.test.ts @@ -1,4 +1,3 @@ -import sinon from "sinon"; import {itBench} from "@dapplion/benchmark"; import {expect} from "chai"; import {BitArray, toHexString} from "@chainsafe/ssz"; @@ -29,7 +28,6 @@ describe("getAttestationsForBlock", () => { let originalState: CachedBeaconStateAltair; let protoArray: ProtoArray; let forkchoice: ForkChoice; - const sandbox = sinon.createSandbox(); before(function () { this.timeout(2 * 60 * 1000); // Generating the states for the first time is very slow @@ -127,10 +125,6 @@ describe("getAttestationsForBlock", () => { forkchoice = new ForkChoice(originalState.config, fcStore, protoArray); }); - after(() => { - sandbox.restore(); - }); - itBench({ id: "getAttestationsForBlock", beforeEach: () => getAggregatedAttestationPool(originalState), diff --git a/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts b/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts index f8ed571f9622..2507c43bcc9c 100644 --- a/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts +++ b/packages/beacon-node/test/perf/network/peers/enrSubnetsDeserialize.test.ts @@ -6,7 +6,7 @@ import {deserializeEnrSubnets} from "../../../../src/network/peers/utils/enrSubn /** * Ideally we want to sleep between requests to test the prune. - * But adding sinon mock timer here make it impossible to benchmark. + * But adding mock timer here make it impossible to benchmark. */ describe("network / peers / deserializeEnrSubnets", () => { const attnets = Buffer.from("feffb7f7fdfffefd", "hex"); diff --git a/packages/beacon-node/test/scripts/el-interop/gethdocker/README.md b/packages/beacon-node/test/scripts/el-interop/gethdocker/README.md index df4b56f4368a..6525de57d30f 100644 --- a/packages/beacon-node/test/scripts/el-interop/gethdocker/README.md +++ b/packages/beacon-node/test/scripts/el-interop/gethdocker/README.md @@ -12,5 +12,5 @@ docker pull ethereum/client-go:latest ```bash cd packages/lodestar -EL_BINARY_DIR=ethereum/client-go:latest EL_SCRIPT_DIR=gethdocker ETH_PORT=8545 ENGINE_PORT=8551 TX_SCENARIOS=simple yarn mocha test/sim/merge-interop.test.ts +EL_BINARY_DIR=ethereum/client-go:latest EL_SCRIPT_DIR=gethdocker ETH_PORT=8545 ENGINE_PORT=8551 TX_SCENARIOS=simple yarn vitest --run test/sim/merge-interop.test.ts ``` diff --git a/packages/beacon-node/test/setup.ts b/packages/beacon-node/test/setup.ts deleted file mode 100644 index b83e6cb78511..000000000000 --- a/packages/beacon-node/test/setup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import sinonChai from "sinon-chai"; - -chai.use(chaiAsPromised); -chai.use(sinonChai); diff --git a/packages/beacon-node/test/sim/4844-interop.test.ts b/packages/beacon-node/test/sim/4844-interop.test.ts index 014339a3d2d8..d6de49e32eff 100644 --- a/packages/beacon-node/test/sim/4844-interop.test.ts +++ b/packages/beacon-node/test/sim/4844-interop.test.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {Context} from "mocha"; +import {describe, it, vi, afterAll, afterEach} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; import {TimestampFormatCode} from "@lodestar/logger"; @@ -24,7 +24,7 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// DEV_RUN=true EL_BINARY_DIR=g11tech/ethereumjs:devnet6-32aaac EL_SCRIPT_DIR=ethereumjsdocker yarn mocha test/sim/4844-interop.test.ts +// DEV_RUN=true EL_BINARY_DIR=g11tech/ethereumjs:devnet6-32aaac EL_SCRIPT_DIR=ethereumjsdocker yarn vitest --run test/sim/4844-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -37,7 +37,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` ); } - this.timeout("10min"); + vi.setConfig({testTimeout: 1000 * 60 * 10, hookTimeout: 1000 * 60 * 10}); const dataPath = fs.mkdtempSync("lodestar-test-4844"); const elSetupConfig = { @@ -52,7 +52,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const controller = new AbortController(); - after(async () => { + afterAll(async () => { controller?.abort(); await shell(`sudo rm -rf ${dataPath}`); }); @@ -65,6 +65,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } }); + // eslint-disable-next-line vitest/expect-expect it("Post-merge, run for a few blocks", async function () { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( @@ -74,17 +75,22 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, denebEpoch: 0, testName: "post-merge", }); }); - async function runNodeWithEL( - this: Context, - {elClient, denebEpoch, testName}: {elClient: ELClient; denebEpoch: Epoch; testName: string} - ): Promise { + async function runNodeWithEL({ + elClient, + denebEpoch, + testName, + }: { + elClient: ELClient; + denebEpoch: Epoch; + testName: string; + }): Promise { const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; const validatorClientCount = 1; const validatorsPerClient = 8; @@ -112,8 +118,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ((epochsOfMargin + 10 * expectedEpochsToFinish) * SLOTS_PER_EPOCH + genesisSlotsDelay) * testParams.SECONDS_PER_SLOT * 1000; - - this.timeout(timeout + 2 * timeoutSetupMargin); + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/sim/merge-interop.test.ts b/packages/beacon-node/test/sim/merge-interop.test.ts index a9fa10ab2208..9467c53831c8 100644 --- a/packages/beacon-node/test/sim/merge-interop.test.ts +++ b/packages/beacon-node/test/sim/merge-interop.test.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {Context} from "mocha"; +import {describe, it, afterAll, afterEach, vi} from "vitest"; import {fromHexString} from "@chainsafe/ssz"; import {isExecutionStateType, isMergeTransitionComplete} from "@lodestar/state-transition"; import {LogLevel, sleep} from "@lodestar/utils"; @@ -39,7 +39,7 @@ import {shell} from "./shell.js"; // ``` // $ EL_BINARY_DIR=/home/lion/Code/eth2.0/merge-interop/go-ethereum/build/bin \ // EL_SCRIPT_DIR=geth ETH_PORT=8545 ENGINE_PORT=8551 TX_SCENARIOS=simple \ -// ../../node_modules/.bin/mocha test/sim/merge.test.ts +// ../../node_modules/.bin/vitest --run test/sim/merge.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention, quotes */ @@ -58,7 +58,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` ); } - this.timeout("10min"); + vi.setConfig({testTimeout: 10 * 60 * 1000}); const dataPath = fs.mkdtempSync("lodestar-test-merge-interop"); const elSetupConfig = { @@ -73,7 +73,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const controller = new AbortController(); - after(async () => { + afterAll(async () => { controller?.abort(); await shell(`sudo rm -rf ${dataPath}`); }); @@ -86,6 +86,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } }); + // eslint-disable-next-line vitest/expect-expect it("Send stub payloads to EL", async () => { const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge}, @@ -202,6 +203,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { */ }); + // eslint-disable-next-line vitest/expect-expect it("Post-merge, run for a few blocks", async function () { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( @@ -211,13 +213,14 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, bellatrixEpoch: 0, testName: "post-merge", }); }); + // eslint-disable-next-line vitest/expect-expect it("Pre-merge, run for a few blocks", async function () { console.log("\n\nPre-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( @@ -227,17 +230,22 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, bellatrixEpoch: 1, testName: "pre-merge", }); }); - async function runNodeWithEL( - this: Context, - {elClient, bellatrixEpoch, testName}: {elClient: ELClient; bellatrixEpoch: Epoch; testName: string} - ): Promise { + async function runNodeWithEL({ + elClient, + bellatrixEpoch, + testName, + }: { + elClient: ELClient; + bellatrixEpoch: Epoch; + testName: string; + }): Promise { const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; const validatorClientCount = 1; const validatorsPerClient = 32; @@ -261,7 +269,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { testParams.SECONDS_PER_SLOT * 1000; - this.timeout(timeout + 2 * timeoutSetupMargin); + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/sim/mergemock.test.ts b/packages/beacon-node/test/sim/mergemock.test.ts index d9492723599d..97a9d9f2aaf7 100644 --- a/packages/beacon-node/test/sim/mergemock.test.ts +++ b/packages/beacon-node/test/sim/mergemock.test.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {Context} from "mocha"; +import {describe, it, afterAll, afterEach, vi} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; import {TimestampFormatCode} from "@lodestar/logger"; @@ -22,7 +22,7 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// EL_BINARY_DIR=g11tech/mergemock:latest EL_SCRIPT_DIR=mergemock LODESTAR_PRESET=mainnet ETH_PORT=8661 ENGINE_PORT=8551 yarn mocha test/sim/mergemock.test.ts +// EL_BINARY_DIR=g11tech/mergemock:latest EL_SCRIPT_DIR=mergemock LODESTAR_PRESET=mainnet ETH_PORT=8661 ENGINE_PORT=8551 yarn vitest --run test/sim/mergemock.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -35,7 +35,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` ); } - this.timeout("10min"); + vi.setConfig({testTimeout: 10 * 60 * 1000}); const dataPath = fs.mkdtempSync("lodestar-test-mergemock"); const elSetupConfig = { @@ -50,7 +50,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const controller = new AbortController(); - after(async () => { + afterAll(async () => { controller?.abort(); await shell(`sudo rm -rf ${dataPath}`); }); @@ -64,6 +64,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }); for (const useProduceBlockV3 of [false, true]) { + // eslint-disable-next-line vitest/expect-expect it(`Test builder with useProduceBlockV3=${useProduceBlockV3}`, async function () { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( @@ -73,7 +74,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, bellatrixEpoch: 0, testName: "post-merge", @@ -84,10 +85,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { type RunOpts = {elClient: ELClient; bellatrixEpoch: Epoch; testName: string; useProduceBlockV3: boolean}; - async function runNodeWithEL( - this: Context, - {elClient, bellatrixEpoch, testName, useProduceBlockV3}: RunOpts - ): Promise { + async function runNodeWithEL({elClient, bellatrixEpoch, testName, useProduceBlockV3}: RunOpts): Promise { const {genesisBlockHash, ttd, engineRpcUrl, ethRpcUrl} = elClient; const validatorClientCount = 1; const validatorsPerClient = 32; @@ -123,7 +121,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { testParams.SECONDS_PER_SLOT * 1000; - this.timeout(timeout + 2 * timeoutSetupMargin); + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/sim/withdrawal-interop.test.ts b/packages/beacon-node/test/sim/withdrawal-interop.test.ts index b828382ad247..6fdd4fd5a0ce 100644 --- a/packages/beacon-node/test/sim/withdrawal-interop.test.ts +++ b/packages/beacon-node/test/sim/withdrawal-interop.test.ts @@ -1,5 +1,5 @@ import fs from "node:fs"; -import {Context} from "mocha"; +import {describe, it, afterAll, afterEach, vi} from "vitest"; import {fromHexString, toHexString} from "@chainsafe/ssz"; import {LogLevel, sleep} from "@lodestar/utils"; import {TimestampFormatCode} from "@lodestar/logger"; @@ -27,7 +27,7 @@ import {logFilesDir} from "./params.js"; import {shell} from "./shell.js"; // NOTE: How to run -// EL_BINARY_DIR=g11tech/geth:withdrawalsfeb8 EL_SCRIPT_DIR=gethdocker yarn mocha test/sim/withdrawal-interop.test.ts +// EL_BINARY_DIR=g11tech/geth:withdrawalsfeb8 EL_SCRIPT_DIR=gethdocker yarn vitest --run test/sim/withdrawal-interop.test.ts // ``` /* eslint-disable no-console, @typescript-eslint/naming-convention */ @@ -42,7 +42,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { `EL ENV must be provided, EL_BINARY_DIR: ${process.env.EL_BINARY_DIR}, EL_SCRIPT_DIR: ${process.env.EL_SCRIPT_DIR}` ); } - this.timeout("10min"); + vi.setConfig({testTimeout: 10 * 60 * 1000}); const dataPath = fs.mkdtempSync("lodestar-test-withdrawal"); const elSetupConfig = { @@ -57,7 +57,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { }; const controller = new AbortController(); - after(async () => { + afterAll(async () => { controller?.abort(); await shell(`sudo rm -rf ${dataPath}`); }); @@ -70,6 +70,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { } }); + // eslint-disable-next-line vitest/expect-expect it("Send stub payloads to EL", async () => { const {elClient, tearDownCallBack} = await runEL( {...elSetupConfig, mode: ELStartMode.PostMerge, genesisTemplate: "genesisPostWithdraw.tmpl"}, @@ -184,6 +185,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); }); + // eslint-disable-next-line vitest/expect-expect it("Post-merge, run for a few blocks", async function () { console.log("\n\nPost-merge, run for a few blocks\n\n"); const {elClient, tearDownCallBack} = await runEL( @@ -193,17 +195,22 @@ describe("executionEngine / ExecutionEngineHttp", function () { ); afterEachCallbacks.push(() => tearDownCallBack()); - await runNodeWithEL.bind(this)({ + await runNodeWithEL({ elClient, capellaEpoch: 0, testName: "post-merge", }); }); - async function runNodeWithEL( - this: Context, - {elClient, capellaEpoch, testName}: {elClient: ELClient; capellaEpoch: Epoch; testName: string} - ): Promise { + async function runNodeWithEL({ + elClient, + capellaEpoch, + testName, + }: { + elClient: ELClient; + capellaEpoch: Epoch; + testName: string; + }): Promise { const {genesisBlockHash, ttd, engineRpcUrl} = elClient; const validatorClientCount = 1; const validatorsPerClient = 32; @@ -229,7 +236,7 @@ describe("executionEngine / ExecutionEngineHttp", function () { testParams.SECONDS_PER_SLOT * 1000; - this.timeout(timeout + 2 * timeoutSetupMargin); + vi.setConfig({testTimeout: timeout + 2 * timeoutSetupMargin}); const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; diff --git a/packages/beacon-node/test/spec/bls/index.test.ts b/packages/beacon-node/test/spec/bls/index.test.ts index b581b8681870..b781685432e6 100644 --- a/packages/beacon-node/test/spec/bls/index.test.ts +++ b/packages/beacon-node/test/spec/bls/index.test.ts @@ -35,20 +35,14 @@ for (const fnName of readdirSyncSpec(blsSpecTests.outputDir)) { const fnTestDirpath = path.join(blsSpecTests.outputDir, fnName); for (const testName of readdirSyncSpec(fnTestDirpath)) { - // TODO: Will be removed when we remove chai/mocha eslint rules - // eslint-disable-next-line mocha/handle-done-callback it(`${fnName}/${testName}`, function (context) { if (fn === "skip") { - // TODO: Will be removed when we remove chai/mocha eslint rules - // eslint-disable-next-line mocha/no-nested-tests context.skip(); return; } // Do not manually skip tests here, do it in the top of the file if (skippedTestNames.includes(testName)) { - // TODO: Will be removed when we remove chai/mocha eslint rules - // eslint-disable-next-line mocha/no-nested-tests context.skip(); return; } @@ -58,10 +52,10 @@ for (const fnName of readdirSyncSpec(blsSpecTests.outputDir)) { // Test format: https://github.com/ethereum/bls12-381-tests if (testData.output === null) { // Expect failure - expect(() => fn(testData.input) as never).to.throw(); + expect(() => fn(testData.input) as never).toThrow(); } else { // Expect success - expect(fn(testData.input)).to.deep.equals(testData.output); + expect(fn(testData.input)).toEqual(testData.output); } }); } diff --git a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts index 951761b9b743..a244762143f3 100644 --- a/packages/beacon-node/test/spec/presets/epoch_processing.test.ts +++ b/packages/beacon-node/test/spec/presets/epoch_processing.test.ts @@ -71,7 +71,7 @@ const epochProcessing = if (testcase.post === undefined) { // If post.ssz_snappy is not value, the sub-transition processing is aborted // https://github.com/ethereum/consensus-specs/blob/dev/tests/formats/epoch_processing/README.md#postssz_snappy - expect(() => epochTransitionFn(state, epochTransitionCache)).to.throw(); + expect(() => epochTransitionFn(state, epochTransitionCache)).toThrow(); } else { epochTransitionFn(state, epochTransitionCache); } diff --git a/packages/beacon-node/test/spec/presets/fork_choice.test.ts b/packages/beacon-node/test/spec/presets/fork_choice.test.ts index 665e395222f9..b0ad63a68205 100644 --- a/packages/beacon-node/test/spec/presets/fork_choice.test.ts +++ b/packages/beacon-node/test/spec/presets/fork_choice.test.ts @@ -20,8 +20,8 @@ import {getExecutionEngineFromBackend} from "../../../src/execution/index.js"; import {ExecutionPayloadStatus} from "../../../src/execution/engine/interface.js"; import {ExecutionEngineMockBackend} from "../../../src/execution/engine/mock.js"; import {defaultChainOptions} from "../../../src/chain/options.js"; -import {getStubbedBeaconDb} from "../../utils/mocks/db.js"; -import {ClockStopped} from "../../utils/mocks/clock.js"; +import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; +import {ClockStopped} from "../../mocks/clock.js"; import { getBlockInput, AttestationImportOpt, @@ -99,7 +99,7 @@ const forkChoiceTest = }, { config: createBeaconConfig(config, state.genesisValidatorsRoot), - db: getStubbedBeaconDb(), + db: getMockedBeaconDb(), logger, // eslint-disable-next-line @typescript-eslint/no-empty-function processShutdownCallback: () => {}, @@ -268,13 +268,13 @@ const forkChoiceTest = const proposerBootRoot = (chain.forkChoice as ForkChoice).getProposerBoostRoot(); if (step.checks.head !== undefined) { - expect({slot: head.slot, root: head.blockRoot}).deep.equals( + expect({slot: head.slot, root: head.blockRoot}).toEqualWithMessage( {slot: bnToNum(step.checks.head.slot), root: step.checks.head.root}, `Invalid head at step ${i}` ); } if (step.checks.proposer_boost_root !== undefined) { - expect(proposerBootRoot).to.be.equal( + expect(proposerBootRoot).toEqualWithMessage( step.checks.proposer_boost_root, `Invalid proposer boost root at step ${i}` ); @@ -283,18 +283,18 @@ const forkChoiceTest = // Compare in slots because proposer boost steps doesn't always come on // slot boundary. if (step.checks.time !== undefined && step.checks.time > 0) - expect(chain.forkChoice.getTime()).to.be.equal( + expect(chain.forkChoice.getTime()).toEqualWithMessage( Math.floor(bnToNum(step.checks.time) / config.SECONDS_PER_SLOT), `Invalid forkchoice time at step ${i}` ); if (step.checks.justified_checkpoint) { - expect(toSpecTestCheckpoint(chain.forkChoice.getJustifiedCheckpoint())).to.be.deep.equal( + expect(toSpecTestCheckpoint(chain.forkChoice.getJustifiedCheckpoint())).toEqualWithMessage( step.checks.justified_checkpoint, `Invalid justified checkpoint at step ${i}` ); } if (step.checks.finalized_checkpoint) { - expect(toSpecTestCheckpoint(chain.forkChoice.getFinalizedCheckpoint())).to.be.deep.equal( + expect(toSpecTestCheckpoint(chain.forkChoice.getFinalizedCheckpoint())).toEqualWithMessage( step.checks.finalized_checkpoint, `Invalid finalized checkpoint at step ${i}` ); diff --git a/packages/beacon-node/test/spec/presets/genesis.test.ts b/packages/beacon-node/test/spec/presets/genesis.test.ts index 0b707f509428..ba3351a2103c 100644 --- a/packages/beacon-node/test/spec/presets/genesis.test.ts +++ b/packages/beacon-node/test/spec/presets/genesis.test.ts @@ -109,7 +109,7 @@ const genesisValidity: TestRunnerFn = (fork) = }, getExpected: (testCase) => testCase.is_valid, expectFunc: (testCase, expected, actual) => { - expect(actual).to.be.equal(expected, "isValidGenesisState is not" + expected); + expect(actual).toEqualWithMessage(expected, "isValidGenesisState is not" + expected); }, }, }; diff --git a/packages/beacon-node/test/spec/presets/merkle.test.ts b/packages/beacon-node/test/spec/presets/merkle.test.ts index a711d9ce66ac..d3f6890527e9 100644 --- a/packages/beacon-node/test/spec/presets/merkle.test.ts +++ b/packages/beacon-node/test/spec/presets/merkle.test.ts @@ -23,7 +23,7 @@ const merkle: TestRunnerFn = (fork) => { const leafIndex = Number(specTestProof.leaf_index); const depth = Math.floor(Math.log2(leafIndex)); const verified = verifyMerkleBranch(leaf, branch, depth, leafIndex % 2 ** depth, stateRoot); - expect(verified).to.equal(true, "invalid merkle branch"); + expect(verified).toEqualWithMessage(true, "invalid merkle branch"); const lodestarProof = new Tree(state.node).getProof({ gindex: specTestProof.leaf_index, @@ -48,7 +48,7 @@ const merkle: TestRunnerFn = (fork) => { timeout: 10000, getExpected: (testCase) => testCase.proof, expectFunc: (testCase, expected, actual) => { - expect(actual).to.be.deep.equal(expected, "incorrect proof"); + expect(actual).toEqualWithMessage(expected, "incorrect proof"); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts }, diff --git a/packages/beacon-node/test/spec/presets/rewards.test.ts b/packages/beacon-node/test/spec/presets/rewards.test.ts index 635d658857b1..426245242d84 100644 --- a/packages/beacon-node/test/spec/presets/rewards.test.ts +++ b/packages/beacon-node/test/spec/presets/rewards.test.ts @@ -58,7 +58,7 @@ const rewards: TestRunnerFn = (fork) => { testCase.inactivity_penalty_deltas, ]), expectFunc: (testCase, expected, actual) => { - expect(actual).to.deep.equal(expected); + expect(actual).toEqual(expected); }, // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts }, diff --git a/packages/beacon-node/test/spec/presets/ssz_static.test.ts b/packages/beacon-node/test/spec/presets/ssz_static.test.ts index bcab25acde4c..b721fced69a9 100644 --- a/packages/beacon-node/test/spec/presets/ssz_static.test.ts +++ b/packages/beacon-node/test/spec/presets/ssz_static.test.ts @@ -60,6 +60,7 @@ const sszStatic = for (const testCase of fs.readdirSync(testSuiteDirpath)) { // Do not manually skip tests here, do it in packages/beacon-node/test/spec/presets/index.test.ts + // eslint-disable-next-line vitest/consistent-test-it it(testCase, function () { // Mainnet must deal with big full states and hash each one multiple times if (ACTIVE_PRESET === "mainnet") { diff --git a/packages/beacon-node/test/spec/utils/runValidSszTest.ts b/packages/beacon-node/test/spec/utils/runValidSszTest.ts index 7dedd0983e3b..e5f249ab5257 100644 --- a/packages/beacon-node/test/spec/utils/runValidSszTest.ts +++ b/packages/beacon-node/test/spec/utils/runValidSszTest.ts @@ -76,7 +76,7 @@ export function runValidSszTest(type: Type, testData: ValidTestCaseData // To print the chunk roots of a type value // - // $ RENDER_ROOTS=true ONLY_ID="4 arrays" ../../node_modules/.bin/mocha test/unit/byType/vector/valid.test.ts + // $ RENDER_ROOTS=true ONLY_ID="4 arrays" ../../node_modules/.bin/vitest test/unit/byType/vector/valid.test.ts // // 0x0000000000000000000000000000000000000000000000000000000000000000 if (process.env.RENDER_ROOTS) { @@ -103,7 +103,7 @@ export function runValidSszTest(type: Type, testData: ValidTestCaseData // To print a tree a single test you are debugging do // - // $ RENDER_TREE=true ONLY_ID="4 arrays" ../../node_modules/.bin/mocha test/unit/byType/vector/valid.test.ts + // $ RENDER_TREE=true ONLY_ID="4 arrays" ../../node_modules/.bin/vitest --run test/unit/byType/vector/valid.test.ts // // '1000' => '0x0000000000000000000000000000000000000000000000000000000000000000', // '1001' => '0x0000000000000000000000000000000000000000000000000000000000000000', diff --git a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts index 3b84bba01f92..6805f00ced1b 100644 --- a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {TopicScoreParams} from "@chainsafe/libp2p-gossipsub/score"; import {ATTESTATION_SUBNET_COUNT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; @@ -26,11 +26,11 @@ describe("computeGossipPeerScoreParams", function () { currentSlot: 0, currentEpoch: 0, }; - expect(gossipScoreThresholds.gossipThreshold).to.be.equal(-4000); - expect(gossipScoreThresholds.publishThreshold).to.be.equal(-8000); - expect(gossipScoreThresholds.graylistThreshold).to.be.equal(-16000); - expect(gossipScoreThresholds.acceptPXThreshold).to.be.equal(100); - expect(gossipScoreThresholds.opportunisticGraftThreshold).to.be.equal(5); + expect(gossipScoreThresholds.gossipThreshold).toEqual(-4000); + expect(gossipScoreThresholds.publishThreshold).toEqual(-8000); + expect(gossipScoreThresholds.graylistThreshold).toEqual(-16000); + expect(gossipScoreThresholds.acceptPXThreshold).toEqual(100); + expect(gossipScoreThresholds.opportunisticGraftThreshold).toEqual(5); const params = computeGossipPeerScoreParams({config, eth2Context}); const allTopics = params.topics; if (!allTopics) { @@ -49,11 +49,11 @@ describe("computeGossipPeerScoreParams", function () { currentSlot: 10_000, currentEpoch: Math.floor(10_000 / SLOTS_PER_EPOCH), }; - expect(gossipScoreThresholds.gossipThreshold).to.be.equal(-4000); - expect(gossipScoreThresholds.publishThreshold).to.be.equal(-8000); - expect(gossipScoreThresholds.graylistThreshold).to.be.equal(-16000); - expect(gossipScoreThresholds.acceptPXThreshold).to.be.equal(100); - expect(gossipScoreThresholds.opportunisticGraftThreshold).to.be.equal(5); + expect(gossipScoreThresholds.gossipThreshold).toEqual(-4000); + expect(gossipScoreThresholds.publishThreshold).toEqual(-8000); + expect(gossipScoreThresholds.graylistThreshold).toEqual(-16000); + expect(gossipScoreThresholds.acceptPXThreshold).toEqual(100); + expect(gossipScoreThresholds.opportunisticGraftThreshold).toEqual(5); const params = computeGossipPeerScoreParams({config, eth2Context}); const allTopics = params.topics; if (!allTopics) { @@ -73,10 +73,10 @@ describe("computeGossipPeerScoreParams", function () { }); const params = topics[topicString]; assertMessageRatePenaltiesDisabled(params); - expect(params.topicWeight).to.be.equal(0.05); + expect(params.topicWeight).toEqual(0.05); expect(params.timeInMeshWeight).closeTo(0.03333, TOLERANCE); - expect(params.timeInMeshQuantum).to.be.equal(12 * 1000); - expect(params.timeInMeshCap).to.be.equal(300); + expect(params.timeInMeshQuantum).toEqual(12 * 1000); + expect(params.timeInMeshCap).toEqual(300); expect(params.firstMessageDeliveriesWeight).closeTo(1.8407, TOLERANCE); expect(params.firstMessageDeliveriesDecay).closeTo(0.99856, TOLERANCE); expect(params.firstMessageDeliveriesCap).closeTo(21.73035, TOLERANCE); @@ -99,10 +99,10 @@ describe("computeGossipPeerScoreParams", function () { function validateSlashingTopicScoreParams(params: TopicScoreParams): void { assertMessageRatePenaltiesDisabled(params); - expect(params.topicWeight).to.be.equal(0.05); + expect(params.topicWeight).toEqual(0.05); expect(params.timeInMeshWeight).closeTo(0.03333, TOLERANCE); - expect(params.timeInMeshQuantum).to.be.equal(12 * 1000); - expect(params.timeInMeshCap).to.be.equal(300.0); + expect(params.timeInMeshQuantum).toEqual(12 * 1000); + expect(params.timeInMeshCap).toEqual(300.0); expect(params.firstMessageDeliveriesWeight).closeTo(36.81486, TOLERANCE); expect(params.firstMessageDeliveriesDecay).closeTo(0.998561, TOLERANCE); expect(params.firstMessageDeliveriesCap).closeTo(1.08652, TOLERANCE); @@ -117,10 +117,10 @@ describe("computeGossipPeerScoreParams", function () { }); const params = topics[topicString]; - expect(params.topicWeight).to.be.equal(0.5); + expect(params.topicWeight).toEqual(0.5); expect(params.timeInMeshWeight).closeTo(0.03333, TOLERANCE); - expect(params.timeInMeshQuantum).to.be.equal(12 * 1000); - expect(params.timeInMeshCap).to.be.equal(300.0); + expect(params.timeInMeshQuantum).toEqual(12 * 1000); + expect(params.timeInMeshCap).toEqual(300.0); expect(params.firstMessageDeliveriesWeight).closeTo(0.33509, TOLERANCE); expect(params.firstMessageDeliveriesDecay).closeTo(0.86596, TOLERANCE); expect(params.firstMessageDeliveriesCap).closeTo(119.3712, TOLERANCE); @@ -130,8 +130,8 @@ describe("computeGossipPeerScoreParams", function () { // Check message rate penalty params expect(params.meshMessageDeliveriesDecay).closeTo(0.930572, TOLERANCE); expect(params.meshMessageDeliveriesCap).closeTo(68.6255, TOLERANCE); - expect(params.meshMessageDeliveriesActivation).to.be.equal(384 * 1000); - expect(params.meshMessageDeliveriesWindow).to.be.equal(12 * 1000); + expect(params.meshMessageDeliveriesActivation).toEqual(384 * 1000); + expect(params.meshMessageDeliveriesWindow).toEqual(12 * 1000); expect(params.meshFailurePenaltyWeight).closeTo(-0.7474, TOLERANCE); expect(params.meshFailurePenaltyDecay).closeTo(0.93057, TOLERANCE); @@ -139,8 +139,8 @@ describe("computeGossipPeerScoreParams", function () { expect(params.meshMessageDeliveriesWeight).closeTo(-0.7474, TOLERANCE); expect(params.meshMessageDeliveriesThreshold).closeTo(17.15638, TOLERANCE); } else { - expect(params.meshMessageDeliveriesWeight).to.be.equal(0.0); - expect(params.meshMessageDeliveriesThreshold).to.be.equal(0.0); + expect(params.meshMessageDeliveriesWeight).toEqual(0.0); + expect(params.meshMessageDeliveriesThreshold).toEqual(0.0); } } @@ -151,10 +151,10 @@ describe("computeGossipPeerScoreParams", function () { }); const params = topics[topicString]; - expect(params.topicWeight).to.be.equal(0.5); + expect(params.topicWeight).toEqual(0.5); expect(params.timeInMeshWeight).closeTo(0.03333, TOLERANCE); - expect(params.timeInMeshQuantum).to.be.equal(12 * 1000); - expect(params.timeInMeshCap).to.be.equal(300.0); + expect(params.timeInMeshQuantum).toEqual(12 * 1000); + expect(params.timeInMeshCap).toEqual(300.0); expect(params.firstMessageDeliveriesWeight).closeTo(1.14716, TOLERANCE); expect(params.firstMessageDeliveriesDecay).closeTo(0.99283, TOLERANCE); expect(params.firstMessageDeliveriesCap).closeTo(34.8687, TOLERANCE); @@ -164,8 +164,8 @@ describe("computeGossipPeerScoreParams", function () { // Check message rate penalty params expect(params.meshMessageDeliveriesDecay).closeTo(0.97163, TOLERANCE); expect(params.meshMessageDeliveriesCap).closeTo(2.0547574, TOLERANCE); - expect(params.meshMessageDeliveriesActivation).to.be.equal(384 * 1000); - expect(params.meshMessageDeliveriesWindow).to.be.equal(12 * 1000); + expect(params.meshMessageDeliveriesActivation).toEqual(384 * 1000); + expect(params.meshMessageDeliveriesWindow).toEqual(12 * 1000); expect(params.meshFailurePenaltyWeight).closeTo(-468.9689, TOLERANCE); expect(params.meshFailurePenaltyDecay).closeTo(0.97163, TOLERANCE); @@ -173,8 +173,8 @@ describe("computeGossipPeerScoreParams", function () { expect(params.meshMessageDeliveriesWeight).closeTo(-468.9689, TOLERANCE); expect(params.meshMessageDeliveriesThreshold).closeTo(0.68491, TOLERANCE); } else { - expect(params.meshMessageDeliveriesWeight).to.be.equal(0.0); - expect(params.meshMessageDeliveriesThreshold).to.be.equal(0.0); + expect(params.meshMessageDeliveriesWeight).toEqual(0.0); + expect(params.meshMessageDeliveriesThreshold).toEqual(0.0); } } @@ -193,10 +193,10 @@ describe("computeGossipPeerScoreParams", function () { } function validateAllAttestationSubnetTopicScoreParams(params: TopicScoreParams, penaltiesActive: boolean): void { - expect(params.topicWeight).to.be.equal(0.015625); + expect(params.topicWeight).toEqual(0.015625); expect(params.timeInMeshWeight).closeTo(0.03333, TOLERANCE); - expect(params.timeInMeshQuantum).to.be.equal(12 * 1000); - expect(params.timeInMeshCap).to.be.equal(300.0); + expect(params.timeInMeshQuantum).toEqual(12 * 1000); + expect(params.timeInMeshCap).toEqual(300.0); expect(params.firstMessageDeliveriesWeight).closeTo(2.6807, TOLERANCE); expect(params.firstMessageDeliveriesDecay).closeTo(0.86596, TOLERANCE); expect(params.firstMessageDeliveriesCap).closeTo(14.9214, TOLERANCE); @@ -206,8 +206,8 @@ describe("computeGossipPeerScoreParams", function () { // Check message rate penalty params expect(params.meshMessageDeliveriesDecay).closeTo(0.96466, TOLERANCE); expect(params.meshMessageDeliveriesCap).closeTo(69.88248, TOLERANCE); - expect(params.meshMessageDeliveriesActivation).to.be.equal(204 * 1000); - expect(params.meshMessageDeliveriesWindow).to.be.equal(12 * 1000); + expect(params.meshMessageDeliveriesActivation).toEqual(204 * 1000); + expect(params.meshMessageDeliveriesWindow).toEqual(12 * 1000); expect(params.meshFailurePenaltyWeight).closeTo(-369.0421, TOLERANCE); expect(params.meshFailurePenaltyDecay).closeTo(0.96466, TOLERANCE); @@ -215,19 +215,19 @@ describe("computeGossipPeerScoreParams", function () { expect(params.meshMessageDeliveriesWeight).closeTo(-369.0421, TOLERANCE); expect(params.meshMessageDeliveriesThreshold).closeTo(4.367655, TOLERANCE); } else { - expect(params.meshMessageDeliveriesWeight).to.be.equal(0.0); - expect(params.meshMessageDeliveriesThreshold).to.be.equal(0.0); + expect(params.meshMessageDeliveriesWeight).toEqual(0.0); + expect(params.meshMessageDeliveriesThreshold).toEqual(0.0); } } }); function assertMessageRatePenaltiesDisabled(params: TopicScoreParams): void { - expect(params.meshMessageDeliveriesWeight).to.be.equal(0.0); - expect(params.meshMessageDeliveriesDecay).to.be.equal(0.0); - expect(params.meshMessageDeliveriesThreshold).to.be.equal(0.0); - expect(params.meshMessageDeliveriesCap).to.be.equal(0.0); - expect(params.meshFailurePenaltyWeight).to.be.equal(0.0); - expect(params.meshFailurePenaltyDecay).to.be.equal(0.0); - expect(params.meshMessageDeliveriesActivation).to.be.equal(0); - expect(params.meshMessageDeliveriesWindow).to.be.equal(0); + expect(params.meshMessageDeliveriesWeight).toEqual(0.0); + expect(params.meshMessageDeliveriesDecay).toEqual(0.0); + expect(params.meshMessageDeliveriesThreshold).toEqual(0.0); + expect(params.meshMessageDeliveriesCap).toEqual(0.0); + expect(params.meshFailurePenaltyWeight).toEqual(0.0); + expect(params.meshFailurePenaltyDecay).toEqual(0.0); + expect(params.meshMessageDeliveriesActivation).toEqual(0); + expect(params.meshMessageDeliveriesWindow).toEqual(0); } diff --git a/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts b/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts index b99d2417dd9d..af12ad3d80e8 100644 --- a/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/subnets/util.test.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {describe, it, expect} from "vitest"; import {bigIntToBytes} from "@lodestar/utils"; import {computeSubscribedSubnet} from "../../../../src/network/subnets/util.js"; @@ -61,7 +61,7 @@ describe("computeSubscribedSubnet", () => { for (const [index, {nodeId, epoch, expected}] of testCases.entries()) { it(`test case ${index}`, () => { // node is is of type uint256 = 32 bytes - expect(computeSubscribedSubnet(bigIntToBytes(BigInt(nodeId), 32, "be"), epoch)).to.deep.equal(expected); + expect(computeSubscribedSubnet(bigIntToBytes(BigInt(nodeId), 32, "be"), epoch)).toEqual(expected); }); } }); diff --git a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts index 29df90e8548d..28c8fe652e8a 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/beacon.test.ts @@ -1,35 +1,23 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import {describe, it, expect, beforeAll} from "vitest"; -import {config} from "@lodestar/config/default"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {getBeaconApi} from "../../../../../src/api/impl/beacon/index.js"; -import {setupApiImplTestServer, ApiImplTestModules} from "../../../../__mocks__/apiMocks.js"; -import {testLogger} from "../../../../utils/logger.js"; -import {MockedBeaconDb} from "../../../../__mocks__/mockedBeaconDb.js"; +import {Mutable} from "../../../../utils/types.js"; describe("beacon api implementation", function () { - const logger = testLogger(); - let dbStub: MockedBeaconDb; - let server: ApiImplTestModules; + let modules: ApiTestModules; + let api: ReturnType; beforeAll(function () { - server = setupApiImplTestServer(); - dbStub = new MockedBeaconDb(); + modules = getApiTestModules(); + api = getBeaconApi(modules); }); describe("getGenesis", function () { it("success", async function () { - const api = getBeaconApi({ - config, - chain: server.chainStub, - db: dbStub, - logger, - network: server.networkStub, - metrics: null, - }); - - /** eslint-disable @typescript-eslint/no-unsafe-member-access */ - (server.chainStub as any).genesisTime = 0; - (server.chainStub as any).genesisValidatorsRoot = Buffer.alloc(32); + (modules.chain as Mutable).genesisTime = 0; + (modules.chain as Mutable).genesisValidatorsRoot = + Buffer.alloc(32); const {data: genesis} = await api.getGenesis(); if (genesis === null || genesis === undefined) throw Error("Genesis is nullish"); expect(genesis.genesisForkVersion).toBeDefined(); diff --git a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts index 14853a8de9c4..d3d09f2a1fd6 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/blocks/getBlockHeaders.test.ts @@ -2,19 +2,21 @@ import {toHexString} from "@chainsafe/ssz"; import {describe, it, expect, beforeEach, vi, afterEach} from "vitest"; import {when} from "vitest-when"; import {ssz} from "@lodestar/types"; +import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; import {generateProtoBlock, generateSignedBlockAtSlot} from "../../../../../utils/typeGenerator.js"; -import {setupApiImplTestServer, ApiImplTestModules} from "../../../../../__mocks__/apiMocks.js"; +import {getBeaconBlockApi} from "../../../../../../src/api/impl/beacon/blocks/index.js"; describe("api - beacon - getBlockHeaders", function () { - let server: ApiImplTestModules; + let modules: ApiTestModules; + let api: ReturnType; const parentRoot = toHexString(Buffer.alloc(32, 1)); beforeEach(function () { - server = setupApiImplTestServer(); - server.chainStub.forkChoice = server.forkChoiceStub; + modules = getApiTestModules(); + api = getBeaconBlockApi(modules); - vi.spyOn(server.dbStub.block, "get"); - vi.spyOn(server.dbStub.blockArchive, "getByParentRoot"); + vi.spyOn(modules.db.block, "get"); + vi.spyOn(modules.db.blockArchive, "getByParentRoot"); }); afterEach(() => { @@ -22,11 +24,11 @@ describe("api - beacon - getBlockHeaders", function () { }); it.skip("no filters - assume head slot", async function () { - server.forkChoiceStub.getHead.mockReturnValue(generateProtoBlock({slot: 1})); - when(server.chainStub.getCanonicalBlockAtSlot) + modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 1})); + when(modules.chain.getCanonicalBlockAtSlot) .calledWith(1) .thenResolve({block: ssz.phase0.SignedBeaconBlock.defaultValue(), executionOptimistic: false}); - when(server.forkChoiceStub.getBlockSummariesAtSlot) + when(modules.forkChoice.getBlockSummariesAtSlot) .calledWith(1) .thenReturn([ generateProtoBlock(), @@ -39,92 +41,92 @@ describe("api - beacon - getBlockHeaders", function () { const blockFromDb3 = ssz.phase0.SignedBeaconBlock.defaultValue(); blockFromDb3.message.slot = 3; - server.dbStub.block.get.mockResolvedValue(blockFromDb3); + modules.db.block.get.mockResolvedValue(blockFromDb3); - server.dbStub.blockArchive.get.mockResolvedValue(null); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({}); + modules.db.blockArchive.get.mockResolvedValue(null); + const {data: blockHeaders} = await api.getBlockHeaders({}); expect(blockHeaders).not.toBeNull(); expect(blockHeaders.length).toBe(2); expect(blockHeaders.filter((header) => header.canonical).length).toBe(1); - expect(server.forkChoiceStub.getHead).toHaveBeenCalledTimes(1); - expect(server.chainStub.getCanonicalBlockAtSlot).toHaveBeenCalledTimes(1); - expect(server.forkChoiceStub.getBlockSummariesAtSlot).toHaveBeenCalledTimes(1); - expect(server.dbStub.block.get).toHaveBeenCalledTimes(1); + expect(modules.forkChoice.getHead).toHaveBeenCalledTimes(1); + expect(modules.chain.getCanonicalBlockAtSlot).toHaveBeenCalledTimes(1); + expect(modules.forkChoice.getBlockSummariesAtSlot).toHaveBeenCalledTimes(1); + expect(modules.db.block.get).toHaveBeenCalledTimes(1); }); it("future slot", async function () { - server.forkChoiceStub.getHead.mockReturnValue(generateProtoBlock({slot: 1})); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({slot: 2}); + modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 1})); + const {data: blockHeaders} = await api.getBlockHeaders({slot: 2}); expect(blockHeaders.length).toBe(0); }); it("finalized slot", async function () { - server.forkChoiceStub.getHead.mockReturnValue(generateProtoBlock({slot: 2})); - when(server.chainStub.getCanonicalBlockAtSlot) + modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 2})); + when(modules.chain.getCanonicalBlockAtSlot) .calledWith(0) .thenResolve({block: ssz.phase0.SignedBeaconBlock.defaultValue(), executionOptimistic: false}); - when(server.forkChoiceStub.getBlockSummariesAtSlot).calledWith(0).thenReturn([]); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({slot: 0}); + when(modules.forkChoice.getBlockSummariesAtSlot).calledWith(0).thenReturn([]); + const {data: blockHeaders} = await api.getBlockHeaders({slot: 0}); expect(blockHeaders.length).toBe(1); expect(blockHeaders[0].canonical).toBe(true); }); it("skip slot", async function () { - server.forkChoiceStub.getHead.mockReturnValue(generateProtoBlock({slot: 2})); - when(server.chainStub.getCanonicalBlockAtSlot).calledWith(0).thenResolve(null); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({slot: 0}); + modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: 2})); + when(modules.chain.getCanonicalBlockAtSlot).calledWith(0).thenResolve(null); + const {data: blockHeaders} = await api.getBlockHeaders({slot: 0}); expect(blockHeaders.length).toBe(0); }); it.skip("parent root filter - both finalized and non finalized results", async function () { - server.dbStub.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); - server.forkChoiceStub.getBlockSummariesByParentRoot.mockReturnValue([ + modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); + modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([ generateProtoBlock({slot: 2}), generateProtoBlock({slot: 1}), ]); const canonical = generateSignedBlockAtSlot(2); - when(server.forkChoiceStub.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); - when(server.forkChoiceStub.getCanonicalBlockAtSlot) + when(modules.forkChoice.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); + when(modules.forkChoice.getCanonicalBlockAtSlot) .calledWith(2) .thenReturn(generateProtoBlock({blockRoot: toHexString(ssz.phase0.BeaconBlock.hashTreeRoot(canonical.message))})); - server.dbStub.block.get.mockResolvedValue(generateSignedBlockAtSlot(1)); - server.dbStub.block.get.mockResolvedValue(generateSignedBlockAtSlot(2)); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({parentRoot}); + modules.db.block.get.mockResolvedValue(generateSignedBlockAtSlot(1)); + modules.db.block.get.mockResolvedValue(generateSignedBlockAtSlot(2)); + const {data: blockHeaders} = await api.getBlockHeaders({parentRoot}); expect(blockHeaders.length).toBe(3); expect(blockHeaders.filter((b) => b.canonical).length).toBe(2); }); it("parent root - no finalized block", async function () { - server.dbStub.blockArchive.getByParentRoot.mockResolvedValue(null); - server.forkChoiceStub.getBlockSummariesByParentRoot.mockReturnValue([generateProtoBlock({slot: 1})]); - when(server.forkChoiceStub.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); - server.dbStub.block.get.mockResolvedValue(generateSignedBlockAtSlot(1)); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({parentRoot}); + modules.db.blockArchive.getByParentRoot.mockResolvedValue(null); + modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([generateProtoBlock({slot: 1})]); + when(modules.forkChoice.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); + modules.db.block.get.mockResolvedValue(generateSignedBlockAtSlot(1)); + const {data: blockHeaders} = await api.getBlockHeaders({parentRoot}); expect(blockHeaders.length).toBe(1); }); it("parent root - no non finalized blocks", async function () { - server.dbStub.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); - server.forkChoiceStub.getBlockSummariesByParentRoot.mockReturnValue([]); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({parentRoot}); + modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); + modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([]); + const {data: blockHeaders} = await api.getBlockHeaders({parentRoot}); expect(blockHeaders.length).toBe(1); }); it("parent root + slot filter", async function () { - server.dbStub.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); - server.forkChoiceStub.getBlockSummariesByParentRoot.mockReturnValue([ + modules.db.blockArchive.getByParentRoot.mockResolvedValue(ssz.phase0.SignedBeaconBlock.defaultValue()); + modules.forkChoice.getBlockSummariesByParentRoot.mockReturnValue([ generateProtoBlock({slot: 2}), generateProtoBlock({slot: 1}), ]); const canonical = generateSignedBlockAtSlot(2); - when(server.forkChoiceStub.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); - when(server.forkChoiceStub.getCanonicalBlockAtSlot) + when(modules.forkChoice.getCanonicalBlockAtSlot).calledWith(1).thenReturn(generateProtoBlock()); + when(modules.forkChoice.getCanonicalBlockAtSlot) .calledWith(2) .thenReturn(generateProtoBlock({blockRoot: toHexString(ssz.phase0.BeaconBlock.hashTreeRoot(canonical.message))})); - server.dbStub.block.get.mockResolvedValueOnce(generateSignedBlockAtSlot(1)); - server.dbStub.block.get.mockResolvedValueOnce(generateSignedBlockAtSlot(2)); - const {data: blockHeaders} = await server.blockApi.getBlockHeaders({ + modules.db.block.get.mockResolvedValueOnce(generateSignedBlockAtSlot(1)); + modules.db.block.get.mockResolvedValueOnce(generateSignedBlockAtSlot(2)); + const {data: blockHeaders} = await api.getBlockHeaders({ parentRoot: toHexString(Buffer.alloc(32, 1)), slot: 1, }); diff --git a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts index 5b09df7195b2..6986df406bf0 100644 --- a/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts +++ b/packages/beacon-node/test/unit/api/impl/beacon/state/utils.test.ts @@ -102,7 +102,7 @@ describe("beacon state api utils", function () { }); }); - describe("getStateValidatorIndex", async function () { + describe("getStateValidatorIndex", () => { const state = generateCachedAltairState(); const pubkey2index = state.epochCtx.pubkey2index; diff --git a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts index d68f610d5c1f..27daaadae1fe 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/duties/proposer.test.ts @@ -1,57 +1,29 @@ import {describe, it, expect, beforeEach, vi} from "vitest"; import {config} from "@lodestar/config/default"; -import {ssz} from "@lodestar/types"; import {MAX_EFFECTIVE_BALANCE, SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ApiTestModules, getApiTestModules} from "../../../../../utils/api.js"; import {FAR_FUTURE_EPOCH} from "../../../../../../src/constants/index.js"; import {getValidatorApi} from "../../../../../../src/api/impl/validator/index.js"; -import {ApiModules} from "../../../../../../src/api/impl/types.js"; -import {generateState} from "../../../../../utils/state.js"; +import {generateState, zeroProtoBlock} from "../../../../../utils/state.js"; import {generateValidators} from "../../../../../utils/validator.js"; -import {setupApiImplTestServer, ApiImplTestModules} from "../../../../../__mocks__/apiMocks.js"; -import {testLogger} from "../../../../../utils/logger.js"; import {createCachedBeaconStateTest} from "../../../../../utils/cachedBeaconState.js"; -import {zeroProtoBlock} from "../../../../../utils/mocks/chain.js"; -import {MockedBeaconChain} from "../../../../../__mocks__/mockedBeaconChain.js"; -import {MockedBeaconDb} from "../../../../../__mocks__/mockedBeaconDb.js"; -import {MockedBeaconSync} from "../../../../../__mocks__/beaconSyncMock.js"; describe.skip("get proposers api impl", function () { - const logger = testLogger(); - - let chainStub: MockedBeaconChain, syncStub: MockedBeaconSync, dbStub: MockedBeaconDb; - let api: ReturnType; - let server: ApiImplTestModules; - let modules: ApiModules; + let modules: ApiTestModules; beforeEach(function () { - server = setupApiImplTestServer(); - chainStub = server.chainStub; - syncStub = server.syncStub; - chainStub.getCanonicalBlockAtSlot.mockResolvedValue({ - block: ssz.phase0.SignedBeaconBlock.defaultValue(), - executionOptimistic: false, - }); - dbStub = server.dbStub; - modules = { - chain: server.chainStub, - config, - db: server.dbStub, - logger, - network: server.networkStub, - sync: syncStub, - metrics: null, - }; + modules = getApiTestModules(); api = getValidatorApi(modules); - chainStub.forkChoice.getHead.mockReturnValue(zeroProtoBlock); + modules.forkChoice.getHead.mockReturnValue(zeroProtoBlock); }); it("should get proposers for next epoch", async function () { - syncStub.isSynced.mockReturnValue(true); - vi.spyOn(chainStub.clock, "currentEpoch", "get").mockReturnValue(0); - vi.spyOn(chainStub.clock, "currentSlot", "get").mockReturnValue(0); - dbStub.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); + modules.sync.isSynced.mockReturnValue(true); + vi.spyOn(modules.chain.clock, "currentEpoch", "get").mockReturnValue(0); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(0); + modules.db.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); const state = generateState( { slot: 0, @@ -66,23 +38,23 @@ describe.skip("get proposers api impl", function () { ); const cachedState = createCachedBeaconStateTest(state, config); - chainStub.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); + modules.chain.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); const stubGetNextBeaconProposer = vi.spyOn(cachedState.epochCtx, "getBeaconProposersNextEpoch"); const stubGetBeaconProposer = vi.spyOn(cachedState.epochCtx, "getBeaconProposer"); stubGetNextBeaconProposer.mockReturnValue([1]); const {data: result} = await api.getProposerDuties(1); expect(result.length).toBe(SLOTS_PER_EPOCH); // "stubGetBeaconProposer function should not have been called" - expect(stubGetNextBeaconProposer).toHaveBeenCalled(); + expect(stubGetNextBeaconProposer).toHaveBeenCalledWith(); // "stubGetBeaconProposer function should have been called" - expect(stubGetBeaconProposer).not.toHaveBeenCalled(); + expect(stubGetBeaconProposer).not.toHaveBeenCalledWith(); }); it("should have different proposer for current and next epoch", async function () { - syncStub.isSynced.mockReturnValue(true); - vi.spyOn(chainStub.clock, "currentEpoch", "get").mockReturnValue(0); - vi.spyOn(chainStub.clock, "currentSlot", "get").mockReturnValue(0); - dbStub.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); + modules.sync.isSynced.mockReturnValue(true); + vi.spyOn(modules.chain.clock, "currentEpoch", "get").mockReturnValue(0); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(0); + modules.db.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); const state = generateState( { slot: 0, @@ -96,7 +68,7 @@ describe.skip("get proposers api impl", function () { config ); const cachedState = createCachedBeaconStateTest(state, config); - chainStub.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); + modules.chain.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); const stubGetBeaconProposer = vi.spyOn(cachedState.epochCtx, "getBeaconProposer"); stubGetBeaconProposer.mockReturnValue(1); const {data: currentProposers} = await api.getProposerDuties(0); @@ -105,10 +77,10 @@ describe.skip("get proposers api impl", function () { }); it("should not get proposers for more than one epoch in the future", async function () { - syncStub.isSynced.mockReturnValue(true); - vi.spyOn(chainStub.clock, "currentEpoch", "get").mockReturnValue(0); - vi.spyOn(chainStub.clock, "currentSlot", "get").mockReturnValue(0); - dbStub.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); + modules.sync.isSynced.mockReturnValue(true); + vi.spyOn(modules.chain.clock, "currentEpoch", "get").mockReturnValue(0); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(0); + modules.db.block.get.mockResolvedValue({message: {stateRoot: Buffer.alloc(32)}} as any); const state = generateState( { slot: 0, @@ -122,9 +94,9 @@ describe.skip("get proposers api impl", function () { config ); const cachedState = createCachedBeaconStateTest(state, config); - chainStub.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); + modules.chain.getHeadStateAtCurrentEpoch.mockResolvedValue(cachedState); const stubGetBeaconProposer = vi.spyOn(cachedState.epochCtx, "getBeaconProposer"); await expect(stubGetBeaconProposer).rejects.toThrow(); - await expect(api.getProposerDuties(2), "calling getProposerDuties should throw").rejects.toThrow(); + await expect(api.getProposerDuties(2)).rejects.toThrow(); }); }); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts index f177bccc359a..9c426c677974 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceAttestationData.test.ts @@ -1,52 +1,35 @@ import {describe, it, expect, beforeEach, vi} from "vitest"; -import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; import {SyncState} from "../../../../../src/sync/interface.js"; -import {ApiModules} from "../../../../../src/api/impl/types.js"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; -import {testLogger} from "../../../../utils/logger.js"; -import {ApiImplTestModules, setupApiImplTestServer} from "../../../../__mocks__/apiMocks.js"; describe("api - validator - produceAttestationData", function () { - const logger = testLogger(); - let syncStub: ApiImplTestModules["syncStub"]; - let modules: ApiModules; - let server: ApiImplTestModules; + let modules: ApiTestModules; + let api: ReturnType; beforeEach(function () { - server = setupApiImplTestServer(); - syncStub = server.syncStub; - modules = { - chain: server.chainStub, - config, - db: server.dbStub, - logger, - network: server.networkStub, - sync: syncStub, - metrics: null, - }; + modules = getApiTestModules(); + api = getValidatorApi(modules); }); it("Should throw when node is not synced", async function () { // Set the node's state to way back from current slot const currentSlot = 100000; const headSlot = 0; - vi.spyOn(server.chainStub.clock, "currentSlot", "get").mockReturnValue(currentSlot); - vi.spyOn(syncStub, "state", "get").mockReturnValue(SyncState.SyncingFinalized); - server.chainStub.forkChoice.getHead.mockReturnValue({slot: headSlot} as ProtoBlock); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.SyncingFinalized); + modules.forkChoice.getHead.mockReturnValue({slot: headSlot} as ProtoBlock); - // Should not allow any call to validator API - const api = getValidatorApi(modules); await expect(api.produceAttestationData(0, 0)).rejects.toThrow("Node is syncing"); }); it("Should throw error when node is stopped", async function () { const currentSlot = 100000; - vi.spyOn(server.chainStub.clock, "currentSlot", "get").mockReturnValue(currentSlot); - vi.spyOn(syncStub, "state", "get").mockReturnValue(SyncState.Stalled); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Stalled); // Should not allow any call to validator API - const api = getValidatorApi(modules); await expect(api.produceAttestationData(0, 0)).rejects.toThrow("Node is syncing - waiting for peers"); }); }); diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts index 56913e241e3b..deb148d34b5a 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV2.test.ts @@ -1,56 +1,29 @@ import {fromHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, afterEach, MockedObject, vi} from "vitest"; +import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {ssz} from "@lodestar/types"; -import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ForkName} from "@lodestar/params"; import {computeTimeAtSlot, CachedBeaconStateBellatrix} from "@lodestar/state-transition"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {SyncState} from "../../../../../src/sync/interface.js"; -import {ApiModules} from "../../../../../src/api/impl/types.js"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; -import {testLogger} from "../../../../utils/logger.js"; -import {ApiImplTestModules, setupApiImplTestServer} from "../../../../__mocks__/apiMocks.js"; import {BeaconChain} from "../../../../../src/chain/index.js"; import {generateCachedBellatrixState} from "../../../../utils/state.js"; -import {ExecutionEngineHttp} from "../../../../../src/execution/engine/http.js"; import {PayloadIdCache} from "../../../../../src/execution/engine/payloadIdCache.js"; import {toGraffitiBuffer} from "../../../../../src/util/graffiti.js"; import {BlockType, produceBlockBody} from "../../../../../src/chain/produceBlock/produceBlockBody.js"; import {generateProtoBlock} from "../../../../utils/typeGenerator.js"; import {ZERO_HASH_HEX} from "../../../../../src/constants/index.js"; -import {OpPool} from "../../../../../src/chain/opPools/opPool.js"; -import {AggregatedAttestationPool} from "../../../../../src/chain/opPools/index.js"; -import {Eth1ForBlockProduction} from "../../../../../src/eth1/index.js"; -import {BeaconProposerCache} from "../../../../../src/chain/beaconProposerCache.js"; describe("api/validator - produceBlockV2", function () { - const logger = testLogger(); - - let modules: ApiModules; - let server: ApiImplTestModules; - - let chainStub: ApiImplTestModules["chainStub"]; - let forkChoiceStub: ApiImplTestModules["forkChoiceStub"]; - let executionEngineStub: MockedObject; - let opPoolStub: MockedObject; - let aggregatedAttestationPoolStub: MockedObject; - let eth1Stub: MockedObject; - let syncStub: ApiImplTestModules["syncStub"]; + let api: ReturnType; + let modules: ApiTestModules; let state: CachedBeaconStateBellatrix; - let beaconProposerCacheStub: MockedObject; beforeEach(() => { - server = setupApiImplTestServer(); - chainStub = server.chainStub; - forkChoiceStub = server.chainStub.forkChoice; - executionEngineStub = server.chainStub.executionEngine; - opPoolStub = server.chainStub.opPool; - aggregatedAttestationPoolStub = server.chainStub.aggregatedAttestationPool; - eth1Stub = server.chainStub.eth1; - syncStub = server.syncStub; - beaconProposerCacheStub = server.chainStub.beaconProposerCache; - - // server.chainStub.logger = logger; + modules = getApiTestModules(); + api = getValidatorApi(modules); + state = generateCachedBellatrixState(); }); @@ -59,24 +32,13 @@ describe("api/validator - produceBlockV2", function () { }); it("correctly pass feeRecipient to produceBlock", async function () { - syncStub = server.syncStub; - modules = { - chain: server.chainStub, - config, - db: server.dbStub, - logger, - network: server.networkStub, - sync: syncStub, - metrics: null, - }; - const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); const executionPayloadValue = ssz.Wei.defaultValue(); const consensusBlockValue = ssz.Wei.defaultValue(); const currentSlot = 100000; - vi.spyOn(server.chainStub.clock, "currentSlot", "get").mockReturnValue(currentSlot); - vi.spyOn(syncStub, "state", "get").mockReturnValue(SyncState.Synced); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); // Set the node's state to way back from current slot const slot = 100000; @@ -84,8 +46,7 @@ describe("api/validator - produceBlockV2", function () { const graffiti = "a".repeat(32); const feeRecipient = "0xcccccccccccccccccccccccccccccccccccccccc"; - const api = getValidatorApi(modules); - server.chainStub.produceBlock.mockResolvedValue({ + modules.chain.produceBlock.mockResolvedValue({ block: fullBlock, executionPayloadValue, consensusBlockValue, @@ -93,7 +54,7 @@ describe("api/validator - produceBlockV2", function () { // check if expectedFeeRecipient is passed to produceBlock await api.produceBlockV2(slot, randaoReveal, graffiti, {feeRecipient}); - expect(server.chainStub.produceBlock).toBeCalledWith({ + expect(modules.chain.produceBlock).toBeCalledWith({ randaoReveal, graffiti: toGraffitiBuffer(graffiti), slot, @@ -103,7 +64,7 @@ describe("api/validator - produceBlockV2", function () { // check that no feeRecipient is passed to produceBlock so that produceBlockBody will // pick it from beaconProposerCache await api.produceBlockV2(slot, randaoReveal, graffiti); - expect(server.chainStub.produceBlock).toBeCalledWith({ + expect(modules.chain.produceBlock).toBeCalledWith({ randaoReveal, graffiti: toGraffitiBuffer(graffiti), slot, @@ -120,23 +81,26 @@ describe("api/validator - produceBlockV2", function () { const feeRecipient = "0xccccccccccccccccccccccccccccccccccccccaa"; const headSlot = 0; - forkChoiceStub.getHead.mockReturnValue(generateProtoBlock({slot: headSlot})); + modules.forkChoice.getHead.mockReturnValue(generateProtoBlock({slot: headSlot})); - opPoolStub.getSlashingsAndExits.mockReturnValue([[], [], [], []]); - aggregatedAttestationPoolStub.getAttestationsForBlock.mockReturnValue([]); - eth1Stub.getEth1DataAndDeposits.mockResolvedValue({eth1Data: ssz.phase0.Eth1Data.defaultValue(), deposits: []}); - forkChoiceStub.getJustifiedBlock.mockReturnValue({} as ProtoBlock); - forkChoiceStub.getFinalizedBlock.mockReturnValue({} as ProtoBlock); - (executionEngineStub as unknown as {payloadIdCache: PayloadIdCache}).payloadIdCache = new PayloadIdCache(); + modules.chain["opPool"].getSlashingsAndExits.mockReturnValue([[], [], [], []]); + modules.chain["aggregatedAttestationPool"].getAttestationsForBlock.mockReturnValue([]); + modules.chain["eth1"].getEth1DataAndDeposits.mockResolvedValue({ + eth1Data: ssz.phase0.Eth1Data.defaultValue(), + deposits: [], + }); + modules.forkChoice.getJustifiedBlock.mockReturnValue({} as ProtoBlock); + modules.forkChoice.getFinalizedBlock.mockReturnValue({} as ProtoBlock); - executionEngineStub.notifyForkchoiceUpdate.mockResolvedValue("0x"); - executionEngineStub.getPayload.mockResolvedValue({ + modules.chain["executionEngine"].payloadIdCache = new PayloadIdCache(); + modules.chain["executionEngine"].notifyForkchoiceUpdate.mockResolvedValue("0x"); + modules.chain["executionEngine"].getPayload.mockResolvedValue({ executionPayload: ssz.bellatrix.ExecutionPayload.defaultValue(), executionPayloadValue, }); // use fee recipient passed in produceBlockBody call for payload gen in engine notifyForkchoiceUpdate - await produceBlockBody.call(chainStub as unknown as BeaconChain, BlockType.Full, state, { + await produceBlockBody.call(modules.chain as unknown as BeaconChain, BlockType.Full, state, { randaoReveal, graffiti: toGraffitiBuffer(graffiti), slot, @@ -147,21 +111,21 @@ describe("api/validator - produceBlockV2", function () { proposerPubKey: Uint8Array.from(Buffer.alloc(32, 1)), }); - expect(executionEngineStub.notifyForkchoiceUpdate).toBeCalledWith( + expect(modules.chain["executionEngine"].notifyForkchoiceUpdate).toBeCalledWith( ForkName.bellatrix, ZERO_HASH_HEX, ZERO_HASH_HEX, ZERO_HASH_HEX, { - timestamp: computeTimeAtSlot(chainStub.config, state.slot, state.genesisTime), + timestamp: computeTimeAtSlot(modules.config, state.slot, state.genesisTime), prevRandao: Uint8Array.from(Buffer.alloc(32, 0)), suggestedFeeRecipient: feeRecipient, } ); // use fee recipient set in beaconProposerCacheStub if none passed - beaconProposerCacheStub.getOrDefault.mockReturnValue("0x fee recipient address"); - await produceBlockBody.call(chainStub as unknown as BeaconChain, BlockType.Full, state, { + modules.chain["beaconProposerCache"].getOrDefault.mockReturnValue("0x fee recipient address"); + await produceBlockBody.call(modules.chain as unknown as BeaconChain, BlockType.Full, state, { randaoReveal, graffiti: toGraffitiBuffer(graffiti), slot, @@ -171,13 +135,13 @@ describe("api/validator - produceBlockV2", function () { proposerPubKey: Uint8Array.from(Buffer.alloc(32, 1)), }); - expect(executionEngineStub.notifyForkchoiceUpdate).toBeCalledWith( + expect(modules.chain["executionEngine"].notifyForkchoiceUpdate).toBeCalledWith( ForkName.bellatrix, ZERO_HASH_HEX, ZERO_HASH_HEX, ZERO_HASH_HEX, { - timestamp: computeTimeAtSlot(chainStub.config, state.slot, state.genesisTime), + timestamp: computeTimeAtSlot(modules.config, state.slot, state.genesisTime), prevRandao: Uint8Array.from(Buffer.alloc(32, 0)), suggestedFeeRecipient: "0x fee recipient address", } diff --git a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts index f1aa2cb791df..4484bcf03563 100644 --- a/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts +++ b/packages/beacon-node/test/unit/api/impl/validator/produceBlockV3.test.ts @@ -1,26 +1,17 @@ -import {describe, it, expect, beforeEach, afterEach, MockedObject, vi} from "vitest"; +import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; import {ssz} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {routes} from "@lodestar/api"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {ApiTestModules, getApiTestModules} from "../../../../utils/api.js"; import {SyncState} from "../../../../../src/sync/interface.js"; -import {ApiModules} from "../../../../../src/api/impl/types.js"; import {getValidatorApi} from "../../../../../src/api/impl/validator/index.js"; -import {testLogger} from "../../../../utils/logger.js"; -import {ApiImplTestModules, setupApiImplTestServer} from "../../../../__mocks__/apiMocks.js"; -import {ExecutionBuilderHttp} from "../../../../../src/execution/builder/http.js"; import {CommonBlockBody} from "../../../../../src/chain/interface.js"; /* eslint-disable @typescript-eslint/naming-convention */ describe("api/validator - produceBlockV3", function () { - const logger = testLogger(); - - let modules: ApiModules; - let server: ApiImplTestModules; - - let chainStub: ApiImplTestModules["chainStub"]; - let executionBuilderStub: MockedObject; - let syncStub: ApiImplTestModules["syncStub"]; + let modules: ApiTestModules; + let api: ReturnType; const chainConfig = createChainForkConfig({ ...defaultChainConfig, @@ -31,13 +22,12 @@ describe("api/validator - produceBlockV3", function () { const config = createBeaconConfig(chainConfig, genesisValidatorsRoot); beforeEach(() => { - server = setupApiImplTestServer(); - chainStub = server.chainStub; - executionBuilderStub = server.chainStub.executionBuilder; - syncStub = server.syncStub; + modules = getApiTestModules(); + api = getValidatorApi({...modules, config}); - executionBuilderStub.status = true; + modules.chain.executionBuilder.status = true; }); + afterEach(() => { vi.clearAllMocks(); }); @@ -75,17 +65,6 @@ describe("api/validator - produceBlockV3", function () { finalSelection, ]) => { it(`produceBlockV3 - ${finalSelection} produces block`, async () => { - syncStub = server.syncStub; - modules = { - chain: server.chainStub, - config, - db: server.dbStub, - logger, - network: server.networkStub, - sync: syncStub, - metrics: null, - }; - const fullBlock = ssz.bellatrix.BeaconBlock.defaultValue(); const blindedBlock = ssz.bellatrix.BlindedBeaconBlock.defaultValue(); @@ -95,10 +74,8 @@ describe("api/validator - produceBlockV3", function () { const feeRecipient = "0xccccccccccccccccccccccccccccccccccccccaa"; const currentSlot = 1 * SLOTS_PER_EPOCH; - vi.spyOn(server.chainStub.clock, "currentSlot", "get").mockReturnValue(currentSlot); - vi.spyOn(syncStub, "state", "get").mockReturnValue(SyncState.Synced); - - const api = getValidatorApi(modules); + vi.spyOn(modules.chain.clock, "currentSlot", "get").mockReturnValue(currentSlot); + vi.spyOn(modules.sync, "state", "get").mockReturnValue(SyncState.Synced); if (enginePayloadValue !== null) { const commonBlockBody: CommonBlockBody = { @@ -114,26 +91,26 @@ describe("api/validator - produceBlockV3", function () { syncAggregate: fullBlock.body.syncAggregate, }; - chainStub.produceCommonBlockBody.mockResolvedValue(commonBlockBody); + modules.chain.produceCommonBlockBody.mockResolvedValue(commonBlockBody); - chainStub.produceBlock.mockResolvedValue({ + modules.chain.produceBlock.mockResolvedValue({ block: fullBlock, executionPayloadValue: BigInt(enginePayloadValue), consensusBlockValue: BigInt(consensusBlockValue), shouldOverrideBuilder, }); } else { - chainStub.produceBlock.mockRejectedValue(Error("not produced")); + modules.chain.produceBlock.mockRejectedValue(Error("not produced")); } if (builderPayloadValue !== null) { - chainStub.produceBlindedBlock.mockResolvedValue({ + modules.chain.produceBlindedBlock.mockResolvedValue({ block: blindedBlock, executionPayloadValue: BigInt(builderPayloadValue), consensusBlockValue: BigInt(consensusBlockValue), }); } else { - chainStub.produceBlindedBlock.mockRejectedValue(Error("not produced")); + modules.chain.produceBlindedBlock.mockRejectedValue(Error("not produced")); } const _skipRandaoVerification = false; const produceBlockOpts = { @@ -152,15 +129,15 @@ describe("api/validator - produceBlockV3", function () { // check call counts if (builderSelection === routes.validator.BuilderSelection.ExecutionOnly) { - expect(chainStub.produceBlindedBlock).toBeCalledTimes(0); + expect(modules.chain.produceBlindedBlock).toBeCalledTimes(0); } else { - expect(chainStub.produceBlindedBlock).toBeCalledTimes(1); + expect(modules.chain.produceBlindedBlock).toBeCalledTimes(1); } if (builderSelection === routes.validator.BuilderSelection.BuilderOnly) { - expect(chainStub.produceBlock).toBeCalledTimes(0); + expect(modules.chain.produceBlock).toBeCalledTimes(0); } else { - expect(chainStub.produceBlock).toBeCalledTimes(1); + expect(modules.chain.produceBlock).toBeCalledTimes(1); } }); } diff --git a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts index 4abcd3e59ae8..d9c3b93a76ee 100644 --- a/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts +++ b/packages/beacon-node/test/unit/chain/archive/blockArchiver.test.ts @@ -6,8 +6,8 @@ import {ZERO_HASH_HEX} from "../../../../src/constants/index.js"; import {generateProtoBlock} from "../../../utils/typeGenerator.js"; import {testLogger} from "../../../utils/logger.js"; import {archiveBlocks} from "../../../../src/chain/archiver/archiveBlocks.js"; -import {MockedBeaconDb, getMockedBeaconDb} from "../../../__mocks__/mockedBeaconDb.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; +import {MockedBeaconDb, getMockedBeaconDb} from "../../../mocks/mockedBeaconDb.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("block archiver task", function () { const logger = testLogger(); diff --git a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts index 1035d6e417fb..71ab5688a602 100644 --- a/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts +++ b/packages/beacon-node/test/unit/chain/blocks/verifyBlocksSanityChecks.test.ts @@ -9,9 +9,9 @@ import {verifyBlocksSanityChecks as verifyBlocksImportSanityChecks} from "../../ import {BlockErrorCode} from "../../../../src/chain/errors/index.js"; import {expectThrowsLodestarError} from "../../../utils/errors.js"; import {IClock} from "../../../../src/util/clock.js"; -import {ClockStopped} from "../../../utils/mocks/clock.js"; +import {ClockStopped} from "../../../mocks/clock.js"; import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("chain / blocks / verifyBlocksSanityChecks", function () { let forkChoice: MockedBeaconChain["forkChoice"]; diff --git a/packages/beacon-node/test/unit/chain/bls/bls.test.ts b/packages/beacon-node/test/unit/chain/bls/bls.test.ts index 763ba71d379f..e5b844262632 100644 --- a/packages/beacon-node/test/unit/chain/bls/bls.test.ts +++ b/packages/beacon-node/test/unit/chain/bls/bls.test.ts @@ -46,7 +46,7 @@ describe("BlsVerifier ", function () { it("should return false if at least one signature is malformed", async () => { // signature is malformed const malformedSignature = Buffer.alloc(96, 10); - expect(() => bls.Signature.fromBytes(malformedSignature, CoordType.affine, true)).to.throws(); + expect(() => bls.Signature.fromBytes(malformedSignature, CoordType.affine, true)).toThrow(); sets[1].signature = malformedSignature; expect(await verifier.verifySignatureSets(sets)).toBe(false); }); @@ -79,7 +79,7 @@ describe("BlsVerifier ", function () { it("should return false for malformed signature", async () => { // signature is malformed const malformedSignature = Buffer.alloc(96, 10); - expect(() => bls.Signature.fromBytes(malformedSignature, CoordType.affine, true)).to.throws(); + expect(() => bls.Signature.fromBytes(malformedSignature, CoordType.affine, true)).toThrow(); sets[1].signature = malformedSignature; expect(await verifier.verifySignatureSetsSameMessage(sets, signingRoot)).toEqual([true, false, true]); }); diff --git a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts index 76b2aab29abb..20b6fc8d7a00 100644 --- a/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts +++ b/packages/beacon-node/test/unit/chain/forkChoice/forkChoice.test.ts @@ -1,5 +1,5 @@ import {toHexString} from "@chainsafe/ssz"; -import {describe, it, expect, beforeEach, beforeAll} from "vitest"; +import {describe, it, expect, beforeEach, beforeAll, vi} from "vitest"; import {config} from "@lodestar/config/default"; import {CheckpointWithHex, ExecutionStatus, ForkChoice} from "@lodestar/fork-choice"; import {FAR_FUTURE_EPOCH, MAX_EFFECTIVE_BALANCE} from "@lodestar/params"; @@ -16,6 +16,9 @@ import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; import {generateState} from "../../../utils/state.js"; import {generateValidators} from "../../../utils/validator.js"; +// We mock this package globally +vi.unmock("@lodestar/fork-choice"); + describe("LodestarForkChoice", function () { let forkChoice: ForkChoice; const anchorState = createCachedBeaconStateTest( @@ -86,7 +89,6 @@ describe("LodestarForkChoice", function () { const parentBlockHex = ssz.phase0.BeaconBlock.hashTreeRoot(parentBlock.message); const orphanedBlockHex = ssz.phase0.BeaconBlock.hashTreeRoot(orphanedBlock.message); // forkchoice tie-break condition is based on root hex - // eslint-disable-next-line chai-expect/no-inner-compare expect(orphanedBlockHex > parentBlockHex).toBe(true); const currentSlot = childBlock.message.slot; forkChoice.updateTime(currentSlot); diff --git a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts index b181aa1c1292..48abfbc35675 100644 --- a/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts +++ b/packages/beacon-node/test/unit/chain/opPools/aggregatedAttestationPool.test.ts @@ -5,6 +5,7 @@ import {describe, it, expect, beforeEach, beforeAll, afterEach, vi} from "vitest import {CachedBeaconStateAllForks} from "@lodestar/state-transition"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {ssz, phase0} from "@lodestar/types"; +import {MockedForkChoice, getMockedForkChoice} from "../../../mocks/mockedBeaconChain.js"; import { AggregatedAttestationPool, aggregateInto, @@ -17,7 +18,6 @@ import {generateCachedAltairState} from "../../../utils/state.js"; import {renderBitArray} from "../../../utils/render.js"; import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; import {generateProtoBlock} from "../../../utils/typeGenerator.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; /** Valid signature of random data to prevent BLS errors */ const validSignature = fromHexString( @@ -38,12 +38,12 @@ describe("AggregatedAttestationPool", function () { const attDataRootHex = toHexString(ssz.phase0.AttestationData.hashTreeRoot(attestation.data)); const committee = [0, 1, 2, 3]; - let forkchoiceStub: MockedBeaconChain["forkChoice"]; + let forkchoiceStub: MockedForkChoice; beforeEach(() => { pool = new AggregatedAttestationPool(); altairState = originalState.clone(); - forkchoiceStub = getMockedBeaconChain().forkChoice; + forkchoiceStub = getMockedForkChoice(); }); afterEach(() => { diff --git a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts index f4fa68609015..6d1be3fa8dd5 100644 --- a/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts +++ b/packages/beacon-node/test/unit/chain/prepareNextSlot.test.ts @@ -3,13 +3,12 @@ import {config} from "@lodestar/config/default"; import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {routes} from "@lodestar/api"; import {ProtoBlock} from "@lodestar/fork-choice"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; +import {MockedLogger, getMockedLogger} from "../../mocks/loggerMock.js"; import {IChainOptions} from "../../../src/chain/options.js"; import {PrepareNextSlotScheduler} from "../../../src/chain/prepareNextSlot.js"; -import {generateCachedBellatrixState} from "../../utils/state.js"; +import {generateCachedBellatrixState, zeroProtoBlock} from "../../utils/state.js"; import {PayloadIdCache} from "../../../src/execution/engine/payloadIdCache.js"; -import {zeroProtoBlock} from "../../utils/mocks/chain.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../__mocks__/mockedBeaconChain.js"; -import {MockedLogger, getMockedLogger} from "../../__mocks__/loggerMock.js"; describe("PrepareNextSlot scheduler", () => { const abortController = new AbortController(); @@ -62,7 +61,7 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(2 * SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); expect(regenStub.getBlockSlotState).not.toHaveBeenCalled(); }); @@ -74,8 +73,8 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); - expect(regenStub.getBlockSlotState).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); + expect(regenStub.getBlockSlotState).toHaveBeenCalledOnce(); }); it("pre bellatrix - should handle regen.getBlockSlotState error", async () => { @@ -87,8 +86,8 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); - expect(regenStub.getBlockSlotState).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); + expect(regenStub.getBlockSlotState).toHaveBeenCalledOnce(); expect(loggerStub.error).toHaveBeenCalledTimes(1); }); @@ -99,7 +98,7 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(2 * SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledWith(); expect(regenStub.getBlockSlotState).not.toHaveBeenCalled(); }); @@ -112,8 +111,8 @@ describe("PrepareNextSlot scheduler", () => { scheduler.prepareForNextSlot(SLOTS_PER_EPOCH - 1), vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); - expect(regenStub.getBlockSlotState).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); + expect(regenStub.getBlockSlotState).toHaveBeenCalledOnce(); }); it("bellatrix - should prepare payload", async () => { @@ -135,11 +134,11 @@ describe("PrepareNextSlot scheduler", () => { vi.advanceTimersByTimeAsync((config.SECONDS_PER_SLOT * 1000 * 2) / 3), ]); - expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalled(); - expect(regenStub.getBlockSlotState).toHaveBeenCalled(); - expect(updateBuilderStatus).toHaveBeenCalled(); - expect(forkChoiceStub.getJustifiedBlock).toHaveBeenCalled(); - expect(forkChoiceStub.getFinalizedBlock).toHaveBeenCalled(); + expect(chainStub.recomputeForkChoiceHead).toHaveBeenCalledOnce(); + expect(regenStub.getBlockSlotState).toHaveBeenCalledOnce(); + expect(updateBuilderStatus).toHaveBeenCalledOnce(); + expect(forkChoiceStub.getJustifiedBlock).toHaveBeenCalledOnce(); + expect(forkChoiceStub.getFinalizedBlock).toHaveBeenCalledOnce(); expect(executionEngineStub.notifyForkchoiceUpdate).toHaveBeenCalledTimes(1); expect(spy).toHaveBeenCalledTimes(1); }); diff --git a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts index c389e1b81e70..16af7b0df10e 100644 --- a/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts +++ b/packages/beacon-node/test/unit/chain/seenCache/seenGossipBlockInput.test.ts @@ -114,16 +114,16 @@ describe("SeenGossipBlockInput", () => { if (expectedResponseType instanceof Error) { expect.fail(`expected to fail with error: ${expectedResponseType.message}`); } else if (expectedResponseType === null) { - expect(blockInputRes).toBeNull; + expect(blockInputRes).toBeNull(); } else { - expect(blockInputRes.blockInput?.type).to.be.equal(expectedResponseType); + expect(blockInputRes.blockInput?.type).toEqual(expectedResponseType); } } else { const index = parseInt(inputEvent.split("blob")[1] ?? "0"); const blobSidecar = blobSidecars[index]; - expect(blobSidecar).not.equal(undefined); + expect(blobSidecar).not.toBeUndefined(); - const blockInputRes = seenGossipBlockInput.getGossipBlockInput(config, { + const blobInputRes = seenGossipBlockInput.getGossipBlockInput(config, { type: GossipedInputType.blob, blobSidecar, blobBytes: null, @@ -132,16 +132,17 @@ describe("SeenGossipBlockInput", () => { if (expectedResponseType instanceof Error) { expect.fail(`expected to fail with error: ${expectedResponseType.message}`); } else if (expectedResponseType === null) { - expect(blockInputRes).toBeNull; + expect(blobInputRes.blockInput).toBeNull(); + expect(blobInputRes.blockInputMeta.expectedBlobs).toBeNull(); } else { - expect(blockInputRes.blockInput?.type).to.equal(expectedResponseType); + expect(blobInputRes.blockInput?.type).toEqual(expectedResponseType); } } } catch (e) { if (!(e as Error).message.includes("expected to fail with error")) { if (!(expectedResponseType instanceof Error)) { expect.fail( - `expected not to fail with respose=${expectedResponseType} but errored: ${(e as Error).message}` + `expected not to fail with response=${expectedResponseType} but errored: ${(e as Error).message}` ); } } diff --git a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts index 186739ff2475..6295a993c072 100644 --- a/packages/beacon-node/test/unit/chain/shufflingCache.test.ts +++ b/packages/beacon-node/test/unit/chain/shufflingCache.test.ts @@ -19,19 +19,19 @@ describe("ShufflingCache", function () { it("should get shuffling from cache", async function () { const decisionRoot = getShufflingDecisionBlock(state, currentEpoch); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).to.deep.equal(state.epochCtx.currentShuffling); + expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); }); it("should bound by maxSize(=1)", async function () { const decisionRoot = getShufflingDecisionBlock(state, currentEpoch); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).to.deep.equal(state.epochCtx.currentShuffling); + expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert promises at the same epoch does not prune the cache shufflingCache.insertPromise(currentEpoch, "0x00"); - expect(await shufflingCache.get(currentEpoch, decisionRoot)).to.deep.equal(state.epochCtx.currentShuffling); + expect(await shufflingCache.get(currentEpoch, decisionRoot)).toEqual(state.epochCtx.currentShuffling); // insert shufflings at other epochs does prune the cache shufflingCache.processState(state, currentEpoch + 1); // the current shuffling is not available anymore - expect(await shufflingCache.get(currentEpoch, decisionRoot)).to.be.null; + expect(await shufflingCache.get(currentEpoch, decisionRoot)).toBeNull(); }); it("should return shuffling from promise", async function () { @@ -40,8 +40,8 @@ describe("ShufflingCache", function () { const shufflingRequest0 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); const shufflingRequest1 = shufflingCache.get(currentEpoch + 1, nextDecisionRoot); shufflingCache.processState(state, currentEpoch + 1); - expect(await shufflingRequest0).to.deep.equal(state.epochCtx.nextShuffling); - expect(await shufflingRequest1).to.deep.equal(state.epochCtx.nextShuffling); + expect(await shufflingRequest0).toEqual(state.epochCtx.nextShuffling); + expect(await shufflingRequest1).toEqual(state.epochCtx.nextShuffling); }); it("should support up to 2 promises at a time", async function () { @@ -49,6 +49,6 @@ describe("ShufflingCache", function () { shufflingCache.insertPromise(currentEpoch, "0x00"); shufflingCache.insertPromise(currentEpoch, "0x01"); // inserting other promise should throw error - expect(() => shufflingCache.insertPromise(currentEpoch, "0x02")).to.throw(); + expect(() => shufflingCache.insertPromise(currentEpoch, "0x02")).toThrow(); }); }); diff --git a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts index 62f2bff13d19..4628b1b07220 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/fifoBlockStateCache.test.ts @@ -91,15 +91,15 @@ describe("FIFOBlockStateCache", function () { it(name, () => { // move to head this state cache.setHeadState(headState); - expect(cache.size).to.be.equal(2, "Size must be same as initial 2"); + expect(cache.size).toEqualWithMessage(2, "Size must be same as initial 2"); for (const addAsHead of addAsHeadArr) { cache.add(state3, addAsHead); } - expect(cache.size).to.be.equal(2, "Size should reduce to initial 2 after prunning"); + expect(cache.size).toEqualWithMessage(2, "Size should reduce to initial 2 after prunning"); expect(cache.dumpKeyOrder()).toEqual(keptStates); expect(cache.get(prunedState)).toBeNull(); for (const key of keptStates) { - expect(cache.get(key), `must have key ${key}`).to.be.not.null; + expect(cache.get(key)).not.toBeNull(); } }); } diff --git a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts index 18bdfac89793..9c37b863623d 100644 --- a/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts +++ b/packages/beacon-node/test/unit/chain/stateCache/persistentCheckpointsCache.test.ts @@ -99,15 +99,15 @@ describe("PersistentCheckpointStateCache", function () { // cp0 expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch)?.hashTreeRoot()).toEqual(states["cp0a"].hashTreeRoot()); expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch + 1)?.hashTreeRoot()).toEqual(states["cp0a"].hashTreeRoot()); - expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch - 1)?.hashTreeRoot()).to.be.undefined; + expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch - 1)?.hashTreeRoot()).toBeUndefined(); // cp1 expect(cache.getLatest(cp1Hex.rootHex, cp1.epoch)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); expect(cache.getLatest(cp1Hex.rootHex, cp1.epoch + 1)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); - expect(cache.getLatest(cp1Hex.rootHex, cp1.epoch - 1)?.hashTreeRoot()).to.be.undefined; + expect(cache.getLatest(cp1Hex.rootHex, cp1.epoch - 1)?.hashTreeRoot()).toBeUndefined(); // cp2 - expect(cache.getLatest(cp2Hex.rootHex, cp2.epoch)?.hashTreeRoot()).to.be.undefined; + expect(cache.getLatest(cp2Hex.rootHex, cp2.epoch)?.hashTreeRoot()).toBeUndefined(); }); it("getOrReloadLatest", async () => { @@ -119,15 +119,15 @@ describe("PersistentCheckpointStateCache", function () { expect(Array.from(fileApisBuffer.keys())).toEqual([persistent0bKey]); // getLatest() does not reload from disk - expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch)).to.be.null; - expect(cache.getLatest(cp0bHex.rootHex, cp0b.epoch)).to.be.null; + expect(cache.getLatest(cp0aHex.rootHex, cp0a.epoch)).toBeNull(); + expect(cache.getLatest(cp0bHex.rootHex, cp0b.epoch)).toBeNull(); // cp0a has the root from previous epoch so we only prune it from db - expect(await cache.getOrReloadLatest(cp0aHex.rootHex, cp0a.epoch)).to.be.null; + expect(await cache.getOrReloadLatest(cp0aHex.rootHex, cp0a.epoch)).toBeNull(); // but getOrReloadLatest() does for cp0b expect((await cache.getOrReloadLatest(cp0bHex.rootHex, cp0b.epoch))?.serialize()).toEqual(stateBytes["cp0b"]); expect((await cache.getOrReloadLatest(cp0bHex.rootHex, cp0b.epoch + 1))?.serialize()).toEqual(stateBytes["cp0b"]); - expect((await cache.getOrReloadLatest(cp0bHex.rootHex, cp0b.epoch - 1))?.serialize()).to.be.undefined; + expect((await cache.getOrReloadLatest(cp0bHex.rootHex, cp0b.epoch - 1))?.serialize()).toBeUndefined(); }); it("pruneFinalized and getStateOrBytes", async function () { @@ -139,15 +139,15 @@ describe("PersistentCheckpointStateCache", function () { expect(Array.from(fileApisBuffer.keys())).toEqual([persistent0bKey]); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // cp1 is in memory - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // cp2 is in memory - expect(cache.get(cp2Hex)).to.be.not.null; + expect(cache.get(cp2Hex)).not.toBeNull(); // finalize epoch cp2 cache.pruneFinalized(cp2.epoch); expect(fileApisBuffer.size).toEqual(0); - expect(cache.get(cp1Hex)).to.be.null; - expect(cache.get(cp2Hex)).to.be.not.null; - expect(await cache.getStateOrBytes(cp0bHex)).to.be.null; + expect(cache.get(cp1Hex)).toBeNull(); + expect(cache.get(cp2Hex)).not.toBeNull(); + expect(await cache.getStateOrBytes(cp0bHex)).toBeNull(); }); describe("findSeedStateToReload", () => { @@ -258,15 +258,15 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // epoch 22 has 1 checkpoint state - expect(cache.get(cp2Hex)).to.be.not.null; + expect(cache.get(cp2Hex)).not.toBeNull(); // epoch 21 has 1 checkpoint state - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0bHex)).toBeNull(); // but cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // while cp0aHex is not - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -300,15 +300,15 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // epoch 22 has 1 checkpoint state - expect(cache.get(cp2Hex)).to.be.not.null; + expect(cache.get(cp2Hex)).not.toBeNull(); // epoch 21 has 1 checkpoint state - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0bHex)).toBeNull(); // but cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // while cp0aHex is not - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -346,13 +346,13 @@ describe("PersistentCheckpointStateCache", function () { await cache.processState(toHexString(root3), blockStateRoot3); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // epoch 22 has 2 checkpoint states - expect(cache.get(cp2Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp2a))).to.be.not.null; + expect(cache.get(cp2Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp2a))).not.toBeNull(); // epoch 21 has 1 checkpoint state - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -399,13 +399,13 @@ describe("PersistentCheckpointStateCache", function () { await cache.processState(toHexString(root3), blockStateRoot3); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // epoch 21 and 22 have 2 checkpoint states - expect(cache.get(cp1Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1a))).to.be.not.null; - expect(cache.get(cp2Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp2a))).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1a))).not.toBeNull(); + expect(cache.get(cp2Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp2a))).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -424,7 +424,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // cp0a was pruned from memory and not in disc - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); // regen needs to regen cp0a cache.add(cp0a, states["cp0a"]); @@ -455,13 +455,13 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(root3), blockStateRoot3)).toEqual(1); await assertPersistedCheckpointState([cp0b, cp0a], [stateBytes["cp0b"], stateBytes["cp0a"]]); // epoch 21 and 22 have 2 checkpoint states - expect(cache.get(cp1Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1a))).to.be.not.null; - expect(cache.get(cp2Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp2a))).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1a))).not.toBeNull(); + expect(cache.get(cp2Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp2a))).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -480,7 +480,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(cp2.root), states["cp2"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // cp0a was pruned from memory and not in disc - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); // regen needs to reload cp0b cache.add(cp0b, states["cp0b"]); @@ -511,13 +511,13 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); // epoch 21 and 22 have 2 checkpoint states - expect(cache.get(cp1Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1b))).to.be.not.null; - expect(cache.get(cp2Hex)).to.be.not.null; - expect(cache.get(toCheckpointHex(cp2b))).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1b))).not.toBeNull(); + expect(cache.get(cp2Hex)).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp2b))).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); }); }); @@ -557,14 +557,14 @@ describe("PersistentCheckpointStateCache", function () { expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // epoch 21 has 1 checkpoint state - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); // but cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // while cp0aHex is not - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -597,14 +597,14 @@ describe("PersistentCheckpointStateCache", function () { await cache.processState(toHexString(root3), blockStateRoot3); // epoch 21 has 1 checkpoint state - expect(cache.get(cp1Hex)).to.be.not.null; + expect(cache.get(cp1Hex)).not.toBeNull(); // epoch 20 has 0 checkpoint state - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); // but cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // while cp0aHex is not - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -647,8 +647,8 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // keep these 2 cp states at epoch 21 - expect(cache.get(toCheckpointHex(cp1a))).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1))).to.be.not.null; + expect(cache.get(toCheckpointHex(cp1a))).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1))).not.toBeNull(); }); // epoch: 19 20 21 22 23 @@ -685,8 +685,8 @@ describe("PersistentCheckpointStateCache", function () { // but cp0b in-memory state is pruned expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // keep these 2 cp states at epoch 21 - expect(cache.get(toCheckpointHex(cp1b))).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1))).to.be.not.null; + expect(cache.get(toCheckpointHex(cp1b))).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1))).not.toBeNull(); }); // epoch: 19 20 21 22 23 @@ -708,8 +708,8 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(cp1.root), states["cp1"])).toEqual(0); expect(fileApisBuffer.size).toEqual(0); // at epoch 20, there should be 2 cps in memory - expect(cache.get(cp0aHex)).to.be.not.null; - expect(cache.get(cp0bHex)).to.be.not.null; + expect(cache.get(cp0aHex)).not.toBeNull(); + expect(cache.get(cp0bHex)).not.toBeNull(); await assertPersistedCheckpointState([], []); // cp1 @@ -720,11 +720,11 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // 2 checkpoint states at epoch 20 are pruned - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); // only cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); // root2, regen cp0a cache.add(cp0a, states["cp0a"]); @@ -740,8 +740,8 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b, cp0a], [stateBytes["cp0b"], stateBytes["cp0a"]]); expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // keep these 2 cp states at epoch 21 - expect(cache.get(toCheckpointHex(cp1a))).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1))).to.be.not.null; + expect(cache.get(toCheckpointHex(cp1a))).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1))).not.toBeNull(); }); // epoch: 19 20 21 22 23 @@ -762,11 +762,11 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // 2 checkpoint states at epoch 20 are pruned - expect(cache.get(cp0aHex)).to.be.null; - expect(cache.get(cp0bHex)).to.be.null; + expect(cache.get(cp0aHex)).toBeNull(); + expect(cache.get(cp0bHex)).toBeNull(); // only cp0bHex is persisted expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); // root2, regen cp0a cache.add(cp0a, states["cp0a"]); @@ -782,8 +782,8 @@ describe("PersistentCheckpointStateCache", function () { await assertPersistedCheckpointState([cp0b, cp0a], [stateBytes["cp0b"], stateBytes["cp0a"]]); expect(cache.get(cp1Hex)?.hashTreeRoot()).toEqual(states["cp1"].hashTreeRoot()); // keep these 2 cp states at epoch 21 - expect(cache.get(toCheckpointHex(cp1a))).to.be.not.null; - expect(cache.get(toCheckpointHex(cp1))).to.be.not.null; + expect(cache.get(toCheckpointHex(cp1a))).not.toBeNull(); + expect(cache.get(toCheckpointHex(cp1))).not.toBeNull(); }); describe("processState, maxEpochsInMemory = 0", () => { @@ -808,7 +808,7 @@ describe("PersistentCheckpointStateCache", function () { it("no reorg", async () => { expect(await cache.processState(toHexString(root0b), states["cp0b"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); const root1a = Buffer.alloc(32, 100); @@ -818,7 +818,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(root1a), state1a)).toEqual(0); // nothing change - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); }); @@ -832,7 +832,7 @@ describe("PersistentCheckpointStateCache", function () { it("reorg in same epoch", async () => { expect(await cache.processState(toHexString(root0b), states["cp0b"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); const root1a = Buffer.alloc(32, 100); @@ -842,7 +842,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(root1a), state1a)).toEqual(0); // nothing change - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); // simulate reload cp1b @@ -856,7 +856,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(root1b), state1b)).toEqual(0); // although states["cp0b"] is pruned expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); }); // epoch: 19 20 21 22 23 @@ -869,7 +869,7 @@ describe("PersistentCheckpointStateCache", function () { it("reorg 1 epoch", async () => { expect(await cache.processState(toHexString(root0b), states["cp0b"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); const root1a = Buffer.alloc(32, 100); @@ -879,7 +879,7 @@ describe("PersistentCheckpointStateCache", function () { expect(await cache.processState(toHexString(root1a), state1a)).toEqual(0); // nothing change - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); const root1b = Buffer.alloc(32, 101); @@ -908,7 +908,7 @@ describe("PersistentCheckpointStateCache", function () { it("reorg 2 epochs", async () => { expect(await cache.processState(toHexString(root0b), states["cp0b"])).toEqual(1); await assertPersistedCheckpointState([cp0b], [stateBytes["cp0b"]]); - expect(await cache.getStateOrBytes(cp0aHex)).to.be.null; + expect(await cache.getStateOrBytes(cp0aHex)).toBeNull(); expect(await cache.getStateOrBytes(cp0bHex)).toEqual(stateBytes["cp0b"]); cache.add(cp1, states["cp1"]); @@ -948,7 +948,7 @@ describe("PersistentCheckpointStateCache", function () { const cpHex = toCheckpointHex(cp); expect(await cache.getStateOrBytes(cpHex)).toStrictEqual(stateBytesArr[i]); // simple get() does not reload from disk - expect(cache.get(cpHex)).to.be.null; + expect(cache.get(cpHex)).toBeNull(); } } }); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation.test.ts deleted file mode 100644 index efd7d3c00cbb..000000000000 --- a/packages/beacon-node/test/unit/chain/validation/attestation.test.ts +++ /dev/null @@ -1,591 +0,0 @@ -import {BitArray} from "@chainsafe/ssz"; -import type {PublicKey, SecretKey} from "@chainsafe/bls/types"; -import bls from "@chainsafe/bls"; -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; -import {EpochDifference, ProtoBlock} from "@lodestar/fork-choice"; -import {EpochShuffling, SignatureSetType, computeStartSlotAtEpoch} from "@lodestar/state-transition"; -import {ssz} from "@lodestar/types"; -// eslint-disable-next-line import/no-relative-packages -import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../state-transition/test/perf/util.js"; -import {IBeaconChain} from "../../../../src/chain/index.js"; -import { - AttestationError, - AttestationErrorCode, - GossipAction, - GossipErrorCode, -} from "../../../../src/chain/errors/index.js"; -import { - ApiAttestation, - GossipAttestation, - validateApiAttestation, - Step0Result, - validateAttestation, - validateGossipAttestationsSameAttData, - getShufflingForAttestationVerification, -} from "../../../../src/chain/validation/index.js"; -import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; -import {memoOnce} from "../../../utils/cache.js"; -import {getAttestationValidData, AttestationValidDataOpts} from "../../../utils/validationData/attestation.js"; -import {RegenCaller} from "../../../../src/chain/regen/interface.js"; -import {ZERO_HASH_HEX} from "../../../../src/constants/constants.js"; - -import {BlsSingleThreadVerifier} from "../../../../src/chain/bls/singleThread.js"; -import {SeenAttesters} from "../../../../src/chain/seenCache/seenAttesters.js"; -import {getAttDataBase64FromAttestationSerialized} from "../../../../src/util/sszBytes.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; - -describe("validateGossipAttestationsSameAttData", () => { - // phase0Result specifies whether the attestation is valid in phase0 - // phase1Result specifies signature verification - const testCases: {phase0Result: boolean[]; phase1Result: boolean[]; seenAttesters: number[]}[] = [ - { - phase0Result: [true, true, true, true, true], - phase1Result: [true, true, true, true, true], - seenAttesters: [0, 1, 2, 3, 4], - }, - { - phase0Result: [false, true, true, true, true], - phase1Result: [true, false, true, true, true], - seenAttesters: [2, 3, 4], - }, - { - phase0Result: [false, false, true, true, true], - phase1Result: [true, false, false, true, true], - seenAttesters: [3, 4], - }, - { - phase0Result: [false, false, true, true, true], - phase1Result: [true, false, false, true, false], - seenAttesters: [3], - }, - { - phase0Result: [false, false, true, true, true], - phase1Result: [true, true, false, false, false], - seenAttesters: [], - }, - ]; - - type Keypair = {publicKey: PublicKey; secretKey: SecretKey}; - const keypairs = new Map(); - function getKeypair(i: number): Keypair { - let keypair = keypairs.get(i); - if (!keypair) { - const bytes = new Uint8Array(32); - const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); - dataView.setUint32(0, i + 1, true); - const secretKey = bls.SecretKey.fromBytes(bytes); - const publicKey = secretKey.toPublicKey(); - keypair = {secretKey, publicKey}; - keypairs.set(i, keypair); - } - return keypair; - } - - let chain: IBeaconChain; - const signingRoot = Buffer.alloc(32, 1); - - beforeEach(() => { - chain = { - bls: new BlsSingleThreadVerifier({metrics: null}), - seenAttesters: new SeenAttesters(), - opts: { - minSameMessageSignatureSetsToBatch: 2, - } as IBeaconChain["opts"], - } as Partial as IBeaconChain; - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - for (const [testCaseIndex, testCase] of testCases.entries()) { - const {phase0Result, phase1Result, seenAttesters} = testCase; - it(`test case ${testCaseIndex}`, async () => { - const phase0Results: Promise[] = []; - for (const [i, isValid] of phase0Result.entries()) { - const signatureSet = { - type: SignatureSetType.single, - pubkey: getKeypair(i).publicKey, - signingRoot, - signature: getKeypair(i).secretKey.sign(signingRoot).toBytes(), - }; - if (isValid) { - if (!phase1Result[i]) { - // invalid signature - signatureSet.signature = getKeypair(2023).secretKey.sign(signingRoot).toBytes(); - } - phase0Results.push( - Promise.resolve({ - attestation: ssz.phase0.Attestation.defaultValue(), - signatureSet, - validatorIndex: i, - } as Partial as Step0Result) - ); - } else { - phase0Results.push( - Promise.reject( - new AttestationError(GossipAction.REJECT, { - code: AttestationErrorCode.BAD_TARGET_EPOCH, - }) - ) - ); - } - } - - let callIndex = 0; - const phase0ValidationFn = (): Promise => { - const result = phase0Results[callIndex]; - callIndex++; - return result; - }; - await validateGossipAttestationsSameAttData(ForkName.phase0, chain, new Array(5).fill({}), 0, phase0ValidationFn); - for (let validatorIndex = 0; validatorIndex < phase0Result.length; validatorIndex++) { - if (seenAttesters.includes(validatorIndex)) { - expect(chain.seenAttesters.isKnown(0, validatorIndex)).toBe(true); - } else { - expect(chain.seenAttesters.isKnown(0, validatorIndex)).toBe(false); - } - } - }); // end test case - } -}); - -describe("validateAttestation", () => { - const vc = 64; - const stateSlot = 100; - - const UNKNOWN_ROOT = Buffer.alloc(32, 1); - const KNOWN_TARGET_ROOT = Buffer.alloc(32, 0xd0); - const KNOWN_BEACON_BLOCK_ROOT = Buffer.alloc(32, 0xd1); - - const getState = memoOnce(() => generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot})); - - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - function getValidData(opts?: Partial) { - return getAttestationValidData({ - currentSlot: stateSlot, - attSlot: opts?.currentSlot ?? stateSlot, - attIndex: 1, - bitIndex: 1, - targetRoot: KNOWN_TARGET_ROOT, - beaconBlockRoot: KNOWN_BEACON_BLOCK_ROOT, - state: getState(), - ...opts, - }); - } - - it("Valid", async () => { - const {chain, attestation} = getValidData(); - - const fork = chain.config.getForkName(stateSlot); - await validateApiAttestation(fork, chain, {attestation, serializedData: null}); - }); - - it("INVALID_SERIALIZED_BYTES_ERROR_CODE", async () => { - const {chain, subnet} = getValidData(); - await expectGossipError( - chain, - {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, attDataBase64: "invalid"}, - subnet, - GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE - ); - }); - - it("BAD_TARGET_EPOCH", async () => { - const {chain, attestation, subnet} = getValidData(); - - // Change target epoch to it doesn't match data.slot - attestation.data.target.epoch += 1; - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.BAD_TARGET_EPOCH); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.BAD_TARGET_EPOCH - ); - }); - - it("PAST_SLOT", async () => { - // Set attestation at a very old slot - const {chain, attestation, subnet} = getValidData({attSlot: stateSlot - SLOTS_PER_EPOCH - 3}); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.PAST_SLOT); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.PAST_SLOT - ); - }); - - it("FUTURE_SLOT", async () => { - // Set attestation to a future slot - const {chain, attestation, subnet} = getValidData({attSlot: stateSlot + 2}); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.FUTURE_SLOT); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.FUTURE_SLOT - ); - }); - - it("NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - 0 bits", async () => { - // Unset the single aggregationBits - const bitIndex = 1; - const {chain, attestation, subnet} = getValidData({bitIndex}); - attestation.aggregationBits.set(bitIndex, false); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError( - chain, - {attestation, serializedData: null}, - AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - ); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - ); - }); - - it("NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - 2 bits", async () => { - // Set an extra bit in the attestation - const bitIndex = 1; - const {chain, attestation, subnet} = getValidData({bitIndex}); - attestation.aggregationBits.set(bitIndex + 1, true); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - ); - }); - - it("UNKNOWN_BEACON_BLOCK_ROOT", async () => { - const {chain, attestation, subnet} = getValidData(); - // Set beaconBlockRoot to a root not known by the fork choice - attestation.data.beaconBlockRoot = UNKNOWN_ROOT; - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError( - chain, - {attestation, serializedData: null}, - AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT - ); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT - ); - }); - - it("INVALID_TARGET_ROOT", async () => { - const {chain, attestation, subnet} = getValidData(); - // Set target.root to an unknown root - attestation.data.target.root = UNKNOWN_ROOT; - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.INVALID_TARGET_ROOT); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.INVALID_TARGET_ROOT - ); - }); - - it("WRONG_NUMBER_OF_AGGREGATION_BITS", async () => { - const {chain, attestation, subnet} = getValidData(); - // Increase the length of aggregationBits beyond the committee size - attestation.aggregationBits = new BitArray( - attestation.aggregationBits.uint8Array, - attestation.aggregationBits.bitLen + 1 - ); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError( - chain, - {attestation, serializedData: null}, - AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS - ); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS - ); - }); - - it("INVALID_SUBNET_ID", async () => { - const {chain, attestation, subnet} = getValidData(); - // Pass a different subnet value than the correct one - const invalidSubnet = subnet === 0 ? 1 : 0; - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - invalidSubnet, - AttestationErrorCode.INVALID_SUBNET_ID - ); - }); - - it("ATTESTATION_ALREADY_KNOWN", async () => { - const {chain, attestation, subnet, validatorIndex} = getValidData(); - // Register attester as already seen - chain.seenAttesters.add(attestation.data.target.epoch, validatorIndex); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.ATTESTATION_ALREADY_KNOWN - ); - }); - - it("INVALID_SIGNATURE", async () => { - const bitIndex = 1; - const {chain, attestation, subnet} = getValidData({bitIndex}); - // Change the bit index so the signature is validated against a different pubkey - attestation.aggregationBits.set(bitIndex, false); - attestation.aggregationBits.set(bitIndex + 1, true); - const serializedData = ssz.phase0.Attestation.serialize(attestation); - - await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.INVALID_SIGNATURE); - await expectGossipError( - chain, - { - attestation: null, - serializedData, - attSlot: attestation.data.slot, - attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), - }, - subnet, - AttestationErrorCode.INVALID_SIGNATURE - ); - }); - - /** Alias to reduce code duplication */ - async function expectApiError( - chain: IBeaconChain, - attestationOrBytes: ApiAttestation, - errorCode: string - ): Promise { - const fork = chain.config.getForkName(stateSlot); - await expectRejectedWithLodestarError(validateApiAttestation(fork, chain, attestationOrBytes), errorCode); - } - - async function expectGossipError( - chain: IBeaconChain, - attestationOrBytes: GossipAttestation, - subnet: number, - errorCode: string - ): Promise { - const fork = chain.config.getForkName(stateSlot); - await expectRejectedWithLodestarError(validateAttestation(fork, chain, attestationOrBytes, subnet), errorCode); - } -}); - -describe("getShufflingForAttestationVerification", () => { - let regenStub: MockedBeaconChain["regen"]; - let forkchoiceStub: MockedBeaconChain["forkChoice"]; - let shufflingCacheStub: MockedBeaconChain["shufflingCache"]; - let chain: MockedBeaconChain; - - beforeEach(() => { - chain = getMockedBeaconChain(); - regenStub = chain.regen; - forkchoiceStub = chain.forkChoice; - shufflingCacheStub = chain.shufflingCache; - vi.spyOn(regenStub, "getBlockSlotState"); - vi.spyOn(regenStub, "getState"); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - const attEpoch = 1000; - const blockRoot = "0xd76aed834b4feef32efb53f9076e407c0d344cfdb70f0a770fa88416f70d304d"; - - it("block epoch is the same to attestation epoch", async () => { - const headSlot = computeStartSlotAtEpoch(attEpoch); - const attHeadBlock = { - slot: headSlot, - stateRoot: ZERO_HASH_HEX, - blockRoot, - } as Partial as ProtoBlock; - const previousDependentRoot = "0xa916b57729dbfb89a082820e0eb2b669d9d511a675d3d8c888b2f300f10b0bdf"; - forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { - if (block === attHeadBlock && epochDiff === EpochDifference.previous) { - return previousDependentRoot; - } else { - throw new Error("Unexpected input"); - } - }); - const expectedShuffling = {epoch: attEpoch} as EpochShuffling; - shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { - if (epoch === attEpoch && root === previousDependentRoot) { - return Promise.resolve(expectedShuffling); - } else { - return Promise.resolve(null); - } - }); - const resultShuffling = await getShufflingForAttestationVerification( - chain, - attEpoch, - attHeadBlock, - RegenCaller.validateGossipAttestation - ); - expect(resultShuffling).to.be.deep.equal(expectedShuffling); - }); - - it("block epoch is previous attestation epoch", async () => { - const headSlot = computeStartSlotAtEpoch(attEpoch - 1); - const attHeadBlock = { - slot: headSlot, - stateRoot: ZERO_HASH_HEX, - blockRoot, - } as Partial as ProtoBlock; - const currentDependentRoot = "0xa916b57729dbfb89a082820e0eb2b669d9d511a675d3d8c888b2f300f10b0bdf"; - forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { - if (block === attHeadBlock && epochDiff === EpochDifference.current) { - return currentDependentRoot; - } else { - throw new Error("Unexpected input"); - } - }); - const expectedShuffling = {epoch: attEpoch} as EpochShuffling; - shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { - if (epoch === attEpoch && root === currentDependentRoot) { - return Promise.resolve(expectedShuffling); - } else { - return Promise.resolve(null); - } - }); - const resultShuffling = await getShufflingForAttestationVerification( - chain, - attEpoch, - attHeadBlock, - RegenCaller.validateGossipAttestation - ); - expect(resultShuffling).to.be.deep.equal(expectedShuffling); - }); - - it("block epoch is attestation epoch - 2", async () => { - const headSlot = computeStartSlotAtEpoch(attEpoch - 2); - const attHeadBlock = { - slot: headSlot, - stateRoot: ZERO_HASH_HEX, - blockRoot, - } as Partial as ProtoBlock; - const expectedShuffling = {epoch: attEpoch} as EpochShuffling; - let callCount = 0; - shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { - if (epoch === attEpoch && root === blockRoot) { - if (callCount === 0) { - callCount++; - return Promise.resolve(null); - } else { - return Promise.resolve(expectedShuffling); - } - } else { - return Promise.resolve(null); - } - }); - chain.regenStateForAttestationVerification.mockImplementationOnce(() => Promise.resolve(expectedShuffling)); - - const resultShuffling = await getShufflingForAttestationVerification( - chain, - attEpoch, - attHeadBlock, - RegenCaller.validateGossipAttestation - ); - // sandbox.assert.notCalled(forkchoiceStub.getDependentRoot); - expect(forkchoiceStub.getDependentRoot).not.toHaveBeenCalledTimes(1); - expect(resultShuffling).to.be.deep.equal(expectedShuffling); - }); - - it("block epoch is attestation epoch + 1", async () => { - const headSlot = computeStartSlotAtEpoch(attEpoch + 1); - const attHeadBlock = { - slot: headSlot, - stateRoot: ZERO_HASH_HEX, - blockRoot, - } as Partial as ProtoBlock; - try { - await getShufflingForAttestationVerification( - chain, - attEpoch, - attHeadBlock, - RegenCaller.validateGossipAttestation - ); - expect.fail("Expect error because attestation epoch is greater than block epoch"); - } catch (e) { - expect(e instanceof Error).to.be.true; - } - }); -}); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts new file mode 100644 index 000000000000..a0eb147db8e8 --- /dev/null +++ b/packages/beacon-node/test/unit/chain/validation/attestation/getShufflingForAttestationVerification.test.ts @@ -0,0 +1,150 @@ +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +// We need to import the mock before the packages +// eslint-disable-next-line import/order +import {MockedBeaconChain, getMockedBeaconChain} from "../../../../mocks/mockedBeaconChain.js"; +import {EpochShuffling, computeStartSlotAtEpoch} from "@lodestar/state-transition"; +import {EpochDifference, ProtoBlock} from "@lodestar/fork-choice"; +import {RegenCaller} from "../../../../../src/chain/regen/interface.js"; +import {getShufflingForAttestationVerification} from "../../../../../src/chain/validation/index.js"; +import {ZERO_HASH_HEX} from "../../../../../src/constants/constants.js"; + +describe("getShufflingForAttestationVerification", () => { + let chain: MockedBeaconChain; + let regenStub: MockedBeaconChain["regen"]; + let forkchoiceStub: MockedBeaconChain["forkChoice"]; + let shufflingCacheStub: MockedBeaconChain["shufflingCache"]; + + beforeEach(() => { + chain = getMockedBeaconChain(); + regenStub = chain.regen; + forkchoiceStub = chain.forkChoice; + shufflingCacheStub = chain.shufflingCache; + vi.spyOn(regenStub, "getBlockSlotState"); + vi.spyOn(regenStub, "getState"); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + const attEpoch = 1000; + const blockRoot = "0xd76aed834b4feef32efb53f9076e407c0d344cfdb70f0a770fa88416f70d304d"; + + it("block epoch is the same to attestation epoch", async () => { + const headSlot = computeStartSlotAtEpoch(attEpoch); + const attHeadBlock = { + slot: headSlot, + stateRoot: ZERO_HASH_HEX, + blockRoot, + } as Partial; + const previousDependentRoot = "0xa916b57729dbfb89a082820e0eb2b669d9d511a675d3d8c888b2f300f10b0bdf"; + forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { + if (block === attHeadBlock && epochDiff === EpochDifference.previous) { + return previousDependentRoot; + } else { + throw new Error("Unexpected input"); + } + }); + const expectedShuffling = {epoch: attEpoch} as EpochShuffling; + shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { + if (epoch === attEpoch && root === previousDependentRoot) { + return Promise.resolve(expectedShuffling); + } else { + return Promise.resolve(null); + } + }); + const resultShuffling = await getShufflingForAttestationVerification( + chain, + attEpoch, + attHeadBlock as ProtoBlock, + RegenCaller.validateGossipAttestation + ); + expect(resultShuffling).toEqual(expectedShuffling); + }); + + it("block epoch is previous attestation epoch", async () => { + const headSlot = computeStartSlotAtEpoch(attEpoch - 1); + const attHeadBlock = { + slot: headSlot, + stateRoot: ZERO_HASH_HEX, + blockRoot, + } as Partial; + const currentDependentRoot = "0xa916b57729dbfb89a082820e0eb2b669d9d511a675d3d8c888b2f300f10b0bdf"; + forkchoiceStub.getDependentRoot.mockImplementationOnce((block, epochDiff) => { + if (block === attHeadBlock && epochDiff === EpochDifference.current) { + return currentDependentRoot; + } else { + throw new Error("Unexpected input"); + } + }); + const expectedShuffling = {epoch: attEpoch} as EpochShuffling; + shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { + if (epoch === attEpoch && root === currentDependentRoot) { + return Promise.resolve(expectedShuffling); + } else { + return Promise.resolve(null); + } + }); + const resultShuffling = await getShufflingForAttestationVerification( + chain, + attEpoch, + attHeadBlock as ProtoBlock, + RegenCaller.validateGossipAttestation + ); + expect(resultShuffling).toEqual(expectedShuffling); + }); + + it("block epoch is attestation epoch - 2", async () => { + const headSlot = computeStartSlotAtEpoch(attEpoch - 2); + const attHeadBlock = { + slot: headSlot, + stateRoot: ZERO_HASH_HEX, + blockRoot, + } as Partial; + const expectedShuffling = {epoch: attEpoch} as EpochShuffling; + let callCount = 0; + shufflingCacheStub.get.mockImplementationOnce((epoch, root) => { + if (epoch === attEpoch && root === blockRoot) { + if (callCount === 0) { + callCount++; + return Promise.resolve(null); + } else { + return Promise.resolve(expectedShuffling); + } + } else { + return Promise.resolve(null); + } + }); + chain.regenStateForAttestationVerification.mockImplementationOnce(() => Promise.resolve(expectedShuffling)); + + const resultShuffling = await getShufflingForAttestationVerification( + chain, + attEpoch, + attHeadBlock as ProtoBlock, + RegenCaller.validateGossipAttestation + ); + // sandbox.assert.notCalled(forkchoiceStub.getDependentRoot); + expect(forkchoiceStub.getDependentRoot).not.toHaveBeenCalledTimes(1); + expect(resultShuffling).toEqual(expectedShuffling); + }); + + it("block epoch is attestation epoch + 1", async () => { + const headSlot = computeStartSlotAtEpoch(attEpoch + 1); + const attHeadBlock = { + slot: headSlot, + stateRoot: ZERO_HASH_HEX, + blockRoot, + } as Partial; + try { + await getShufflingForAttestationVerification( + chain, + attEpoch, + attHeadBlock as ProtoBlock, + RegenCaller.validateGossipAttestation + ); + expect.fail("Expect error because attestation epoch is greater than block epoch"); + } catch (e) { + expect(e instanceof Error).toBeTruthy(); + } + }); +}); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts new file mode 100644 index 000000000000..56aab699f4f7 --- /dev/null +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateAttestation.test.ts @@ -0,0 +1,316 @@ +import {BitArray} from "@chainsafe/ssz"; +import {describe, it} from "vitest"; +import {SLOTS_PER_EPOCH} from "@lodestar/params"; +import {ssz} from "@lodestar/types"; +// eslint-disable-next-line import/no-relative-packages +import {generateTestCachedBeaconStateOnlyValidators} from "../../../../../../state-transition/test/perf/util.js"; +import {AttestationErrorCode, GossipErrorCode} from "../../../../../src/chain/errors/index.js"; +import {IBeaconChain} from "../../../../../src/chain/index.js"; +import { + ApiAttestation, + GossipAttestation, + validateApiAttestation, + validateAttestation, +} from "../../../../../src/chain/validation/index.js"; +import {getAttDataBase64FromAttestationSerialized} from "../../../../../src/util/sszBytes.js"; +import {memoOnce} from "../../../../utils/cache.js"; +import {expectRejectedWithLodestarError} from "../../../../utils/errors.js"; +import {AttestationValidDataOpts, getAttestationValidData} from "../../../../utils/validationData/attestation.js"; + +describe("validateAttestation", () => { + const vc = 64; + const stateSlot = 100; + + const UNKNOWN_ROOT = Buffer.alloc(32, 1); + const KNOWN_TARGET_ROOT = Buffer.alloc(32, 0xd0); + const KNOWN_BEACON_BLOCK_ROOT = Buffer.alloc(32, 0xd1); + + const getState = memoOnce(() => generateTestCachedBeaconStateOnlyValidators({vc, slot: stateSlot})); + + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + function getValidData(opts?: Partial) { + return getAttestationValidData({ + currentSlot: stateSlot, + attSlot: opts?.currentSlot ?? stateSlot, + attIndex: 1, + bitIndex: 1, + targetRoot: KNOWN_TARGET_ROOT, + beaconBlockRoot: KNOWN_BEACON_BLOCK_ROOT, + state: getState(), + ...opts, + }); + } + + it("Valid", async () => { + const {chain, attestation} = getValidData(); + + const fork = chain.config.getForkName(stateSlot); + await validateApiAttestation(fork, chain, {attestation, serializedData: null}); + }); + + it("INVALID_SERIALIZED_BYTES_ERROR_CODE", async () => { + const {chain, subnet} = getValidData(); + await expectGossipError( + chain, + {attestation: null, serializedData: Buffer.alloc(0), attSlot: 0, attDataBase64: "invalid"}, + subnet, + GossipErrorCode.INVALID_SERIALIZED_BYTES_ERROR_CODE + ); + }); + + it("BAD_TARGET_EPOCH", async () => { + const {chain, attestation, subnet} = getValidData(); + + // Change target epoch to it doesn't match data.slot + attestation.data.target.epoch += 1; + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.BAD_TARGET_EPOCH); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.BAD_TARGET_EPOCH + ); + }); + + it("PAST_SLOT", async () => { + // Set attestation at a very old slot + const {chain, attestation, subnet} = getValidData({attSlot: stateSlot - SLOTS_PER_EPOCH - 3}); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.PAST_SLOT); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.PAST_SLOT + ); + }); + + it("FUTURE_SLOT", async () => { + // Set attestation to a future slot + const {chain, attestation, subnet} = getValidData({attSlot: stateSlot + 2}); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.FUTURE_SLOT); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.FUTURE_SLOT + ); + }); + + it("NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - 0 bits", async () => { + // Unset the single aggregationBits + const bitIndex = 1; + const {chain, attestation, subnet} = getValidData({bitIndex}); + attestation.aggregationBits.set(bitIndex, false); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError( + chain, + {attestation, serializedData: null}, + AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET + ); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET + ); + }); + + it("NOT_EXACTLY_ONE_AGGREGATION_BIT_SET - 2 bits", async () => { + // Set an extra bit in the attestation + const bitIndex = 1; + const {chain, attestation, subnet} = getValidData({bitIndex}); + attestation.aggregationBits.set(bitIndex + 1, true); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.NOT_EXACTLY_ONE_AGGREGATION_BIT_SET + ); + }); + + it("UNKNOWN_BEACON_BLOCK_ROOT", async () => { + const {chain, attestation, subnet} = getValidData(); + // Set beaconBlockRoot to a root not known by the fork choice + attestation.data.beaconBlockRoot = UNKNOWN_ROOT; + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError( + chain, + {attestation, serializedData: null}, + AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT + ); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.UNKNOWN_OR_PREFINALIZED_BEACON_BLOCK_ROOT + ); + }); + + it("INVALID_TARGET_ROOT", async () => { + const {chain, attestation, subnet} = getValidData(); + // Set target.root to an unknown root + attestation.data.target.root = UNKNOWN_ROOT; + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.INVALID_TARGET_ROOT); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.INVALID_TARGET_ROOT + ); + }); + + it("WRONG_NUMBER_OF_AGGREGATION_BITS", async () => { + const {chain, attestation, subnet} = getValidData(); + // Increase the length of aggregationBits beyond the committee size + attestation.aggregationBits = new BitArray( + attestation.aggregationBits.uint8Array, + attestation.aggregationBits.bitLen + 1 + ); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError( + chain, + {attestation, serializedData: null}, + AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS + ); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.WRONG_NUMBER_OF_AGGREGATION_BITS + ); + }); + + it("INVALID_SUBNET_ID", async () => { + const {chain, attestation, subnet} = getValidData(); + // Pass a different subnet value than the correct one + const invalidSubnet = subnet === 0 ? 1 : 0; + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + invalidSubnet, + AttestationErrorCode.INVALID_SUBNET_ID + ); + }); + + it("ATTESTATION_ALREADY_KNOWN", async () => { + const {chain, attestation, subnet, validatorIndex} = getValidData(); + // Register attester as already seen + chain.seenAttesters.add(attestation.data.target.epoch, validatorIndex); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.ATTESTATION_ALREADY_KNOWN); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.ATTESTATION_ALREADY_KNOWN + ); + }); + + it("INVALID_SIGNATURE", async () => { + const bitIndex = 1; + const {chain, attestation, subnet} = getValidData({bitIndex}); + // Change the bit index so the signature is validated against a different pubkey + attestation.aggregationBits.set(bitIndex, false); + attestation.aggregationBits.set(bitIndex + 1, true); + const serializedData = ssz.phase0.Attestation.serialize(attestation); + + await expectApiError(chain, {attestation, serializedData: null}, AttestationErrorCode.INVALID_SIGNATURE); + await expectGossipError( + chain, + { + attestation: null, + serializedData, + attSlot: attestation.data.slot, + attDataBase64: getAttDataBase64FromAttestationSerialized(serializedData), + }, + subnet, + AttestationErrorCode.INVALID_SIGNATURE + ); + }); + + /** Alias to reduce code duplication */ + async function expectApiError( + chain: IBeaconChain, + attestationOrBytes: ApiAttestation, + errorCode: string + ): Promise { + const fork = chain.config.getForkName(stateSlot); + await expectRejectedWithLodestarError(validateApiAttestation(fork, chain, attestationOrBytes), errorCode); + } + + async function expectGossipError( + chain: IBeaconChain, + attestationOrBytes: GossipAttestation, + subnet: number, + errorCode: string + ): Promise { + const fork = chain.config.getForkName(stateSlot); + await expectRejectedWithLodestarError(validateAttestation(fork, chain, attestationOrBytes, subnet), errorCode); + } +}); diff --git a/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts b/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts new file mode 100644 index 000000000000..29b9ba3e1912 --- /dev/null +++ b/packages/beacon-node/test/unit/chain/validation/attestation/validateGossipAttestationsSameAttData.test.ts @@ -0,0 +1,128 @@ +import bls from "@chainsafe/bls"; +import type {PublicKey, SecretKey} from "@chainsafe/bls/types"; +import {afterEach, beforeEach, describe, expect, it, vi} from "vitest"; +import {ForkName} from "@lodestar/params"; +import {SignatureSetType} from "@lodestar/state-transition"; +import {ssz} from "@lodestar/types"; +// eslint-disable-next-line import/no-relative-packages +import {BlsSingleThreadVerifier} from "../../../../../src/chain/bls/singleThread.js"; +import {AttestationError, AttestationErrorCode, GossipAction} from "../../../../../src/chain/errors/index.js"; +import {IBeaconChain} from "../../../../../src/chain/index.js"; +import {SeenAttesters} from "../../../../../src/chain/seenCache/seenAttesters.js"; +import {Step0Result, validateGossipAttestationsSameAttData} from "../../../../../src/chain/validation/index.js"; + +describe("validateGossipAttestationsSameAttData", () => { + // phase0Result specifies whether the attestation is valid in phase0 + // phase1Result specifies signature verification + const testCases: {phase0Result: boolean[]; phase1Result: boolean[]; seenAttesters: number[]}[] = [ + { + phase0Result: [true, true, true, true, true], + phase1Result: [true, true, true, true, true], + seenAttesters: [0, 1, 2, 3, 4], + }, + { + phase0Result: [false, true, true, true, true], + phase1Result: [true, false, true, true, true], + seenAttesters: [2, 3, 4], + }, + { + phase0Result: [false, false, true, true, true], + phase1Result: [true, false, false, true, true], + seenAttesters: [3, 4], + }, + { + phase0Result: [false, false, true, true, true], + phase1Result: [true, false, false, true, false], + seenAttesters: [3], + }, + { + phase0Result: [false, false, true, true, true], + phase1Result: [true, true, false, false, false], + seenAttesters: [], + }, + ]; + + type Keypair = {publicKey: PublicKey; secretKey: SecretKey}; + const keypairs = new Map(); + function getKeypair(i: number): Keypair { + let keypair = keypairs.get(i); + if (!keypair) { + const bytes = new Uint8Array(32); + const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength); + dataView.setUint32(0, i + 1, true); + const secretKey = bls.SecretKey.fromBytes(bytes); + const publicKey = secretKey.toPublicKey(); + keypair = {secretKey, publicKey}; + keypairs.set(i, keypair); + } + return keypair; + } + + let chain: IBeaconChain; + const signingRoot = Buffer.alloc(32, 1); + + beforeEach(() => { + chain = { + bls: new BlsSingleThreadVerifier({metrics: null}), + seenAttesters: new SeenAttesters(), + opts: { + minSameMessageSignatureSetsToBatch: 2, + } as IBeaconChain["opts"], + } as Partial as IBeaconChain; + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + for (const [testCaseIndex, testCase] of testCases.entries()) { + const {phase0Result, phase1Result, seenAttesters} = testCase; + it(`test case ${testCaseIndex}`, async () => { + const phase0Results: Promise[] = []; + for (const [i, isValid] of phase0Result.entries()) { + const signatureSet = { + type: SignatureSetType.single, + pubkey: getKeypair(i).publicKey, + signingRoot, + signature: getKeypair(i).secretKey.sign(signingRoot).toBytes(), + }; + if (isValid) { + if (!phase1Result[i]) { + // invalid signature + signatureSet.signature = getKeypair(2023).secretKey.sign(signingRoot).toBytes(); + } + phase0Results.push( + Promise.resolve({ + attestation: ssz.phase0.Attestation.defaultValue(), + signatureSet, + validatorIndex: i, + } as Partial as Step0Result) + ); + } else { + phase0Results.push( + Promise.reject( + new AttestationError(GossipAction.REJECT, { + code: AttestationErrorCode.BAD_TARGET_EPOCH, + }) + ) + ); + } + } + + let callIndex = 0; + const phase0ValidationFn = (): Promise => { + const result = phase0Results[callIndex]; + callIndex++; + return result; + }; + await validateGossipAttestationsSameAttData(ForkName.phase0, chain, new Array(5).fill({}), 0, phase0ValidationFn); + for (let validatorIndex = 0; validatorIndex < phase0Result.length; validatorIndex++) { + if (seenAttesters.includes(validatorIndex)) { + expect(chain.seenAttesters.isKnown(0, validatorIndex)).toBe(true); + } else { + expect(chain.seenAttesters.isKnown(0, validatorIndex)).toBe(false); + } + } + }); // end test case + } +}); diff --git a/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts b/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts index dcb07e5998ec..629753824669 100644 --- a/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/attesterSlashing.test.ts @@ -1,10 +1,10 @@ import {describe, it, beforeEach, afterEach, vi} from "vitest"; import {phase0, ssz} from "@lodestar/types"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {generateCachedState} from "../../../utils/state.js"; import {validateGossipAttesterSlashing} from "../../../../src/chain/validation/attesterSlashing.js"; import {AttesterSlashingErrorCode} from "../../../../src/chain/errors/attesterSlashingError.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; describe("GossipMessageValidator", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/block.test.ts b/packages/beacon-node/test/unit/chain/validation/block.test.ts index f1aca0a43cf7..65f8114ebe93 100644 --- a/packages/beacon-node/test/unit/chain/validation/block.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/block.test.ts @@ -1,21 +1,21 @@ -import {Mock, MockedObject, beforeEach, describe, it, vi} from "vitest"; +import {Mock, Mocked, beforeEach, describe, it, vi} from "vitest"; import {config} from "@lodestar/config/default"; import {ProtoBlock} from "@lodestar/fork-choice"; import {ForkName} from "@lodestar/params"; import {allForks, ssz} from "@lodestar/types"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {BlockErrorCode} from "../../../../src/chain/errors/index.js"; import {QueuedStateRegenerator} from "../../../../src/chain/regen/index.js"; import {SeenBlockProposers} from "../../../../src/chain/seenCache/index.js"; import {validateGossipBlock} from "../../../../src/chain/validation/index.js"; import {EMPTY_SIGNATURE, ZERO_HASH} from "../../../../src/constants/index.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {generateCachedState} from "../../../utils/state.js"; describe("gossip block validation", function () { let chain: MockedBeaconChain; let forkChoice: MockedBeaconChain["forkChoice"]; - let regen: MockedObject; + let regen: Mocked; let verifySignature: Mock<[boolean]>; let job: allForks.SignedBeaconBlock; const proposerIndex = 0; diff --git a/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts b/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts index dd4402255949..f83b900beb69 100644 --- a/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/blsToExecutionChange.test.ts @@ -14,13 +14,12 @@ import { ForkName, } from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; - +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {generateState} from "../../../utils/state.js"; import {validateGossipBlsToExecutionChange} from "../../../../src/chain/validation/blsToExecutionChange.js"; import {BlsToExecutionChangeErrorCode} from "../../../../src/chain/errors/blsToExecutionChangeError.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; describe("validate bls to execution change", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts index 5e30b13a8861..70dda2535521 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientFinalityUpdate.test.ts @@ -5,7 +5,7 @@ import {computeTimeAtSlot} from "@lodestar/state-transition"; import {validateLightClientFinalityUpdate} from "../../../../src/chain/validation/lightClientFinalityUpdate.js"; import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientError.js"; import {IBeaconChain} from "../../../../src/chain/index.js"; -import {getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; +import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("Light Client Finality Update validation", function () { const afterEachCallbacks: (() => Promise | void)[] = []; diff --git a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts index 0631c01758e2..304db1365fb1 100644 --- a/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/lightClientOptimisticUpdate.test.ts @@ -5,7 +5,7 @@ import {computeTimeAtSlot} from "@lodestar/state-transition"; import {validateLightClientOptimisticUpdate} from "../../../../src/chain/validation/lightClientOptimisticUpdate.js"; import {LightClientErrorCode} from "../../../../src/chain/errors/lightClientError.js"; import {IBeaconChain} from "../../../../src/chain/index.js"; -import {getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; +import {getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; describe("Light Client Optimistic Update validation", function () { const afterEachCallbacks: (() => Promise | void)[] = []; diff --git a/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts b/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts index de172c0ec136..f5eb7310a39c 100644 --- a/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/proposerSlashing.test.ts @@ -1,10 +1,10 @@ import {describe, it, beforeEach, afterEach, vi} from "vitest"; import {phase0, ssz} from "@lodestar/types"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {generateCachedState} from "../../../utils/state.js"; import {ProposerSlashingErrorCode} from "../../../../src/chain/errors/proposerSlashingError.js"; import {validateGossipProposerSlashing} from "../../../../src/chain/validation/proposerSlashing.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; describe("validate proposer slashing", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts index 739ab44503c7..b498333ae738 100644 --- a/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/syncCommittee.test.ts @@ -3,13 +3,13 @@ import {describe, it, expect, afterEach, beforeEach, beforeAll, afterAll, vi, Mo import {altair, Epoch, Slot} from "@lodestar/types"; import {SLOTS_PER_EPOCH} from "@lodestar/params"; import {createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {SyncCommitteeErrorCode} from "../../../../src/chain/errors/syncCommitteeError.js"; import {validateGossipSyncCommittee} from "../../../../src/chain/validation/syncCommittee.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {generateCachedAltairState} from "../../../utils/state.js"; import {SeenSyncCommitteeMessages} from "../../../../src/chain/seenCache/index.js"; import {ZERO_HASH} from "../../../../src/constants/constants.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; // https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/altair/p2p-interface.md describe("Sync Committee Signature validation", function () { diff --git a/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts b/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts index 2933fdc1ef77..3966815c28ce 100644 --- a/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts +++ b/packages/beacon-node/test/unit/chain/validation/voluntaryExit.test.ts @@ -11,12 +11,12 @@ import { import {phase0, ssz} from "@lodestar/types"; import {DOMAIN_VOLUNTARY_EXIT, FAR_FUTURE_EPOCH, SLOTS_PER_EPOCH} from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../../mocks/mockedBeaconChain.js"; import {generateState} from "../../../utils/state.js"; import {validateGossipVoluntaryExit} from "../../../../src/chain/validation/voluntaryExit.js"; import {VoluntaryExitErrorCode} from "../../../../src/chain/errors/voluntaryExitError.js"; import {expectRejectedWithLodestarError} from "../../../utils/errors.js"; import {createCachedBeaconStateTest} from "../../../utils/cachedBeaconState.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../../__mocks__/mockedBeaconChain.js"; describe("validate voluntary exit", () => { let chainStub: MockedBeaconChain; diff --git a/packages/beacon-node/test/unit/db/api/repository.test.ts b/packages/beacon-node/test/unit/db/api/repository.test.ts index 713ed0df88f2..07c199632125 100644 --- a/packages/beacon-node/test/unit/db/api/repository.test.ts +++ b/packages/beacon-node/test/unit/db/api/repository.test.ts @@ -87,18 +87,18 @@ describe("database repository", function () { it("should store with hashTreeRoot as id", async function () { const item = {bool: true, bytes: Buffer.alloc(32)}; - expect(repository.add(item)).not.rejects; + await expect(repository.add(item)).resolves.toBeUndefined(); expect(controller.put).toHaveBeenCalledTimes(1); }); it("should store with given id", async function () { const item = {bool: true, bytes: Buffer.alloc(32)}; - expect(repository.put("1", item)).not.rejects; + await expect(repository.put("1", item)).resolves.toBeUndefined(); expect(controller.put).toHaveBeenCalledTimes(1); }); it("should delete", async function () { - expect(repository.delete("1")).not.rejects; + await expect(repository.delete("1")).resolves.toBeUndefined(); expect(controller.delete).toHaveBeenCalledTimes(1); }); diff --git a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts index 37e4b84a3d68..d0bd3faffcf8 100644 --- a/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts +++ b/packages/beacon-node/test/unit/eth1/eth1DepositDataTracker.test.ts @@ -6,7 +6,7 @@ import {Eth1Provider} from "../../../src/eth1/provider/eth1Provider.js"; import {testLogger} from "../../utils/logger.js"; import {defaultEth1Options} from "../../../src/eth1/options.js"; import {BeaconDb} from "../../../src/db/beacon.js"; -import {getMockedBeaconDb} from "../../__mocks__/mockedBeaconDb.js"; +import {getMockedBeaconDb} from "../../mocks/mockedBeaconDb.js"; describe("Eth1DepositDataTracker", function () { const controller = new AbortController(); diff --git a/packages/beacon-node/test/unit/monitoring/service.test.ts b/packages/beacon-node/test/unit/monitoring/service.test.ts index 068f35634f81..c5911ba4b113 100644 --- a/packages/beacon-node/test/unit/monitoring/service.test.ts +++ b/packages/beacon-node/test/unit/monitoring/service.test.ts @@ -5,7 +5,7 @@ import {RegistryMetricCreator} from "../../../src/index.js"; import {MonitoringService} from "../../../src/monitoring/service.js"; import {MonitoringOptions} from "../../../src/monitoring/options.js"; import {sleep} from "../../utils/sleep.js"; -import {MockedLogger, getMockedLogger} from "../../__mocks__/loggerMock.js"; +import {MockedLogger, getMockedLogger} from "../../mocks/loggerMock.js"; import {startRemoteService, remoteServiceRoutes, remoteServiceError} from "./remoteService.js"; describe("monitoring / service", () => { diff --git a/packages/beacon-node/test/unit/network/peers/priorization.test.ts b/packages/beacon-node/test/unit/network/peers/priorization.test.ts index cc9ef9b7d711..3ec770051275 100644 --- a/packages/beacon-node/test/unit/network/peers/priorization.test.ts +++ b/packages/beacon-node/test/unit/network/peers/priorization.test.ts @@ -14,6 +14,7 @@ import {RequestedSubnet} from "../../../../src/network/peers/utils/index.js"; type Result = ReturnType; +// eslint-disable-next-line vitest/valid-describe-callback describe("network / peers / priorization", async () => { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { @@ -263,6 +264,7 @@ describe("network / peers / priorization", async () => { } }); +// eslint-disable-next-line vitest/valid-describe-callback describe("sortPeersToPrune", async function () { const peers: PeerId[] = []; for (let i = 0; i < 8; i++) { diff --git a/packages/beacon-node/test/unit/network/peers/score.test.ts b/packages/beacon-node/test/unit/network/peers/score.test.ts index 9c5402b5c888..df842f9a1310 100644 --- a/packages/beacon-node/test/unit/network/peers/score.test.ts +++ b/packages/beacon-node/test/unit/network/peers/score.test.ts @@ -9,10 +9,10 @@ import { RealScore, } from "../../../../src/network/peers/score/index.js"; -vi.mock("../../../../src/network/peers/score/index.js", async (requireActual) => { - const mod = await requireActual(); +vi.mock("../../../../src/network/peers/score/index.js", async (importActual) => { + const mod = await importActual(); - mod.PeerRpcScoreStore.prototype.updateGossipsubScore = vi.fn(); + vi.spyOn(mod.PeerRpcScoreStore.prototype, "updateGossipsubScore").mockImplementation(() => {}); return { ...mod, diff --git a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts index fb2fd7e78fdb..1c293fbb7640 100644 --- a/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts +++ b/packages/beacon-node/test/unit/network/subnets/attnetsService.test.ts @@ -112,7 +112,7 @@ describe("AttnetsService", function () { expect(metadata.seqNumber).toBe(BigInt(1)); expect(EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION * SLOTS_PER_EPOCH).toBeGreaterThan(150); vi.advanceTimersByTime(150 * SLOTS_PER_EPOCH * SECONDS_PER_SLOT * 1000); - expect(gossipStub.unsubscribeTopic).toHaveBeenCalled(); + expect(gossipStub.unsubscribeTopic).toHaveBeenCalledOnce(); // subscribe then unsubscribe expect(metadata.seqNumber).toBe(BigInt(2)); }); @@ -127,8 +127,8 @@ describe("AttnetsService", function () { vi.advanceTimersByTime(SLOTS_PER_EPOCH * SECONDS_PER_SLOT * 1000); } // may call 2 times, 1 for committee subnet, 1 for random subnet - expect(gossipStub.unsubscribeTopic).toHaveBeenCalled(); - // rebalance twice + expect(gossipStub.unsubscribeTopic).toHaveBeenCalledWith(expect.any(Object)); + // rebalanced twice expect(metadata.seqNumber).toBe(BigInt(2)); }); diff --git a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts index ebfe85eab09f..08ffdc4c3b02 100644 --- a/packages/beacon-node/test/unit/sync/backfill/verify.test.ts +++ b/packages/beacon-node/test/unit/sync/backfill/verify.test.ts @@ -25,7 +25,9 @@ describe("backfill sync - verify block sequence", function () { it("should verify valid chain of blocks", function () { const blocks = getBlocks(); - expect(() => verifyBlockSequence(beaconConfig, blocks.slice(0, 2), blocks[2].data.message.parentRoot)).to.not.throw; + expect(() => + verifyBlockSequence(beaconConfig, blocks.slice(0, 2), blocks[2].data.message.parentRoot) + ).not.toThrow(); }); it("should fail with sequence not anchored", function () { diff --git a/packages/beacon-node/test/unit/sync/range/batch.test.ts b/packages/beacon-node/test/unit/sync/range/batch.test.ts index acbfdcdb938b..caf8d5ea82e4 100644 --- a/packages/beacon-node/test/unit/sync/range/batch.test.ts +++ b/packages/beacon-node/test/unit/sync/range/batch.test.ts @@ -7,7 +7,7 @@ import {Batch, BatchStatus, BatchErrorCode, BatchError} from "../../../../src/sy import {EPOCHS_PER_BATCH} from "../../../../src/sync/constants.js"; import {BlockSource, getBlockInput} from "../../../../src/chain/blocks/types.js"; import {validPeerIdStr} from "../../../utils/peer.js"; -describe("sync / range / batch", async () => { +describe("sync / range / batch", () => { // Common mock data const startEpoch = 0; const peer = validPeerIdStr; diff --git a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts index 1da15ce7553b..a0a8be65dd28 100644 --- a/packages/beacon-node/test/unit/sync/unknownBlock.test.ts +++ b/packages/beacon-node/test/unit/sync/unknownBlock.test.ts @@ -6,18 +6,18 @@ import {createChainForkConfig} from "@lodestar/config"; import {IForkChoice, ProtoBlock} from "@lodestar/fork-choice"; import {ssz} from "@lodestar/types"; import {notNullish, sleep} from "@lodestar/utils"; +import {MockedBeaconChain, getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; import {IBeaconChain} from "../../../src/chain/index.js"; import {INetwork, NetworkEvent, NetworkEventBus, PeerAction} from "../../../src/network/index.js"; import {UnknownBlockSync} from "../../../src/sync/unknownBlock.js"; import {testLogger} from "../../utils/logger.js"; import {getRandPeerIdStr} from "../../utils/peer.js"; import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; -import {ClockStopped} from "../../utils/mocks/clock.js"; +import {ClockStopped} from "../../mocks/clock.js"; import {SeenBlockProposers} from "../../../src/chain/seenCache/seenBlockProposers.js"; import {BlockError, BlockErrorCode} from "../../../src/chain/errors/blockError.js"; import {defaultSyncOptions} from "../../../src/sync/options.js"; import {ZERO_HASH} from "../../../src/constants/constants.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../__mocks__/mockedBeaconChain.js"; describe("sync by UnknownBlockSync", () => { const logger = testLogger(); @@ -199,7 +199,7 @@ describe("sync by UnknownBlockSync", () => { const [_, requestedRoots] = await sendBeaconBlocksByRootPromise; await sleep(200); // should not send the invalid root block to chain - expect(processBlockSpy).toBeCalled(); + expect(processBlockSpy).toHaveBeenCalledOnce(); for (const requestedRoot of requestedRoots) { expect(syncService["pendingBlocks"].get(toHexString(requestedRoot))?.downloadAttempts).toEqual(1); } diff --git a/packages/beacon-node/test/unit/util/dependentRoot.test.ts b/packages/beacon-node/test/unit/util/dependentRoot.test.ts index e2f11acc3eba..e7923f111d0b 100644 --- a/packages/beacon-node/test/unit/util/dependentRoot.test.ts +++ b/packages/beacon-node/test/unit/util/dependentRoot.test.ts @@ -1,11 +1,12 @@ -import {describe, it, expect, beforeEach, afterEach, vi} from "vitest"; -import {EpochDifference, ProtoBlock} from "@lodestar/fork-choice"; +import {describe, it, expect, beforeEach, afterEach, vi, Mocked} from "vitest"; +import {EpochDifference, ProtoBlock, ForkChoice} from "@lodestar/fork-choice"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {getShufflingDependentRoot} from "../../../src/util/dependentRoot.js"; -import {MockedBeaconChain, getMockedBeaconChain} from "../../__mocks__/mockedBeaconChain.js"; + +vi.mock("@lodestar/fork-choice"); describe("util / getShufflingDependentRoot", () => { - let forkchoiceStub: MockedBeaconChain["forkChoice"]; + let forkchoiceStub: Mocked; const headBattHeadBlock = { slot: 100, @@ -13,7 +14,7 @@ describe("util / getShufflingDependentRoot", () => { const blockEpoch = computeEpochAtSlot(headBattHeadBlock.slot); beforeEach(() => { - forkchoiceStub = getMockedBeaconChain().forkChoice; + forkchoiceStub = vi.mocked(new ForkChoice({} as any, {} as any, {} as any)); }); afterEach(() => { @@ -29,7 +30,7 @@ describe("util / getShufflingDependentRoot", () => { throw new Error("should not be called"); } }); - expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).to.be.equal("current"); + expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toEqual("current"); }); it("should return next dependent root", () => { @@ -42,7 +43,7 @@ describe("util / getShufflingDependentRoot", () => { throw new Error("should not be called"); } }); - expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).to.be.equal("0x000"); + expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toEqual("0x000"); }); it("should return head block root as dependent root", () => { @@ -51,7 +52,7 @@ describe("util / getShufflingDependentRoot", () => { forkchoiceStub.getDependentRoot.mockImplementation(() => { throw Error("should not be called"); }); - expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).to.be.equal( + expect(getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toEqual( headBattHeadBlock.blockRoot ); }); @@ -62,6 +63,6 @@ describe("util / getShufflingDependentRoot", () => { forkchoiceStub.getDependentRoot.mockImplementation(() => { throw Error("should not be called"); }); - expect(() => getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).to.throw(); + expect(() => getShufflingDependentRoot(forkchoiceStub, attEpoch, blockEpoch, headBattHeadBlock)).toThrow(); }); }); diff --git a/packages/beacon-node/test/unit/util/kzg.test.ts b/packages/beacon-node/test/unit/util/kzg.test.ts index cfe35e8fc76e..e170aed1a2de 100644 --- a/packages/beacon-node/test/unit/util/kzg.test.ts +++ b/packages/beacon-node/test/unit/util/kzg.test.ts @@ -2,12 +2,12 @@ import {describe, it, expect, afterEach, beforeAll} from "vitest"; import {bellatrix, deneb, ssz} from "@lodestar/types"; import {BYTES_PER_FIELD_ELEMENT, BLOB_TX_TYPE} from "@lodestar/params"; import {createBeaconConfig, createChainForkConfig, defaultChainConfig} from "@lodestar/config"; +import {getMockedBeaconChain} from "../../mocks/mockedBeaconChain.js"; import {computeBlobSidecars, kzgCommitmentToVersionedHash} from "../../../src/util/blobs.js"; import {loadEthereumTrustedSetup, initCKZG, ckzg, FIELD_ELEMENTS_PER_BLOB_MAINNET} from "../../../src/util/kzg.js"; import {validateBlobSidecars, validateGossipBlobSidecar} from "../../../src/chain/validation/blobSidecar.js"; -import {getMockedBeaconChain} from "../../__mocks__/mockedBeaconChain.js"; -describe("C-KZG", async () => { +describe("C-KZG", () => { const afterEachCallbacks: (() => Promise | void)[] = []; afterEach(async () => { while (afterEachCallbacks.length > 0) { diff --git a/packages/beacon-node/test/utils/api.ts b/packages/beacon-node/test/utils/api.ts new file mode 100644 index 000000000000..41face1ae737 --- /dev/null +++ b/packages/beacon-node/test/utils/api.ts @@ -0,0 +1,36 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import {Mocked} from "vitest"; +import {config} from "@lodestar/config/default"; +import {ForkChoice} from "@lodestar/fork-choice"; +import {MockedBeaconChain, getMockedBeaconChain} from "../mocks/mockedBeaconChain.js"; +import {getMockedBeaconSync} from "../mocks/beaconSyncMock.js"; +import {MockedBeaconDb, getMockedBeaconDb} from "../mocks/mockedBeaconDb.js"; +import {getMockedNetwork} from "../mocks/mockedNetwork.js"; +import {ApiModules} from "../../src/api/index.js"; + +type ApiModulesWithoutConfig = Omit; + +export type ApiTestModules = {[K in keyof ApiModulesWithoutConfig]: Mocked} & { + chain: MockedBeaconChain; + forkChoice: Mocked; + db: MockedBeaconDb; + config: ApiModules["config"]; +}; + +export function getApiTestModules(): ApiTestModules { + const chainStub = getMockedBeaconChain(); + const syncStub = getMockedBeaconSync(); + const dbStub = getMockedBeaconDb(); + const networkStub = getMockedNetwork(); + + return { + config, + chain: chainStub, + sync: syncStub, + db: dbStub, + network: networkStub, + logger: chainStub.logger, + forkChoice: chainStub.forkChoice, + metrics: null, + }; +} diff --git a/packages/beacon-node/test/utils/logger.ts b/packages/beacon-node/test/utils/logger.ts index b3382cc221e2..1c1526514565 100644 --- a/packages/beacon-node/test/utils/logger.ts +++ b/packages/beacon-node/test/utils/logger.ts @@ -8,9 +8,9 @@ export type TestLoggerOpts = LoggerNodeOpts; /** * Run the test with ENVs to control log level: * ``` - * LOG_LEVEL=debug mocha .ts - * DEBUG=1 mocha .ts - * VERBOSE=1 mocha .ts + * LOG_LEVEL=debug vitest .ts + * DEBUG=1 vitest .ts + * VERBOSE=1 vitest .ts * ``` */ export const testLogger = (module?: string, opts?: TestLoggerOpts): LoggerNode => { diff --git a/packages/beacon-node/test/utils/mocks/chain.ts b/packages/beacon-node/test/utils/mocks/chain.ts deleted file mode 100644 index 9704b3a3f825..000000000000 --- a/packages/beacon-node/test/utils/mocks/chain.ts +++ /dev/null @@ -1,33 +0,0 @@ -import sinon from "sinon"; -import {IForkChoice, ProtoBlock, ExecutionStatus, ForkChoice} from "@lodestar/fork-choice"; -import {IBeaconChain, BeaconChain} from "../../../src/chain/index.js"; -import {ZERO_HASH_HEX} from "../../../src/constants/constants.js"; -import {StubbedChainMutable, StubbedOf} from "../stub/index.js"; -import {Mutable} from "../types.js"; - -export function getMockBeaconChain(): StubbedChainMutable { - return sinon.createStubInstance(BeaconChain) as StubbedChainMutable; -} - -export function getMockForkChoice(): StubbedOf> { - return sinon.createStubInstance(ForkChoice) as StubbedOf>; -} - -export const zeroProtoBlock: ProtoBlock = { - slot: 0, - blockRoot: ZERO_HASH_HEX, - parentRoot: ZERO_HASH_HEX, - stateRoot: ZERO_HASH_HEX, - targetRoot: ZERO_HASH_HEX, - - justifiedEpoch: 0, - justifiedRoot: ZERO_HASH_HEX, - finalizedEpoch: 0, - finalizedRoot: ZERO_HASH_HEX, - unrealizedJustifiedEpoch: 0, - unrealizedJustifiedRoot: ZERO_HASH_HEX, - unrealizedFinalizedEpoch: 0, - unrealizedFinalizedRoot: ZERO_HASH_HEX, - - ...{executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}, -}; diff --git a/packages/beacon-node/test/utils/mocks/db.ts b/packages/beacon-node/test/utils/mocks/db.ts deleted file mode 100644 index 16d7b32a1bcc..000000000000 --- a/packages/beacon-node/test/utils/mocks/db.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {IBeaconDb} from "../../../src/db/index.js"; -import {CheckpointStateRepository} from "../../../src/db/repositories/checkpointState.js"; -import { - AttesterSlashingRepository, - BlockArchiveRepository, - BlockRepository, - DepositEventRepository, - DepositDataRootRepository, - Eth1DataRepository, - ProposerSlashingRepository, - StateArchiveRepository, - VoluntaryExitRepository, - BestLightClientUpdateRepository, - CheckpointHeaderRepository, - SyncCommitteeRepository, - SyncCommitteeWitnessRepository, - BackfilledRanges, - BlobSidecarsRepository, - BlobSidecarsArchiveRepository, - BLSToExecutionChangeRepository, -} from "../../../src/db/repositories/index.js"; -import {PreGenesisState, PreGenesisStateLastProcessedBlock} from "../../../src/db/single/index.js"; -import {createStubInstance} from "../types.js"; - -/* eslint-disable @typescript-eslint/no-empty-function */ - -/** - * Stubbed BeaconDb that ignores all DELETE and PUT actions, and returns void on all GET actions - */ -export function getStubbedBeaconDb(): IBeaconDb { - return { - // unfinalized blocks - block: createStubInstance(BlockRepository), - // finalized blocks - blockArchive: createStubInstance(BlockArchiveRepository), - - blobSidecars: createStubInstance(BlobSidecarsRepository), - blobSidecarsArchive: createStubInstance(BlobSidecarsArchiveRepository), - - // finalized states - stateArchive: createStubInstance(StateArchiveRepository), - checkpointState: createStubInstance(CheckpointStateRepository), - - // op pool - voluntaryExit: createStubInstance(VoluntaryExitRepository), - proposerSlashing: createStubInstance(ProposerSlashingRepository), - attesterSlashing: createStubInstance(AttesterSlashingRepository), - depositEvent: createStubInstance(DepositEventRepository), - blsToExecutionChange: createStubInstance(BLSToExecutionChangeRepository), - - // eth1 processing - preGenesisState: createStubInstance(PreGenesisState), - preGenesisStateLastProcessedBlock: createStubInstance(PreGenesisStateLastProcessedBlock), - - // all deposit data roots and merkle tree - depositDataRoot: createStubInstance(DepositDataRootRepository), - eth1Data: createStubInstance(Eth1DataRepository), - - // lightclient - bestLightClientUpdate: createStubInstance(BestLightClientUpdateRepository), - checkpointHeader: createStubInstance(CheckpointHeaderRepository), - syncCommittee: createStubInstance(SyncCommitteeRepository), - syncCommitteeWitness: createStubInstance(SyncCommitteeWitnessRepository), - - backfilledRanges: createStubInstance(BackfilledRanges), - - async close(): Promise {}, - /** To inject metrics after CLI initialization */ - setMetrics(): void {}, - async pruneHotDb(): Promise {}, - }; -} diff --git a/packages/beacon-node/test/utils/mocks/logger.ts b/packages/beacon-node/test/utils/mocks/logger.ts deleted file mode 100644 index d827805fa648..000000000000 --- a/packages/beacon-node/test/utils/mocks/logger.ts +++ /dev/null @@ -1,15 +0,0 @@ -import sinon, {SinonSandbox, SinonStubbedInstance} from "sinon"; -import {LoggerNode} from "@lodestar/logger/node"; - -export const createStubbedLogger = (sandbox?: SinonSandbox): LoggerNode & SinonStubbedInstance => { - sandbox = sandbox ?? sinon; - return { - debug: sandbox.stub(), - info: sandbox.stub(), - error: sandbox.stub(), - warn: sandbox.stub(), - verbose: sandbox.stub(), - child: sandbox.stub(), - toOpts: sandbox.stub(), - } as unknown as LoggerNode & SinonStubbedInstance; -}; diff --git a/packages/beacon-node/test/utils/network.ts b/packages/beacon-node/test/utils/network.ts index 5b0cdbe04b6c..56c831b269f5 100644 --- a/packages/beacon-node/test/utils/network.ts +++ b/packages/beacon-node/test/utils/network.ts @@ -1,30 +1,12 @@ +import {BitArray} from "@chainsafe/ssz"; import {PeerId} from "@libp2p/interface"; import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; -import {BitArray} from "@chainsafe/ssz"; import {ATTESTATION_SUBNET_COUNT, SYNC_COMMITTEE_SUBNET_COUNT} from "@lodestar/params"; -import {ssz} from "@lodestar/types"; -import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; -import { - GossipHandlers, - INetwork, - Network, - NetworkEvent, - NetworkInitModules, - getReqRespHandlers, -} from "../../src/network/index.js"; -import {createNodeJsLibp2p} from "../../src/network/libp2p/index.js"; +import {INetwork, Network, NetworkEvent} from "../../src/network/index.js"; import {Libp2p} from "../../src/network/interface.js"; -import {GetReqRespHandlerFn} from "../../src/network/reqresp/types.js"; -import {Eth1ForBlockProductionDisabled} from "../../src/eth1/index.js"; -import {defaultNetworkOptions, NetworkOptions} from "../../src/network/options.js"; -import {BeaconChain} from "../../src/chain/chain.js"; -import {ExecutionEngineDisabled} from "../../src/execution/index.js"; +import {createNodeJsLibp2p} from "../../src/network/libp2p/index.js"; +import {NetworkOptions, defaultNetworkOptions} from "../../src/network/options.js"; import {PeerIdStr} from "../../src/util/peerId.js"; -import {testLogger} from "./logger.js"; -import {generateState} from "./state.js"; -import {getStubbedBeaconDb} from "./mocks/db.js"; -import {ClockStatic} from "./clock.js"; -import {createCachedBeaconStateTest} from "./cachedBeaconState.js"; export async function createNode(multiaddr: string, inPeerId?: PeerId): Promise { const peerId = inPeerId || (await createSecp256k1PeerId()); @@ -42,101 +24,6 @@ export async function createNetworkModules( }; } -export type NetworkForTestOpts = { - startSlot?: number; - opts?: Partial; - gossipHandlersPartial?: Partial; - getReqRespHandler?: GetReqRespHandlerFn; -}; - -export async function getNetworkForTest( - loggerId: string, - config: ChainForkConfig, - opts: NetworkForTestOpts -): Promise<[network: Network, closeAll: () => Promise]> { - const logger = testLogger(loggerId); - const startSlot = opts.startSlot ?? 0; - - const block = ssz.phase0.SignedBeaconBlock.defaultValue(); - const state = generateState( - { - slot: startSlot, - finalizedCheckpoint: { - epoch: 0, - root: ssz.phase0.BeaconBlock.hashTreeRoot(block.message), - }, - }, - config - ); - - const beaconConfig = createBeaconConfig(config, state.genesisValidatorsRoot); - const db = getStubbedBeaconDb(); - - const chain = new BeaconChain( - { - safeSlotsToImportOptimistically: 0, - archiveStateEpochFrequency: 0, - suggestedFeeRecipient: "", - blsVerifyAllMainThread: true, - disableOnBlockError: true, - disableArchiveOnCheckpoint: true, - disableLightClientServerOnImportBlockHead: true, - disablePrepareNextSlot: true, - minSameMessageSignatureSetsToBatch: 32, - }, - { - config: beaconConfig, - db, - logger, - // eslint-disable-next-line @typescript-eslint/no-empty-function - processShutdownCallback: () => {}, - // set genesis time so that we are at ALTAIR_FORK_EPOCH - // sinon mock timer does not work on worker thread - clock: new ClockStatic(startSlot, Math.floor(Date.now() / 1000) - startSlot * beaconConfig.SECONDS_PER_SLOT), - metrics: null, - anchorState: createCachedBeaconStateTest(state, beaconConfig), - eth1: new Eth1ForBlockProductionDisabled(), - executionEngine: new ExecutionEngineDisabled(), - } - ); - - const modules: Omit = { - config: beaconConfig, - chain, - db, - getReqRespHandler: opts.getReqRespHandler ?? getReqRespHandlers({db, chain}), - gossipHandlers: opts.gossipHandlersPartial as GossipHandlers, - metrics: null, - }; - - const network = await Network.init({ - ...modules, - peerId: await createSecp256k1PeerId(), - opts: { - ...defaultNetworkOptions, - maxPeers: 1, - targetPeers: 1, - bootMultiaddrs: [], - localMultiaddrs: ["/ip4/127.0.0.1/tcp/0"], - discv5FirstQueryDelayMs: 0, - discv5: null, - skipParamsLog: true, - // Disable rate limiting - rateLimitMultiplier: 0, - ...opts.opts, - }, - logger, - }); - - return [ - network, - async function closeAll() { - await network.close(); - await chain.close(); - }, - ]; -} - export async function getPeerIdOf(net: INetwork): Promise { return (await net.getNetworkIdentity()).peerId; } diff --git a/packages/beacon-node/test/utils/networkWithMockDb.ts b/packages/beacon-node/test/utils/networkWithMockDb.ts new file mode 100644 index 000000000000..3eea47892a0f --- /dev/null +++ b/packages/beacon-node/test/utils/networkWithMockDb.ts @@ -0,0 +1,109 @@ +import {createSecp256k1PeerId} from "@libp2p/peer-id-factory"; +import {ChainForkConfig, createBeaconConfig} from "@lodestar/config"; +import {ssz} from "@lodestar/types"; +import {BeaconChain} from "../../src/chain/chain.js"; +import {Eth1ForBlockProductionDisabled} from "../../src/eth1/index.js"; +import {ExecutionEngineDisabled} from "../../src/execution/index.js"; +import {GossipHandlers, Network, NetworkInitModules, getReqRespHandlers} from "../../src/network/index.js"; +import {NetworkOptions, defaultNetworkOptions} from "../../src/network/options.js"; +import {GetReqRespHandlerFn} from "../../src/network/reqresp/types.js"; +import {getMockedBeaconDb} from "../mocks/mockedBeaconDb.js"; +import {createCachedBeaconStateTest} from "./cachedBeaconState.js"; +import {ClockStatic} from "./clock.js"; +import {testLogger} from "./logger.js"; +import {generateState} from "./state.js"; + +export type NetworkForTestOpts = { + startSlot?: number; + opts?: Partial; + gossipHandlersPartial?: Partial; + getReqRespHandler?: GetReqRespHandlerFn; +}; + +export async function getNetworkForTest( + loggerId: string, + config: ChainForkConfig, + opts: NetworkForTestOpts +): Promise<[network: Network, closeAll: () => Promise]> { + const logger = testLogger(loggerId); + const startSlot = opts.startSlot ?? 0; + + const block = ssz.phase0.SignedBeaconBlock.defaultValue(); + const state = generateState( + { + slot: startSlot, + finalizedCheckpoint: { + epoch: 0, + root: ssz.phase0.BeaconBlock.hashTreeRoot(block.message), + }, + }, + config + ); + + const beaconConfig = createBeaconConfig(config, state.genesisValidatorsRoot); + const db = getMockedBeaconDb(); + + const chain = new BeaconChain( + { + safeSlotsToImportOptimistically: 0, + archiveStateEpochFrequency: 0, + suggestedFeeRecipient: "", + blsVerifyAllMainThread: true, + disableOnBlockError: true, + disableArchiveOnCheckpoint: true, + disableLightClientServerOnImportBlockHead: true, + disablePrepareNextSlot: true, + minSameMessageSignatureSetsToBatch: 32, + }, + { + config: beaconConfig, + db, + logger, + // eslint-disable-next-line @typescript-eslint/no-empty-function + processShutdownCallback: () => {}, + // set genesis time so that we are at ALTAIR_FORK_EPOCH + // mock timer does not work on worker thread + clock: new ClockStatic(startSlot, Math.floor(Date.now() / 1000) - startSlot * beaconConfig.SECONDS_PER_SLOT), + metrics: null, + anchorState: createCachedBeaconStateTest(state, beaconConfig), + eth1: new Eth1ForBlockProductionDisabled(), + executionEngine: new ExecutionEngineDisabled(), + } + ); + + const modules: Omit = { + config: beaconConfig, + chain, + db, + getReqRespHandler: opts.getReqRespHandler ?? getReqRespHandlers({db, chain}), + gossipHandlers: opts.gossipHandlersPartial as GossipHandlers, + metrics: null, + }; + + const network = await Network.init({ + ...modules, + peerId: await createSecp256k1PeerId(), + opts: { + ...defaultNetworkOptions, + maxPeers: 1, + targetPeers: 1, + bootMultiaddrs: [], + localMultiaddrs: ["/ip4/127.0.0.1/tcp/0"], + discv5FirstQueryDelayMs: 0, + discv5: null, + skipParamsLog: true, + // Disable rate limiting + rateLimitMultiplier: 0, + ...opts.opts, + }, + logger, + }); + + return [ + network, + async function closeAll() { + await network.close(); + await chain.close(); + }, + ]; +} diff --git a/packages/beacon-node/test/utils/sinon/matcher.ts b/packages/beacon-node/test/utils/sinon/matcher.ts deleted file mode 100644 index 3fff4826579c..000000000000 --- a/packages/beacon-node/test/utils/sinon/matcher.ts +++ /dev/null @@ -1,8 +0,0 @@ -import sinon, {SinonMatcher} from "sinon"; -import {toHexString} from "@chainsafe/ssz"; - -export const bufferEqualsMatcher = (expected: Buffer): SinonMatcher => { - return sinon.match((value) => { - return toHexString(expected) === toHexString(value); - }); -}; diff --git a/packages/beacon-node/test/utils/state.ts b/packages/beacon-node/test/utils/state.ts index 64c223acf4ea..a0fa42be555e 100644 --- a/packages/beacon-node/test/utils/state.ts +++ b/packages/beacon-node/test/utils/state.ts @@ -12,6 +12,8 @@ import {allForks, altair, bellatrix, ssz} from "@lodestar/types"; import {createBeaconConfig, ChainForkConfig} from "@lodestar/config"; import {FAR_FUTURE_EPOCH, ForkName, ForkSeq, MAX_EFFECTIVE_BALANCE, SYNC_COMMITTEE_SIZE} from "@lodestar/params"; +import {ExecutionStatus, ProtoBlock} from "@lodestar/fork-choice"; +import {ZERO_HASH_HEX} from "../../src/constants/constants.js"; import {generateValidator, generateValidators} from "./validator.js"; import {getConfig} from "./config.js"; @@ -134,3 +136,22 @@ export function generateCachedBellatrixState(opts?: TestBeaconState): CachedBeac index2pubkey: [], }); } + +export const zeroProtoBlock: ProtoBlock = { + slot: 0, + blockRoot: ZERO_HASH_HEX, + parentRoot: ZERO_HASH_HEX, + stateRoot: ZERO_HASH_HEX, + targetRoot: ZERO_HASH_HEX, + + justifiedEpoch: 0, + justifiedRoot: ZERO_HASH_HEX, + finalizedEpoch: 0, + finalizedRoot: ZERO_HASH_HEX, + unrealizedJustifiedEpoch: 0, + unrealizedJustifiedRoot: ZERO_HASH_HEX, + unrealizedFinalizedEpoch: 0, + unrealizedFinalizedRoot: ZERO_HASH_HEX, + + ...{executionPayloadBlockHash: null, executionStatus: ExecutionStatus.PreMerge}, +}; diff --git a/packages/beacon-node/test/utils/stub/index.ts b/packages/beacon-node/test/utils/stub/index.ts deleted file mode 100644 index a0eba06d0cf0..000000000000 --- a/packages/beacon-node/test/utils/stub/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {SinonStubbedInstance} from "sinon"; -import {IBeaconChain} from "../../../src/chain/index.js"; -import {Mutable} from "../types.js"; - -export type StubbedChain = IBeaconChain & SinonStubbedInstance; -export type StubbedOf = T & SinonStubbedInstance; - -/** Helper type to make dependencies mutable for validation tests */ -export type StubbedChainMutable = StubbedOf>; diff --git a/packages/beacon-node/test/utils/types.ts b/packages/beacon-node/test/utils/types.ts index a3d2f65bb892..1368c67282be 100644 --- a/packages/beacon-node/test/utils/types.ts +++ b/packages/beacon-node/test/utils/types.ts @@ -1,15 +1 @@ -import sinon from "sinon"; -import {SinonStub, SinonStubbedInstance} from "sinon"; - -export type SinonStubFn any> = T extends (...args: infer TArgs) => infer TReturnValue - ? SinonStub - : never; - -// eslint-disable-next-line @typescript-eslint/ban-types -type StubbableType = Function & {prototype: TType}; - -export function createStubInstance(constructor: StubbableType): SinonStubbedInstance & TType { - return sinon.createStubInstance(constructor) as SinonStubbedInstance & TType; -} - export type Mutable = Omit & {-readonly [key in K]: T[key]}; diff --git a/packages/beacon-node/vitest.config.e2e.ts b/packages/beacon-node/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/beacon-node/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/beacon-node/vitest.config.spec.ts b/packages/beacon-node/vitest.config.spec.ts index e5f588d17155..f4f301c7985f 100644 --- a/packages/beacon-node/vitest.config.spec.ts +++ b/packages/beacon-node/vitest.config.spec.ts @@ -1,19 +1,11 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.spec.config"; export default mergeConfig( vitestConfig, defineConfig({ test: { globalSetup: ["./test/globalSetup.ts"], - testTimeout: 60_000, - passWithNoTests: true, - pool: "threads", - poolOptions: { - threads: { - isolate: false, - }, - }, }, }) ); diff --git a/packages/beacon-node/vitest.config.ts b/packages/beacon-node/vitest.config.ts index 2a2b2c65304c..dbf15c3408f0 100644 --- a/packages/beacon-node/vitest.config.ts +++ b/packages/beacon-node/vitest.config.ts @@ -1,6 +1,6 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; import {buildTargetPlugin} from "../../scripts/vitest/plugins/buildTargetPlugin.js"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/cli/package.json b/packages/cli/package.json index 594ef5ebbb67..243dee688417 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -31,8 +31,8 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit/ --coverage", - "test:e2e": "vitest --run --poolOptions.threads.singleThread true --dir test/e2e/", + "test:unit": "vitest --run --dir test/unit/", + "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", "test:sim:multifork": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/multi_fork.test.ts", "test:sim:mixedclient": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/mixed_client.test.ts", "test:sim:endpoints": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/endpoints.test.ts", diff --git a/packages/cli/test/sim/endpoints.test.ts b/packages/cli/test/sim/endpoints.test.ts index 536e7ea24aa3..ea55b70e26c1 100644 --- a/packages/cli/test/sim/endpoints.test.ts +++ b/packages/cli/test/sim/endpoints.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import path from "node:path"; +import assert from "node:assert"; import {toHexString} from "@chainsafe/ssz"; -import {expect} from "chai"; import {ApiError, routes} from "@lodestar/api"; import {SimulationEnvironment} from "../utils/simulation/SimulationEnvironment.js"; import {BeaconClient, ExecutionClient} from "../utils/simulation/interfaces.js"; @@ -44,15 +44,15 @@ ApiError.assert(res); const stateValidators = res.response.data; await env.tracker.assert("should have correct validators count called without filters", async () => { - expect(stateValidators.length).to.be.equal(validatorCount); + assert.equal(stateValidators.length, validatorCount); }); await env.tracker.assert("should have correct validator index for first validator filters", async () => { - expect(stateValidators[0].index).to.be.equal(0); + assert.equal(stateValidators[0].index, 0); }); await env.tracker.assert("should have correct validator index for second validator filters", async () => { - expect(stateValidators[1].index).to.be.equal(1); + assert.equal(stateValidators[1].index, 1); }); await env.tracker.assert( @@ -66,7 +66,7 @@ await env.tracker.assert( }); ApiError.assert(res); - expect(res.response.data.length).to.be.equal(1); + assert.equal(res.response.data.length, 1); } ); @@ -81,7 +81,7 @@ await env.tracker.assert( }); ApiError.assert(res); - expect(toHexString(res.response.data[0].validator.pubkey)).to.be.equal(filterPubKey); + assert.equal(toHexString(res.response.data[0].validator.pubkey), filterPubKey); } ); @@ -93,7 +93,7 @@ await env.tracker.assert( const res = await node.api.beacon.getStateValidator("head", validatorIndex); ApiError.assert(res); - expect(res.response.data.index).to.be.equal(validatorIndex); + assert.equal(res.response.data.index, validatorIndex); } ); @@ -106,7 +106,7 @@ await env.tracker.assert( const res = await node.api.beacon.getStateValidator("head", hexPubKey); ApiError.assert(res); - expect(toHexString(res.response.data.validator.pubkey)).to.be.equal(hexPubKey); + assert.equal(toHexString(res.response.data.validator.pubkey), hexPubKey); } ); @@ -122,13 +122,13 @@ await env.tracker.assert("BN Not Synced", async () => { const res = await node.api.node.getSyncingStatus(); ApiError.assert(res); - expect(res.response.data).to.be.deep.equal(expectedSyncStatus); + assert.deepEqual(res.response.data, expectedSyncStatus); }); await env.tracker.assert("Return READY pre genesis", async () => { const {status} = await node.api.node.getHealth(); - expect(status).to.be.equal(routes.node.NodeHealth.READY); + assert.equal(status, routes.node.NodeHealth.READY); }); await env.stop(); diff --git a/packages/cli/test/utils.ts b/packages/cli/test/utils.ts index d4957240cbaf..81136c0a18d4 100644 --- a/packages/cli/test/utils.ts +++ b/packages/cli/test/utils.ts @@ -15,9 +15,9 @@ export type TestLoggerOpts = LoggerNodeOpts; /** * Run the test with ENVs to control log level: * ``` - * LOG_LEVEL=debug mocha .ts - * DEBUG=1 mocha .ts - * VERBOSE=1 mocha .ts + * LOG_LEVEL=debug vitest .ts + * DEBUG=1 vitest .ts + * VERBOSE=1 vitest .ts * ``` */ export const testLogger = (module?: string, opts?: TestLoggerOpts): LoggerNode => { diff --git a/packages/cli/vitest.config.e2e.ts b/packages/cli/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/cli/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/cli/vitest.config.ts b/packages/cli/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/cli/vitest.config.ts +++ b/packages/cli/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/config/package.json b/packages/config/package.json index ed79bd700cfb..c52a070b69fd 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -50,7 +50,7 @@ "lint": "eslint --color --ext .ts src/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "yarn vitest --run --dir test/unit/ --coverage", + "test:unit": "yarn vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/config/vitest.config.ts b/packages/config/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/config/vitest.config.ts +++ b/packages/config/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/db/package.json b/packages/db/package.json index 13ffff098279..d99b21d80b9b 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -33,7 +33,7 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "dependencies": { diff --git a/packages/db/vitest.config.ts b/packages/db/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/db/vitest.config.ts +++ b/packages/db/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/flare/package.json b/packages/flare/package.json index d3849d1b5362..7417cf93c63d 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -44,7 +44,7 @@ "lint": "eslint --color --ext .ts src/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/flare/vitest.config.ts b/packages/flare/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/flare/vitest.config.ts +++ b/packages/flare/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index b19fa976bdf4..495c67a8e80b 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -34,7 +34,7 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "dependencies": { diff --git a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts index 54b8a900d05c..fde551d43cda 100644 --- a/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts +++ b/packages/fork-choice/test/unit/protoArray/computeDeltas.test.ts @@ -132,52 +132,6 @@ describe("computeDeltas", () => { } }); - /** - * Starting Aug 2023, this test case is not valid because when an attestation is added - * to forkchoice, the block should come first, i.e. nextIndex should be a number - */ - // it("move out of tree", () => { - // const balance = 42; - - // const indices = new Map(); - // // there is only one block - // indices.set("2", 0); - - // // There are two validators - // const votes = [ - // // one validator moves their vote from the block to the zero hash - // { - // currentRoot: "2", - // nextRoot: "0", - // nextEpoch: 0, - // }, - // // one validator moves their vote from the block to something outside the tree - // { - // currentRoot: "2", - // nextRoot: "1337", - // nextEpoch: 0, - // }, - // ]; - - // const oldBalances = getEffectiveBalanceIncrementsZeroed(votes.length); - // const newBalances = getEffectiveBalanceIncrementsZeroed(votes.length); - // for (const balances of [oldBalances, newBalances]) { - // for (let i = 0; i < votes.length; i++) { - // balances[i] = balance; - // } - // } - - // const deltas = computeDeltas(indices, votes, oldBalances, newBalances, new Set()); - - // expect(deltas.length).to.eql(1); - - // expect(deltas[0].toString()).to.eql((0 - balance * 2).toString()); - - // for (const vote of votes) { - // expect(vote.currentRoot).to.equal(vote.nextRoot); - // } - // }); - it("changing balances", () => { const oldBalance = 42; const newBalance = 42 * 2; diff --git a/packages/fork-choice/vitest.config.ts b/packages/fork-choice/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/fork-choice/vitest.config.ts +++ b/packages/fork-choice/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/light-client/package.json b/packages/light-client/package.json index f34fe11601e8..dee231409730 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -59,7 +59,7 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/light-client/test/utils/utils.ts b/packages/light-client/test/utils/utils.ts index 455d6ef9997b..930cabfdad11 100644 --- a/packages/light-client/test/utils/utils.ts +++ b/packages/light-client/test/utils/utils.ts @@ -22,7 +22,7 @@ const CURRENT_SYNC_COMMITTEE_DEPTH = 5; /** * To enable debug logs run with * ``` - * DEBUG=true mocha ... + * DEBUG=true vitest ... * ``` */ export const testLogger = getLcLoggerConsole({logDebug: Boolean(process.env.DEBUG)}); diff --git a/packages/light-client/vitest.config.ts b/packages/light-client/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/light-client/vitest.config.ts +++ b/packages/light-client/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/logger/package.json b/packages/logger/package.json index e8cc7d5f9622..2f450ee5be12 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -56,12 +56,12 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e", "check-readme": "typescript-docs-verifier" }, "types": "lib/index.d.ts", diff --git a/packages/logger/test/unit/browser.test.ts b/packages/logger/test/unit/browser.test.ts index e2160418663a..591437450c2d 100644 --- a/packages/logger/test/unit/browser.test.ts +++ b/packages/logger/test/unit/browser.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect} from "vitest"; import {LogLevel} from "@lodestar/utils"; -import {stubLoggerForConsole} from "@lodestar/test-utils/mocha"; +import {stubLoggerForConsole} from "@lodestar/test-utils/doubles"; import {TimestampFormatCode, logFormats} from "../../src/index.js"; import {formatsTestCases} from "../fixtures/loggerFormats.js"; import {getBrowserLogger} from "../../src/browser.js"; diff --git a/packages/logger/test/unit/env.node.test.ts b/packages/logger/test/unit/env.node.test.ts index 4d2b914ca7f4..4bd4df689adf 100644 --- a/packages/logger/test/unit/env.node.test.ts +++ b/packages/logger/test/unit/env.node.test.ts @@ -1,6 +1,6 @@ import {describe, it, expect} from "vitest"; import {LogLevel} from "@lodestar/utils"; -import {stubLoggerForConsole} from "@lodestar/test-utils/mocha"; +import {stubLoggerForConsole} from "@lodestar/test-utils/doubles"; import {TimestampFormatCode, logFormats} from "../../src/index.js"; import {formatsTestCases} from "../fixtures/loggerFormats.js"; import {getEnvLogger} from "../../src/env.js"; diff --git a/packages/logger/vitest.config.e2e.ts b/packages/logger/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/logger/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/logger/vitest.config.ts b/packages/logger/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/logger/vitest.config.ts +++ b/packages/logger/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/params/package.json b/packages/params/package.json index 7861da84424d..2586c73566aa 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -53,12 +53,12 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "test": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --dir test/e2e/", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e/", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/params/test/e2e/setPresetOk.ts b/packages/params/test/e2e/setPresetOk.ts index 8ab718337022..5e76149b293a 100644 --- a/packages/params/test/e2e/setPresetOk.ts +++ b/packages/params/test/e2e/setPresetOk.ts @@ -7,9 +7,9 @@ import {setActivePreset, PresetName} from "../../src/setPreset.js"; setActivePreset(PresetName.minimal); // 2. Import from any other @lodestar/params paths -import {expect} from "chai"; +import assert from "node:assert"; const {SLOTS_PER_EPOCH} = await import("../../src/index.js"); -expect(SLOTS_PER_EPOCH).to.equal(8, "SLOTS_PER_EPOCH should have minimal preset value"); -expect(process.env.LODESTAR_PRESET).to.equal(undefined, "LODESTAR_PRESET ENV must not be set"); +assert.equal(SLOTS_PER_EPOCH, 8, "SLOTS_PER_EPOCH should have minimal preset value"); +assert.equal(process.env.LODESTAR_PRESET, undefined, "LODESTAR_PRESET ENV must not be set"); diff --git a/packages/params/test/unit/activePreset.test.ts b/packages/params/test/unit/activePreset.test.ts index eceda7eaac92..3aeee69672a1 100644 --- a/packages/params/test/unit/activePreset.test.ts +++ b/packages/params/test/unit/activePreset.test.ts @@ -1,4 +1,4 @@ -import {describe, it, expect} from "vitest"; +import {describe, it, expect, beforeAll} from "vitest"; import {mainnetPreset} from "../../src/presets/mainnet.js"; import {minimalPreset} from "../../src/presets/minimal.js"; import {gnosisPreset as gnosisParams} from "../../src/presets/gnosis.js"; @@ -6,8 +6,13 @@ import {ACTIVE_PRESET, PresetName} from "../../src/index.js"; import {setActivePreset} from "../../src/setPreset.js"; import {setActivePreset as setActivePresetLib} from "../../src/setPreset.js"; -describe("active preset", async () => { - const exports = (await import("../../src/index.js")) as Record; +describe("active preset", () => { + let exports: Record; + + beforeAll(async () => { + exports = (await import("../../src/index.js")) as Record; + }); + const params = { [PresetName.mainnet]: mainnetPreset, [PresetName.minimal]: minimalPreset, @@ -30,8 +35,6 @@ describe("active preset", async () => { it("Should not allow to change preset", () => { expect(() => { - // I'm not sure if mocha is requiring from src or lib. Each file has different state. - // To ensure this throws, call setActivePreset on both the src and lib file. setActivePreset(PresetName.minimal); setActivePresetLib(PresetName.minimal); }).toThrow(); diff --git a/packages/params/test/unit/applicationDomains.test.ts b/packages/params/test/unit/applicationDomains.test.ts index 294ceb83ce44..f78e9aa22f07 100644 --- a/packages/params/test/unit/applicationDomains.test.ts +++ b/packages/params/test/unit/applicationDomains.test.ts @@ -8,7 +8,7 @@ describe("validate application domains", () => { for (let i = 0; i < DOMAIN_APPLICATION_MASK.length; i++) { r += DOMAIN_APPLICATION_MASK[i] & domain[i]; } - // eslint-disable-next-line chai-expect/no-inner-compare + expect(r > 0).toBeWithMessage(true, `${name} mask application should be valid`); }); }); diff --git a/packages/params/vitest.config.e2e.ts b/packages/params/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/params/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/params/vitest.config.ts b/packages/params/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/params/vitest.config.ts +++ b/packages/params/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/prover/package.json b/packages/prover/package.json index 80a992118202..05f7c33579b4 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -53,12 +53,12 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --poolOptions.threads.singleThread true --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e", "check-readme": "typescript-docs-verifier", "generate-fixtures": "node --loader ts-node/esm scripts/generate_fixtures.ts" }, diff --git a/packages/prover/test/unit/proof_provider/payload_store.test.ts b/packages/prover/test/unit/proof_provider/payload_store.test.ts index 02c9cc39f87f..738b6ef55f2a 100644 --- a/packages/prover/test/unit/proof_provider/payload_store.test.ts +++ b/packages/prover/test/unit/proof_provider/payload_store.test.ts @@ -67,13 +67,13 @@ describe("proof_provider/payload_store", function () { describe("finalized", () => { it("should return undefined for an empty store", () => { - expect(store.finalized).to.undefined; + expect(store.finalized).toBeUndefined(); }); it("should return undefined if no finalized block", () => { store.set(buildPayload({blockNumber: 10}), false); - expect(store.finalized).to.undefined; + expect(store.finalized).toBeUndefined(); }); it("should return finalized payload", () => { @@ -95,7 +95,7 @@ describe("proof_provider/payload_store", function () { describe("latest", () => { it("should return undefined for an empty store", () => { - expect(store.latest).to.undefined; + expect(store.latest).toBeUndefined(); }); it("should return latest payload if finalized", () => { @@ -260,8 +260,7 @@ describe("proof_provider/payload_store", function () { const executionPayload = (blockResponse.response?.data as capella.SignedBeaconBlock).message.body .executionPayload; api.beacon.getBlockV2.mockResolvedValue(blockResponse); - - expect(store.finalized).to.undefined; + expect(store.finalized).toBeUndefined(); // First process as unfinalized await store.processLCHeader(header, false); @@ -269,7 +268,7 @@ describe("proof_provider/payload_store", function () { await store.processLCHeader(header, true); // Called only once when we process unfinalized - expect(api.beacon.getBlockV2).to.be.toHaveBeenCalledOnce(); + expect(api.beacon.getBlockV2).toHaveBeenCalledOnce(); expect(store.finalized).toEqual(executionPayload); }); }); @@ -318,7 +317,7 @@ describe("proof_provider/payload_store", function () { describe("prune", () => { it("should prune without error for empty store", () => { - expect(() => store.prune()).not.to.throw; + expect(() => store.prune()).not.toThrow(); }); it("should prune the existing payloads if larger than MAX_PAYLOAD_HISTORY", () => { diff --git a/packages/prover/vitest.config.e2e.ts b/packages/prover/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/prover/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/prover/vitest.config.ts b/packages/prover/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/prover/vitest.config.ts +++ b/packages/prover/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index 8cea3d0d6072..c19af565c397 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -50,7 +50,7 @@ "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", "test": "yarn test:unit", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "dependencies": { diff --git a/packages/reqresp/test/fixtures/encoders.ts b/packages/reqresp/test/fixtures/encoders.ts index 3024332a8bdd..408af282e2b1 100644 --- a/packages/reqresp/test/fixtures/encoders.ts +++ b/packages/reqresp/test/fixtures/encoders.ts @@ -187,7 +187,7 @@ export const responseEncodersTestCases: { skipEncoding: true, }, { - id: "Decode successfully response_chunk as a single concated chunk", + id: "Decode successfully response_chunk as a single concatenated chunk", protocol: pingNoHandler, responseChunks: [ {status: RespStatus.SUCCESS, payload: sszSnappyPing.binaryPayload}, diff --git a/packages/reqresp/test/unit/encoders/requestDecode.test.ts b/packages/reqresp/test/unit/encoders/requestDecode.test.ts index 60ccab1eecf1..462bc3bb7378 100644 --- a/packages/reqresp/test/unit/encoders/requestDecode.test.ts +++ b/packages/reqresp/test/unit/encoders/requestDecode.test.ts @@ -9,7 +9,7 @@ describe("encoders / requestDecode", () => { describe("valid cases", () => { it.each(requestEncodersCases)("$id", async ({protocol, requestBody, chunks}) => { const decodedBody = await pipe(arrToSource(chunks), requestDecode(protocol)); - expect(decodedBody).to.deep.equal(requestBody); + expect(decodedBody).toEqual(requestBody); }); }); diff --git a/packages/reqresp/test/unit/encoders/responseDecode.test.ts b/packages/reqresp/test/unit/encoders/responseDecode.test.ts index a6dfe092b169..6e73fbbba315 100644 --- a/packages/reqresp/test/unit/encoders/responseDecode.test.ts +++ b/packages/reqresp/test/unit/encoders/responseDecode.test.ts @@ -6,19 +6,22 @@ import {responseDecode} from "../../../src/encoders/responseDecode.js"; import {responseEncodersErrorTestCases, responseEncodersTestCases} from "../../fixtures/encoders.js"; import {expectRejectedWithLodestarError} from "../../utils/errors.js"; import {arrToSource, onlySuccessResp} from "../../utils/index.js"; +import {ResponseIncoming} from "../../../src/types.js"; describe("encoders / responseDecode", () => { describe("valid cases", () => { it.each(responseEncodersTestCases)("$id", async ({protocol, responseChunks, chunks}) => { - const responses = await pipe( + const responses = (await pipe( arrToSource(chunks), // eslint-disable-next-line @typescript-eslint/no-empty-function responseDecode(protocol, {onFirstHeader: () => {}, onFirstResponseChunk: () => {}}), all - ); + )) as ResponseIncoming[]; const expectedResponses = responseChunks.filter(onlySuccessResp).map((r) => r.payload); - expect(responses).to.deep.equal(expectedResponses); + expect(responses.map((r) => ({...r, data: Buffer.from(r.data)}))).toEqual( + expectedResponses.map((r) => ({...r, data: Buffer.from(r.data)})) + ); }); }); diff --git a/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts b/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts index b3393c609a76..a8cbb6e0d3a6 100644 --- a/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts +++ b/packages/reqresp/test/unit/rate_limiter/rateLimiterGRCA.test.ts @@ -55,9 +55,4 @@ describe("rateLimiterGRCA", () => { expect(rateLimiter.allows(null, 10)).toBe(true); }); }); - - // This is a private behavior but important to test to avoid memory leaks - // describe("prune()", () => { - // it.skip("should remove old entries", () => {}); - // }); }); diff --git a/packages/reqresp/test/utils/errors.ts b/packages/reqresp/test/utils/errors.ts index c6cec8bc1392..16c098f2f57c 100644 --- a/packages/reqresp/test/utils/errors.ts +++ b/packages/reqresp/test/utils/errors.ts @@ -1,4 +1,4 @@ -import {expect} from "chai"; +import {expect} from "vitest"; import {LodestarError, mapValues} from "@lodestar/utils"; export function expectThrowsLodestarError(fn: () => void, expectedErr: LodestarError | string): void { @@ -36,7 +36,7 @@ export function expectLodestarErrorCode(err: LodestarE if (!(err instanceof LodestarError)) throw Error(`err not instanceof LodestarError: ${(err as Error).stack}`); const code = err.type.code; - expect(code).to.deep.equal(expectedCode, "Wrong LodestarError code"); + expect(code).toEqualWithMessage(expectedCode, "Wrong LodestarError code"); } export function expectLodestarError(err1: LodestarError, err2: LodestarError): void { @@ -47,7 +47,7 @@ export function expectLodestarError(err1: LodestarErro const errMeta1 = getErrorMetadata(err1); const errMeta2 = getErrorMetadata(err2); - expect(errMeta1).to.deep.equal(errMeta2, "Wrong LodestarError metadata"); + expect(errMeta1).toEqualWithMessage(errMeta2, "Wrong LodestarError metadata"); } export function getErrorMetadata(err: LodestarError | Error | unknown): unknown { diff --git a/packages/reqresp/test/utils/index.ts b/packages/reqresp/test/utils/index.ts index 98a7387233ba..c3c133352186 100644 --- a/packages/reqresp/test/utils/index.ts +++ b/packages/reqresp/test/utils/index.ts @@ -1,6 +1,6 @@ import {Direction, ReadStatus, Stream, StreamStatus, WriteStatus} from "@libp2p/interface"; import {logger} from "@libp2p/logger"; -import {expect} from "chai"; +import {expect} from "vitest"; import {Uint8ArrayList} from "uint8arraylist"; import {toHexString} from "@chainsafe/ssz"; import {fromHex} from "@lodestar/utils"; @@ -21,14 +21,24 @@ export async function* arrToSource(arr: T[]): AsyncGenerator { * Wrapper for type-safety to ensure and array of Buffers is equal with a diff in hex */ export function expectEqualByteChunks(chunks: Uint8Array[], expectedChunks: Uint8Array[], message?: string): void { - expect(chunks.map(toHexString).join("").replace(/0x/g, "")).to.deep.equal( - expectedChunks.map(toHexString).join("").replace(/0x/g, ""), - message - ); + if (message) { + expect(chunks.map(toHexString).join("").replace(/0x/g, "")).toEqualWithMessage( + expectedChunks.map(toHexString).join("").replace(/0x/g, ""), + message + ); + } else { + expect(chunks.map(toHexString).join("").replace(/0x/g, "")).toEqual( + expectedChunks.map(toHexString).join("").replace(/0x/g, "") + ); + } } export function expectInEqualByteChunks(chunks: Uint8Array[], expectedChunks: Uint8Array[], message?: string): void { - expect(chunks.map(toHexString)).not.to.deep.equal(expectedChunks.map(toHexString), message); + if (message) { + expect(chunks.map(toHexString)).not.toEqualWithMessage(expectedChunks.map(toHexString), message); + } else { + expect(chunks.map(toHexString)).not.toEqual(expectedChunks.map(toHexString)); + } } /** diff --git a/packages/reqresp/vitest.config.ts b/packages/reqresp/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/reqresp/vitest.config.ts +++ b/packages/reqresp/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/spec-test-util/README.md b/packages/spec-test-util/README.md index 7b9182a4729c..405a8b2ba51f 100644 --- a/packages/spec-test-util/README.md +++ b/packages/spec-test-util/README.md @@ -2,7 +2,7 @@ > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project -Mocha / Chai utility for interacting with eth2.0 spec tests. +Vitest utility for interacting with eth2.0 spec tests. For usage see [spec tests]("https://github.com/ChainSafe/lodestar/tree/unstable/packages/beacon-node/test/spec") diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index ab427e2d0a41..899d6438d939 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -47,8 +47,8 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --passWithNoTests --dir test/unit/ --coverage", - "test:e2e": "vitest --run --dir test/e2e/", + "test:unit": "vitest --run --passWithNoTests --dir test/unit/", + "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", "check-readme": "typescript-docs-verifier" }, "repository": { @@ -65,7 +65,7 @@ "@lodestar/utils": "^1.14.0", "async-retry": "^1.3.3", "axios": "^1.3.4", - "vitest": "^1.1.0", + "vitest": "^1.2.1", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", "tar": "^6.1.13" @@ -75,6 +75,6 @@ "@types/tar": "^6.1.4" }, "peerDependencies": { - "vitest": "^1.1.0" + "vitest": "^1.2.1" } } diff --git a/packages/spec-test-util/test/e2e/single/index.test.ts b/packages/spec-test-util/test/e2e/single/index.test.ts index a20b783f4370..849b0cead30d 100644 --- a/packages/spec-test-util/test/e2e/single/index.test.ts +++ b/packages/spec-test-util/test/e2e/single/index.test.ts @@ -12,7 +12,6 @@ import {describeDirectorySpecTest, InputType, loadYamlFile} from "../../../src/s const __dirname = path.dirname(fileURLToPath(import.meta.url)); /* eslint-disable @typescript-eslint/naming-convention */ -/* eslint-disable mocha/no-exports, mocha/no-top-level-hooks */ export type SimpleStruct = { test: boolean; diff --git a/packages/spec-test-util/vitest.config.e2e.ts b/packages/spec-test-util/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/spec-test-util/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/spec-test-util/vitest.config.ts b/packages/spec-test-util/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/spec-test-util/vitest.config.ts +++ b/packages/spec-test-util/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index 2b49b94179ca..cbde9b062177 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -52,7 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, "types": "lib/index.d.ts", diff --git a/packages/state-transition/test/perf/sanityCheck.test.ts b/packages/state-transition/test/perf/sanityCheck.test.ts index 83f48be749d4..834e118d0f76 100644 --- a/packages/state-transition/test/perf/sanityCheck.test.ts +++ b/packages/state-transition/test/perf/sanityCheck.test.ts @@ -32,8 +32,6 @@ describe("Perf test sanity check", function () { const phase0State = generatePerfTestCachedStatePhase0(); const cache = beforeProcessEpoch(phase0State); expect( - // Chai does not support bigint comparisons - // eslint-disable-next-line chai-expect/no-inner-compare BigInt(cache.prevEpochUnslashedStake.targetStakeByIncrement) * BigInt(EFFECTIVE_BALANCE_INCREMENT) > targetStake, `targetStake too low: ${ BigInt(cache.prevEpochUnslashedStake.targetStakeByIncrement) * BigInt(EFFECTIVE_BALANCE_INCREMENT) diff --git a/packages/state-transition/test/utils/beforeValue.ts b/packages/state-transition/test/utils/beforeValue.ts index 61ae3daa32a1..f50520372e17 100644 --- a/packages/state-transition/test/utils/beforeValue.ts +++ b/packages/state-transition/test/utils/beforeValue.ts @@ -3,7 +3,7 @@ import {beforeAll} from "vitest"; export type LazyValue = {value: T}; /** - * Register a callback to compute a value in the before() block of mocha tests + * Register a callback to compute a value in the before() block of vitest tests * ```ts * const state = beforeValue(() => getState()) * it("test", () => { diff --git a/packages/state-transition/test/utils/types.ts b/packages/state-transition/test/utils/types.ts deleted file mode 100644 index a3a28f1cca32..000000000000 --- a/packages/state-transition/test/utils/types.ts +++ /dev/null @@ -1,5 +0,0 @@ -import {SinonStub} from "sinon"; - -export type SinonStubFn any> = T extends (...args: infer TArgs) => infer TReturnValue - ? SinonStub - : never; diff --git a/packages/state-transition/vitest.config.ts b/packages/state-transition/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/state-transition/vitest.config.ts +++ b/packages/state-transition/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/test-utils/.mocharc.yaml b/packages/test-utils/.mocharc.yaml deleted file mode 100644 index 1f15bf5929e0..000000000000 --- a/packages/test-utils/.mocharc.yaml +++ /dev/null @@ -1,4 +0,0 @@ -colors: true -extension: ["ts"] -node-option: - - "loader=ts-node/esm" diff --git a/packages/test-utils/.nycrc.json b/packages/test-utils/.nycrc.json deleted file mode 100644 index 69aa626339a0..000000000000 --- a/packages/test-utils/.nycrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../.nycrc.json" -} diff --git a/packages/test-utils/README.md b/packages/test-utils/README.md index cc7db46c0990..105e0ca7950f 100644 --- a/packages/test-utils/README.md +++ b/packages/test-utils/README.md @@ -2,7 +2,7 @@ > This package is part of [ChainSafe's Lodestar](https://lodestar.chainsafe.io) project -Mocha / Chai and other utility to reuse across testing of other packages. +Vitest and other utility to reuse across testing of other packages. For usage see [spec tests]("https://github.com/ChainSafe/lodestar/tree/unstable/packages/beacon-node/test/spec") diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 61914ba91676..d4a1df589e8f 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -14,11 +14,8 @@ ".": { "import": "./lib/index.js" }, - "./sinon": { - "import": "./lib/sinon.js" - }, - "./mocha": { - "import": "./lib/mocha.js" + "./doubles": { + "import": "./lib/doubles.js" } }, "typesVersions": { @@ -66,20 +63,16 @@ "@lodestar/params": "^1.14.0", "@lodestar/utils": "^1.14.0", "axios": "^1.3.4", - "chai": "^4.3.7", - "mocha": "^10.2.0", - "sinon": "^15.0.3", "testcontainers": "^10.2.1", - "tmp": "^0.2.1" + "tmp": "^0.2.1", + "vitest": "^1.2.1" }, "devDependencies": { "@types/dockerode": "^3.3.19", - "@types/mocha": "^10.0.1", "@types/yargs": "^17.0.24", "yargs": "^17.7.1" }, "peerDependencies": { - "chai": "^4.3.7", - "mocha": "^10.2.0" + "vitest": "^1.2.1" } } diff --git a/packages/test-utils/src/mocha.ts b/packages/test-utils/src/doubles.ts similarity index 55% rename from packages/test-utils/src/mocha.ts rename to packages/test-utils/src/doubles.ts index 7b8c10ad5342..c61c10ea6099 100644 --- a/packages/test-utils/src/mocha.ts +++ b/packages/test-utils/src/doubles.ts @@ -1,48 +1,26 @@ -import type {Suite} from "mocha"; +import {vi, MockInstance} from "vitest"; import {Logger} from "@lodestar/utils"; -import {TestContext} from "./interfaces.js"; -export type {TestContext} from "./interfaces.js"; + +type Callback = () => void; +type Handler = (cb: Callback) => void; /** - * Create a Mocha context object that can be used to register callbacks that will be executed + * Stub the logger methods */ -export function getMochaContext(suite: Suite): TestContext { - const afterEachCallbacks: (() => Promise | void)[] = []; - const beforeEachCallbacks: (() => Promise | void)[] = []; - const afterAllCallbacks: (() => Promise | void)[] = []; - - const context: TestContext = { - afterEach: (cb) => afterEachCallbacks.push(cb), - beforeEach: (cb) => beforeEachCallbacks.push(cb), - afterAll: (cb) => afterAllCallbacks.push(cb), - }; - - const callbacks = [afterEachCallbacks, beforeEachCallbacks, afterAllCallbacks]; - const hooks = [suite.afterEach, suite.beforeEach, suite.afterAll]; - - for (const [index, cbs] of callbacks.entries()) { - const hook = hooks[index].bind(suite); - - hook(async function mochaHook() { - // Add increased timeout for that hook - this.timeout(10000); - - const errs: Error[] = []; - for (const cb of cbs) { - try { - await cb(); - } catch (e) { - errs.push(e as Error); - } - } - cbs.length = 0; // Reset array - if (errs.length > 0) { - throw errs[0]; - } - }); - } +export function stubLogger(context: {beforeEach: Handler; afterEach: Handler}, logger = console): void { + context.beforeEach(() => { + vi.spyOn(logger, "info"); + vi.spyOn(logger, "log"); + vi.spyOn(logger, "warn"); + vi.spyOn(logger, "error"); + }); - return context; + context.afterEach(() => { + (logger.info as unknown as MockInstance).mockRestore(); + (logger.log as unknown as MockInstance).mockRestore(); + (logger.warn as unknown as MockInstance).mockRestore(); + (logger.error as unknown as MockInstance).mockRestore(); + }); } // Typescript does not support array of generics so have to use this flexible workaround diff --git a/packages/test-utils/src/sinon.ts b/packages/test-utils/src/sinon.ts deleted file mode 100644 index 9c75dd171248..000000000000 --- a/packages/test-utils/src/sinon.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {SinonSpy, spy} from "sinon"; - -type Callback = () => void; -type Handler = (cb: Callback) => void; - -/** - * Stub the logger methods - */ -export function stubLogger(context: {beforeEach: Handler; afterEach: Handler}, logger = console): void { - context.beforeEach(() => { - spy(logger, "info"); - spy(logger, "log"); - spy(logger, "warn"); - spy(logger, "error"); - }); - - context.afterEach(() => { - (logger.info as SinonSpy).restore(); - (logger.log as SinonSpy).restore(); - (logger.warn as SinonSpy).restore(); - (logger.error as SinonSpy).restore(); - }); -} diff --git a/packages/types/package.json b/packages/types/package.json index 9d8859ecaf05..b51acbef6801 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -61,9 +61,9 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test:constants:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/constants/ --coverage", - "test:constants:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/constants/ --coverage", - "test:unit": "wrapper() { yarn test:constants:minimal $@ && yarn test:constants:mainnet $@ && vitest --run --dir test/unit/ --coverage $@; }; wrapper", + "test:constants:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/constants/", + "test:constants:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/constants/", + "test:unit": "wrapper() { yarn test:constants:minimal $@ && yarn test:constants:mainnet $@ && vitest --run --dir test/unit/ $@; }; wrapper", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/types/test/constants/blobs.test.ts b/packages/types/test/constants/blobs.test.ts index 93193463e76b..4b145161d292 100644 --- a/packages/types/test/constants/blobs.test.ts +++ b/packages/types/test/constants/blobs.test.ts @@ -19,7 +19,7 @@ describe(`${constants.ACTIVE_PRESET}/ blobs pre-computed constants`, () => { for (const [key, expectedValue] of Object.entries(correctConstants)) { it(key, () => { - expect((constants as unknown as Record)[key]).to.equal(expectedValue); + expect((constants as unknown as Record)[key]).toEqual(expectedValue); }); } }); diff --git a/packages/types/vitest.config.ts b/packages/types/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/types/vitest.config.ts +++ b/packages/types/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/utils/package.json b/packages/utils/package.json index 9f526582483e..fcc0f5ac36c1 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -31,7 +31,7 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit/ --coverage", + "test:unit": "vitest --run --dir test/unit", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/utils/test/unit/err.test.ts b/packages/utils/test/unit/err.test.ts index a4b30ee65d73..54908c50ccd3 100644 --- a/packages/utils/test/unit/err.test.ts +++ b/packages/utils/test/unit/err.test.ts @@ -1,6 +1,5 @@ import {describe, it, expect} from "vitest"; import {Err, isErr, mapOkResults, mapOkResultsAsync, Result} from "../../src/err.js"; -import {expectDeepEquals, expectEquals} from "../utils/chai.js"; /* eslint-disable @typescript-eslint/no-unsafe-assignment */ @@ -28,21 +27,18 @@ describe("Result Err", () => { for (const [i, value] of values.entries()) { it(`${i} Ok(${String(value)})`, () => { // Any value must not be detected as error - expectEquals(isErr(value), false); + expect(isErr(value)).toBeFalsy(); }); it(`${i} Err(${String(value)})`, () => { // Any value can be wrapped in Err - expectEquals(isErr(Err(value)), true); + expect(isErr(Err(value))).toBeTruthy(); }); } }); describe("mapOkResults", () => { it("empty case", () => { - expectDeepEquals( - mapOkResults([], () => []), - [] - ); + expect(mapOkResults([], () => [])).toEqual([]); }); it("throw for different length", () => { @@ -54,13 +50,13 @@ describe("Result Err", () => { const results1 = mapOkResults(results0, (resultsOk) => resultsOk.map((num) => (num >= 5 ? Err(num) : String(num))) ); - expectDeepEquals(results1, ["0", Err(1), "2", Err(3), "4", Err(5), Err(6), Err(7)]); + expect(results1).toEqual(["0", Err(1), "2", Err(3), "4", Err(5), Err(6), Err(7)]); }); }); describe("mapOkResultsAsync", () => { it("empty case", async () => { - expectDeepEquals(await mapOkResultsAsync([], async () => []), []); + expect(await mapOkResultsAsync([], async () => [])).toEqual([]); }); it("reject for different length", async () => { @@ -77,7 +73,7 @@ describe("Result Err", () => { const results1 = await mapOkResultsAsync(results0, async (resultsOk) => resultsOk.map((num) => (num >= 5 ? Err(num) : String(num))) ); - expectDeepEquals(results1, ["0", Err(1), "2", Err(3), "4", Err(5), Err(6), Err(7)]); + expect(results1).toEqual(["0", Err(1), "2", Err(3), "4", Err(5), Err(6), Err(7)]); }); }); }); diff --git a/packages/utils/test/utils/chai.ts b/packages/utils/test/utils/chai.ts deleted file mode 100644 index 3c1e855021be..000000000000 --- a/packages/utils/test/utils/chai.ts +++ /dev/null @@ -1,9 +0,0 @@ -import {expect} from "chai"; - -export function expectDeepEquals(a: T, b: T, message?: string): void { - expect(a).deep.equals(b, message); -} - -export function expectEquals(a: T, b: T, message?: string): void { - expect(a).equals(b, message); -} diff --git a/packages/utils/vitest.config.ts b/packages/utils/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/utils/vitest.config.ts +++ b/packages/utils/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/validator/package.json b/packages/validator/package.json index 14ee1002b214..92c3e92d04a1 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -28,10 +28,10 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "pretest": "yarn run check-types", - "test:unit": "vitest --run --dir test/unit --coverage", + "test:unit": "vitest --run --dir test/unit/", "test": "yarn test:unit", "test:spec": "vitest --run --config vitest.config.spec.ts --dir test/spec/", - "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --poolOptions.threads.singleThread true --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --config vitest.config.e2e.ts --dir test/e2e", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", "coverage": "codecov -F lodestar-validator", "check-readme": "typescript-docs-verifier" diff --git a/packages/validator/test/e2e/web3signer.test.ts b/packages/validator/test/e2e/web3signer.test.ts index c93f1786dfb4..326dbae8c4f7 100644 --- a/packages/validator/test/e2e/web3signer.test.ts +++ b/packages/validator/test/e2e/web3signer.test.ts @@ -137,7 +137,6 @@ describe("web3signer signature test", function () { // ValidatorRegistration includes a timestamp so it's possible that web3signer instance and local instance // sign different messages and this test fails. Disabling unless it can be proven deterministic - // eslint-disable-next-line mocha/no-skipped-tests it.skip("signValidatorRegistration", async () => { const regAttributes = { feeRecipient: "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", diff --git a/packages/validator/test/setup.ts b/packages/validator/test/setup.ts deleted file mode 100644 index b83e6cb78511..000000000000 --- a/packages/validator/test/setup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import chai from "chai"; -import chaiAsPromised from "chai-as-promised"; -import sinonChai from "sinon-chai"; - -chai.use(chaiAsPromised); -chai.use(sinonChai); diff --git a/packages/validator/test/unit/services/attestation.test.ts b/packages/validator/test/unit/services/attestation.test.ts index c8010fe1bdf0..64948ec92529 100644 --- a/packages/validator/test/unit/services/attestation.test.ts +++ b/packages/validator/test/unit/services/attestation.test.ts @@ -1,5 +1,4 @@ import {describe, it, expect, beforeAll, beforeEach, afterEach, vi} from "vitest"; -import sinon from "sinon"; import bls from "@chainsafe/bls"; import {toHexString} from "@chainsafe/ssz"; import {ssz} from "@lodestar/types"; @@ -98,10 +97,9 @@ describe("AttestationService", function () { }); // Mock duties service to return some duties directly - attestationService["dutiesService"].getDutiesAtSlot = sinon.stub().returns(duties); + vi.spyOn(attestationService["dutiesService"], "getDutiesAtSlot").mockImplementation(() => duties); // Mock beacon's attestation and aggregates endpoints - api.validator.produceAttestationData.mockResolvedValue({ response: {data: attestation.data}, ok: true, diff --git a/packages/validator/test/unit/services/syncCommittee.test.ts b/packages/validator/test/unit/services/syncCommittee.test.ts index 20697f651ca9..922447ddf85f 100644 --- a/packages/validator/test/unit/services/syncCommittee.test.ts +++ b/packages/validator/test/unit/services/syncCommittee.test.ts @@ -109,7 +109,7 @@ describe("SyncCommitteeService", function () { }); // Mock duties service to return some duties directly - syncCommitteeService["dutiesService"].getDutiesAtSlot = vi.fn().mockReturnValue(duties); + vi.spyOn(syncCommitteeService["dutiesService"], "getDutiesAtSlot").mockResolvedValue(duties); // Mock beacon's sync committee and contribution routes diff --git a/packages/validator/test/unit/utils/clock.test.ts b/packages/validator/test/unit/utils/clock.test.ts index 8bb12e6ef8ae..15f95ddbe2ee 100644 --- a/packages/validator/test/unit/utils/clock.test.ts +++ b/packages/validator/test/unit/utils/clock.test.ts @@ -89,12 +89,11 @@ describe("util / Clock", function () { {name: "should return next slot after 12s", delta: 12}, {name: "should return next slot after 12.5s", delta: 12.5}, ]; - for (const {name, delta} of testCase) { - it(name, async function () { - const currentSlot = getCurrentSlotAround(testConfig, genesisTime); - vi.advanceTimersByTime(delta * 1000); - expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1); - }); - } + + it.each(testCase)("$name", async function ({delta}) { + const currentSlot = getCurrentSlotAround(testConfig, genesisTime); + vi.advanceTimersByTime(delta * 1000); + expect(getCurrentSlotAround(testConfig, genesisTime)).toBe(currentSlot + 1); + }); }); }); diff --git a/packages/validator/test/utils/logger.ts b/packages/validator/test/utils/logger.ts index 6077b23a9583..8eaed6dfe6c1 100644 --- a/packages/validator/test/utils/logger.ts +++ b/packages/validator/test/utils/logger.ts @@ -5,9 +5,9 @@ import {ClockMock} from "./clock.js"; /** * Run the test with ENVs to control log level: * ``` - * LOG_LEVEL=debug mocha .ts - * DEBUG=1 mocha .ts - * VERBOSE=1 mocha .ts + * LOG_LEVEL=debug vitest .ts + * DEBUG=1 vitest .ts + * VERBOSE=1 vitest .ts * ``` */ export const testLogger = getEnvLogger; diff --git a/packages/validator/vitest.config.e2e.ts b/packages/validator/vitest.config.e2e.ts new file mode 100644 index 000000000000..b9f913705ef2 --- /dev/null +++ b/packages/validator/vitest.config.e2e.ts @@ -0,0 +1,11 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "../../vitest.base.e2e.config"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + globalSetup: ["./test/globalSetup.ts"], + }, + }) +); diff --git a/packages/validator/vitest.config.spec.ts b/packages/validator/vitest.config.spec.ts index e5f588d17155..a207c8e29675 100644 --- a/packages/validator/vitest.config.spec.ts +++ b/packages/validator/vitest.config.spec.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/packages/validator/vitest.config.ts b/packages/validator/vitest.config.ts index 1df0de848936..7a6069341168 100644 --- a/packages/validator/vitest.config.ts +++ b/packages/validator/vitest.config.ts @@ -1,5 +1,5 @@ import {defineConfig, mergeConfig} from "vitest/config"; -import vitestConfig from "../../vitest.base.config"; +import vitestConfig from "../../vitest.base.unit.config"; export default mergeConfig( vitestConfig, diff --git a/tsconfig.build.json b/tsconfig.build.json index d767c8eaec8a..8034a32ce679 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -25,10 +25,8 @@ "incremental": true, "preserveWatchOutput": true, - - // There are two duplicate type definitions included from `chai` and `vitest` packages. - // There is one invalid type declaration introduced from `webdriverio -> got` package. - // TODO: Once we completely remove `chai` and upgrade `webdriverio` we can enable this check again. + // TODO: Investigate following errors: + // - Cannot find module 'rollup/parseAst' or its corresponding type declarations "skipLibCheck": true, } } diff --git a/vitest.base.e2e.config.ts b/vitest.base.e2e.config.ts new file mode 100644 index 000000000000..b8b19c124bad --- /dev/null +++ b/vitest.base.e2e.config.ts @@ -0,0 +1,19 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "./vitest.base.unit.config.js"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + coverage: { + enabled: false, + }, + pool: "forks", + poolOptions: { + forks: { + singleFork: true, + }, + }, + }, + }) +); diff --git a/vitest.base.spec.config.ts b/vitest.base.spec.config.ts new file mode 100644 index 000000000000..72125edcfa81 --- /dev/null +++ b/vitest.base.spec.config.ts @@ -0,0 +1,22 @@ +import {defineConfig, mergeConfig} from "vitest/config"; +import vitestConfig from "./vitest.base.unit.config.js"; + +export default mergeConfig( + vitestConfig, + defineConfig({ + test: { + coverage: { + enabled: false, + }, + testTimeout: 60_000, + hookTimeout: 60_000, + passWithNoTests: true, + pool: "threads", + poolOptions: { + threads: { + isolate: false, + }, + }, + }, + }) +); diff --git a/vitest.base.config.ts b/vitest.base.unit.config.ts similarity index 96% rename from vitest.base.config.ts rename to vitest.base.unit.config.ts index 2c12cbf41b9b..b087466fec12 100644 --- a/vitest.base.config.ts +++ b/vitest.base.unit.config.ts @@ -17,6 +17,7 @@ export default defineConfig({ setupFiles: [path.join(__dirname, "./scripts/vitest/customMatchers.ts")], reporters: ["default", "hanging-process"], coverage: { + enabled: process.env.CI === "true", clean: true, all: false, extension: [".ts"], diff --git a/webpack.test.config.js b/webpack.test.config.js deleted file mode 100644 index 0949c76886d4..000000000000 --- a/webpack.test.config.js +++ /dev/null @@ -1,66 +0,0 @@ -const webpack = require("webpack"); -const ResolveTypeScriptPlugin = require("resolve-typescript-plugin"); - -module.exports = { - mode: "production", - target: "web", - experiments: { - topLevelAwait: true, - }, - optimization: { - minimize: false, - }, - stats: { - errors: true, - errorDetails: true, - }, - plugins: [ - new webpack.ProvidePlugin({ - process: "process/browser.js", - // eslint-disable-next-line @typescript-eslint/naming-convention - Buffer: ["buffer", "Buffer"], - }), - ], - module: { - exprContextCritical: false, - rules: [ - { - test: /\.ts?$/, - use: [ - { - loader: "ts-loader", - options: { - configFile: "tsconfig.e2e.json", - experimentalFileCaching: true, - transpileOnly: true, - projectReferences: true, - }, - }, - ], - exclude: [/node_modules/], - }, - ], - }, - resolve: { - plugins: [new ResolveTypeScriptPlugin({includeNodeModules: false})], - fallback: { - path: require.resolve("path-browserify"), - "node:path": require.resolve("path-browserify"), - http: require.resolve("stream-http"), - https: require.resolve("https-browserify"), - stream: require.resolve("stream-browserify"), - "node:stream": require.resolve("stream-browserify"), - "@chainsafe/blst": false, - process: false, - fs: false, - os: false, - zlib: false, - crypto: false, - url: false, - }, - alias: { - process: "process/browser.js", - }, - extensions: [".ts", ".js"], - }, -}; diff --git a/yarn.lock b/yarn.lock index a6621b6fbd0c..c39d68175f13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -203,163 +203,11 @@ dependencies: "@babel/highlight" "^7.18.6" -"@babel/code-frame@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz" - integrity sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== - dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" - -"@babel/core@^7.7.5": - version "7.11.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.11.4.tgz" - integrity sha512-5deljj5HlqRXN+5oJTY7Zs37iH3z3b++KjiKtIsJy1NrjOOVSEaJHEetLBhyu0aQOSNNZ/0IuEAan9GzRuDXHg== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.11.4" - "@babel/helper-module-transforms" "^7.11.0" - "@babel/helpers" "^7.10.4" - "@babel/parser" "^7.11.4" - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.11.0" - "@babel/types" "^7.11.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.1" - json5 "^2.1.2" - lodash "^4.17.19" - resolve "^1.3.2" - semver "^5.4.1" - source-map "^0.5.0" - -"@babel/generator@^7.11.4": - version "7.15.0" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz" - integrity sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ== - dependencies: - "@babel/types" "^7.15.0" - jsesc "^2.5.1" - source-map "^0.5.0" - -"@babel/generator@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" - integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== - dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" - -"@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.10.4": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz" - integrity sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-transforms@^7.11.0": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz" - integrity sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg== - dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-replace-supers" "^7.10.4" - "@babel/helper-simple-access" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/template" "^7.10.4" - "@babel/types" "^7.11.0" - lodash "^4.17.19" - -"@babel/helper-optimise-call-expression@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz" - integrity sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg== - dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-replace-supers@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz" - integrity sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A== - dependencies: - "@babel/helper-member-expression-to-functions" "^7.10.4" - "@babel/helper-optimise-call-expression" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-simple-access@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz" - integrity sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw== - dependencies: - "@babel/template" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/helper-split-export-declaration@^7.11.0": - version "7.11.0" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz" - integrity sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg== - dependencies: - "@babel/types" "^7.11.0" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" - integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== - "@babel/helper-string-parser@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== -"@babel/helper-validator-identifier@^7.10.4": - version "7.14.9" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz" - integrity sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g== - "@babel/helper-validator-identifier@^7.18.6": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -370,29 +218,6 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== -"@babel/helper-validator-identifier@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" - integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== - -"@babel/helpers@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz" - integrity sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA== - dependencies: - "@babel/template" "^7.10.4" - "@babel/traverse" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/highlight@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz" - integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA== - dependencies: - "@babel/helper-validator-identifier" "^7.10.4" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -402,74 +227,12 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/parser@^7.10.4", "@babel/parser@^7.11.4": - version "7.15.3" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz" - integrity sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA== - -"@babel/parser@^7.22.15", "@babel/parser@^7.23.6": +"@babel/parser@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== -"@babel/parser@^7.23.3": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.5.tgz#37dee97c4752af148e1d38c34b856b2507660563" - integrity sha512-hOOqoiNXrmGdFbhgCzu6GiURxUgM27Xwd/aPuu8RfHEZPBzL1Z54okAHAQjXfcQNwvrlkAmAp4SlRTZ45vlthQ== - -"@babel/template@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz" - integrity sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/parser" "^7.10.4" - "@babel/types" "^7.10.4" - -"@babel/template@^7.22.15": - version "7.22.15" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" - integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== - dependencies: - "@babel/code-frame" "^7.22.13" - "@babel/parser" "^7.22.15" - "@babel/types" "^7.22.15" - -"@babel/traverse@^7.10.4", "@babel/traverse@^7.11.0": - version "7.23.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.7.tgz#9a7bf285c928cb99b5ead19c3b1ce5b310c9c305" - integrity sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/generator" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.23.6" - "@babel/types" "^7.23.6" - debug "^4.3.1" - globals "^11.1.0" - -"@babel/types@^7.10.4", "@babel/types@^7.11.0", "@babel/types@^7.15.0": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" - integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== - dependencies: - "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.5" - to-fast-properties "^2.0.0" - -"@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6": +"@babel/types@^7.23.6": version "7.23.6" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== @@ -478,15 +241,6 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@babel/types@^7.23.3": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.5.tgz#48d730a00c95109fa4393352705954d74fb5b602" - integrity sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - "@balena/dockerignore@^1.0.2": version "1.0.2" resolved "https://registry.yarnpkg.com/@balena/dockerignore/-/dockerignore-1.0.2.tgz#9ffe4726915251e8eb69f44ef3547e0da2c03e0d" @@ -1537,18 +1291,7 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": +"@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== @@ -1560,7 +1303,7 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": +"@jridgewell/gen-mapping@^0.3.0": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== @@ -1584,11 +1327,6 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/source-map@^0.3.3": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.4.tgz#856a142864530d4059dda415659b48d37db2d556" - integrity sha512-KE/SxsDqNs3rrWwFHcRh15ZLVFrI0YoZtgAdIyIq9k5hUNmiWRXXThPomIxHuL20sLdgzbDFyvkUMna14bvtrw== - "@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" @@ -1607,7 +1345,7 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17": +"@jridgewell/trace-mapping@^0.3.12": version "0.3.18" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== @@ -2644,7 +2382,7 @@ picocolors "^1.0.0" tslib "^2.6.0" -"@polka/url@^1.0.0-next.20": +"@polka/url@^1.0.0-next.24": version "1.0.0-next.24" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.24.tgz#58601079e11784d20f82d0585865bb42305c4df3" integrity sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ== @@ -2907,48 +2645,6 @@ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== -"@sinonjs/commons@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" - integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== - dependencies: - type-detect "4.0.8" - -"@sinonjs/commons@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" - integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== - dependencies: - type-detect "4.0.8" - -"@sinonjs/fake-timers@^10.0.2": - version "10.0.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" - integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== - dependencies: - "@sinonjs/commons" "^2.0.0" - -"@sinonjs/fake-timers@^10.3.0": - version "10.3.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" - integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== - dependencies: - "@sinonjs/commons" "^3.0.0" - -"@sinonjs/samsam@^8.0.0": - version "8.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-8.0.0.tgz#0d488c91efb3fa1442e26abea81759dfc8b5ac60" - integrity sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew== - dependencies: - "@sinonjs/commons" "^2.0.0" - lodash.get "^4.4.2" - type-detect "^4.0.8" - -"@sinonjs/text-encoding@^0.7.1": - version "0.7.1" - resolved "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz" - integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== - "@swc/core-darwin-arm64@1.3.101": version "1.3.101" resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.101.tgz#9ffdc0e77c31b20877fa7405c82905e0c76738d0" @@ -3119,43 +2815,11 @@ "@types/node" "*" "@types/responselike" "^1.0.0" -"@types/chai-as-promised@^7.1.6": - version "7.1.6" - resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.6.tgz#3b08cbe1e7206567a480dc6538bade374b19e4e1" - integrity sha512-cQLhk8fFarRVZAXUQV1xEnZgMoPxqKojBvRkqPCKPQCzEhpbbSKl1Uu75kDng7k5Ln6LQLUmNBjLlFthCgm1NA== - dependencies: - "@types/chai" "*" - -"@types/chai@*": - version "4.2.17" - resolved "https://registry.npmjs.org/@types/chai/-/chai-4.2.17.tgz" - integrity sha512-LaiwWNnYuL8xJlQcE91QB2JoswWZckq9A4b+nMPq8dt8AP96727Nb3X4e74u+E3tm4NLTILNI9MYFsyVc30wSA== - -"@types/chai@^4.3.6": - version "4.3.6" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.6.tgz#7b489e8baf393d5dd1266fb203ddd4ea941259e6" - integrity sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw== - -"@types/component-emitter@^1.2.10": - version "1.2.11" - resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.11.tgz#50d47d42b347253817a39709fef03ce66a108506" - integrity sha512-SRXjM+tfsSlA9VuG8hGO2nft2p8zjXCK1VcC6N4NXbBbYbSia9kzCChYQajIjzIqOOOuh5Ock6MmV2oux4jDZQ== - -"@types/cookie@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.4.1.tgz#bfd02c1f2224567676c1545199f87c3a861d878d" - integrity sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q== - "@types/cookiejar@*": version "2.1.2" resolved "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz" integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== -"@types/cors@^2.8.12": - version "2.8.12" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.12.tgz#6b2c510a7ad7039e98e7b8d3d6598f4359e5c080" - integrity sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw== - "@types/datastore-level@^3.0.0": version "3.0.0" resolved "https://registry.npmjs.org/@types/datastore-level/-/datastore-level-3.0.0.tgz" @@ -3193,27 +2857,6 @@ "@types/docker-modem" "*" "@types/node" "*" -"@types/eslint-scope@^3.7.3": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" - integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.4.5" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.5.tgz#acdfb7dd36b91cc5d812d7c093811a8f3d9b31e4" - integrity sha512-dhsC09y1gpJWnK+Ff4SGvCuSnk9DaU0BJZSzOwa6GVSg65XtTugLBITDAAzRU5duGBoXBHpdR/9jHGxJjNflJQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.0.tgz#5fb2e536c1ae9bf35366eed879e827fa59ca41c2" - integrity sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ== - "@types/estree@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" @@ -3273,11 +2916,6 @@ resolved "https://registry.yarnpkg.com/@types/js-yaml/-/js-yaml-4.0.5.tgz#738dd390a6ecc5442f35e7f03fa1431353f7e138" integrity sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA== -"@types/json-schema@*", "@types/json-schema@^7.0.8": - version "7.0.11" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" - integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== - "@types/json-schema@^7.0.12": version "7.0.13" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" @@ -3342,10 +2980,10 @@ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== -"@types/mocha@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.1.tgz#2f4f65bb08bc368ac39c96da7b2f09140b26851b" - integrity sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q== +"@types/mocha@^10.0.6": + version "10.0.6" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" + integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== "@types/mockery@^1.4.30": version "1.4.30" @@ -3373,7 +3011,7 @@ "@types/node" "*" form-data "^3.0.0" -"@types/node@*", "@types/node@>=10.0.0", "@types/node@>=13.7.0", "@types/node@^20.6.5": +"@types/node@*", "@types/node@>=13.7.0", "@types/node@^20.6.5": version "20.6.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.5.tgz#4c6a79adf59a8e8193ac87a0e522605b16587258" integrity sha512-2qGq5LAOTh9izcc0+F+dToFigBWiK1phKPt7rNhOqJSr35y8rlIBjDwGtFSgAI6MGIhjwOVNSQZVdJsZJ2uR1w== @@ -3435,28 +3073,6 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== -"@types/sinon-chai@^3.2.9": - version "3.2.9" - resolved "https://registry.yarnpkg.com/@types/sinon-chai/-/sinon-chai-3.2.9.tgz#71feb938574bbadcb176c68e5ff1a6014c5e69d4" - integrity sha512-/19t63pFYU0ikrdbXKBWj9PCdnKyTd0Qkz0X91Ta081cYsq90OxYdcWwK/dwEoDa6dtXgj2HJfmzgq+QZTHdmQ== - dependencies: - "@types/chai" "*" - "@types/sinon" "*" - -"@types/sinon@*": - version "10.0.13" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.13.tgz#60a7a87a70d9372d0b7b38cc03e825f46981fb83" - integrity sha512-UVjDqJblVNQYvVNUsj0PuYYw0ELRmgt1Nt5Vk0pT5f16ROGfcKJY8o1HVuMOJOpD727RrGB9EGvoaTQE5tgxZQ== - dependencies: - "@types/sinonjs__fake-timers" "*" - -"@types/sinon@^10.0.16": - version "10.0.16" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-10.0.16.tgz#4bf10313bd9aa8eef1e50ec9f4decd3dd455b4d3" - integrity sha512-j2Du5SYpXZjJVJtXBokASpPRj+e2z+VUhCPHmM6WMfe3dpHu6iVKJMU6AiBcMp/XTAYnEj6Wc1trJUWwZ0QaAQ== - dependencies: - "@types/sinonjs__fake-timers" "*" - "@types/sinon@^17.0.0": version "17.0.2" resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-17.0.2.tgz#9a769f67e62b45b7233f1fe01cb1f231d2393e1c" @@ -3617,6 +3233,14 @@ "@typescript-eslint/visitor-keys" "6.7.2" debug "^4.3.4" +"@typescript-eslint/scope-manager@6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.19.0.tgz#b6d2abb825b29ab70cb542d220e40c61c1678116" + integrity sha512-dO1XMhV2ehBI6QN8Ufi7I10wmUovmLU0Oru3n5LVlM2JuzB4M+dVphCPLkVpKvGij2j/pHBWuJ9piuXx+BhzxQ== + dependencies: + "@typescript-eslint/types" "6.19.0" + "@typescript-eslint/visitor-keys" "6.19.0" + "@typescript-eslint/scope-manager@6.7.2": version "6.7.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.7.2.tgz#cf59a2095d2f894770c94be489648ad1c78dc689" @@ -3635,11 +3259,30 @@ debug "^4.3.4" ts-api-utils "^1.0.1" +"@typescript-eslint/types@6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.19.0.tgz#689b0498c436272a6a2059b09f44bcbd90de294a" + integrity sha512-lFviGV/vYhOy3m8BJ/nAKoAyNhInTdXpftonhWle66XHAtT1ouBlkjL496b5H5hb8dWXHwtypTqgtb/DEa+j5A== + "@typescript-eslint/types@6.7.2": version "6.7.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.7.2.tgz#75a615a6dbeca09cafd102fe7f465da1d8a3c066" integrity sha512-flJYwMYgnUNDAN9/GAI3l8+wTmvTYdv64fcH8aoJK76Y+1FCZ08RtI5zDerM/FYT5DMkAc+19E4aLmd5KqdFyg== +"@typescript-eslint/typescript-estree@6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.0.tgz#0813ba364a409afb4d62348aec0202600cb468fa" + integrity sha512-o/zefXIbbLBZ8YJ51NlkSAt2BamrK6XOmuxSR3hynMIzzyMY33KuJ9vuMdFSXW+H0tVvdF9qBPTHA91HDb4BIQ== + dependencies: + "@typescript-eslint/types" "6.19.0" + "@typescript-eslint/visitor-keys" "6.19.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/typescript-estree@6.7.2": version "6.7.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.2.tgz#ce5883c23b581a5caf878af641e49dd0349238c7" @@ -3666,6 +3309,27 @@ "@typescript-eslint/typescript-estree" "6.7.2" semver "^7.5.4" +"@typescript-eslint/utils@^6.15.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.19.0.tgz#557b72c3eeb4f73bef8037c85dae57b21beb1a4b" + integrity sha512-QR41YXySiuN++/dC9UArYOg4X86OAYP83OWTewpVx5ct1IZhjjgTLocj7QNxGhWoTqknsgpl7L+hGygCO+sdYw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.19.0" + "@typescript-eslint/types" "6.19.0" + "@typescript-eslint/typescript-estree" "6.19.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.19.0": + version "6.19.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.0.tgz#4565e0ecd63ca1f81b96f1dd76e49f746c6b2b49" + integrity sha512-hZaUCORLgubBvtGpp1JEFEazcuEdfxta9j4iUwdSAr7mEsYYAp3EAUyCZk3VEEqGj6W+AV4uWyrDGtrlawAsgQ== + dependencies: + "@typescript-eslint/types" "6.19.0" + eslint-visitor-keys "^3.4.1" + "@typescript-eslint/visitor-keys@6.7.2": version "6.7.2" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.2.tgz#4cb2bd786f1f459731b0ad1584c9f73e1c7a4d5c" @@ -3674,19 +3338,19 @@ "@typescript-eslint/types" "6.7.2" eslint-visitor-keys "^3.4.1" -"@vitest/browser@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/browser/-/browser-1.1.0.tgz#b3c3e06d04506309a1e163103e1f65ee1391c262" - integrity sha512-59Uwoiw/zAQPmqgIKrzev8HNfeNlD8Q/nDyP9Xqg1D3kaM0tcOT/wk5RnZFW5f0JdguK0c1+vSeOPUSrOja1hQ== +"@vitest/browser@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/browser/-/browser-1.2.1.tgz#ad04b261416b211804199df0a717c9ecddf5f006" + integrity sha512-jhaQ15zWYAwz8anXgmLW0yAVLCXdT8RFv7LeW9bg7sMlvGJaTCTIHaHWFvCdADF/i62+22tnrzgiiqSnApjXtA== dependencies: - estree-walker "^3.0.3" + "@vitest/utils" "1.2.1" magic-string "^0.30.5" - sirv "^2.0.3" + sirv "^2.0.4" -"@vitest/coverage-v8@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.1.0.tgz#bc0bbb99fcb608f72794701a86302ff3aabbc125" - integrity sha512-kHQRk70vTdXAyQY2C0vKOHPyQD/R6IUzcGdO4vCuyr4alE5Yg1+Sk2jSdjlIrTTXdcNEs+ReWVM09mmSFJpzyQ== +"@vitest/coverage-v8@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/coverage-v8/-/coverage-v8-1.2.1.tgz#e76d64c8f0a8cb882543f12f7a2bc7615b84cbee" + integrity sha512-fJEhKaDwGMZtJUX7BRcGxooGwg1Hl0qt53mVup/ZJeznhvL5EodteVnb/mcByhEcvVWbK83ZF31c7nPEDi4LOQ== dependencies: "@ampproject/remapping" "^2.2.1" "@bcoe/v8-coverage" "^0.2.3" @@ -3696,72 +3360,73 @@ istanbul-lib-source-maps "^4.0.1" istanbul-reports "^3.1.6" magic-string "^0.30.5" - magicast "^0.3.2" + magicast "^0.3.3" picocolors "^1.0.0" std-env "^3.5.0" test-exclude "^6.0.0" v8-to-istanbul "^9.2.0" -"@vitest/expect@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.1.0.tgz#f58eef7de090ad65f30bb93ec54fa9f94c9d1d5d" - integrity sha512-9IE2WWkcJo2BR9eqtY5MIo3TPmS50Pnwpm66A6neb2hvk/QSLfPXBz2qdiwUOQkwyFuuXEUj5380CbwfzW4+/w== +"@vitest/expect@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.2.1.tgz#574c0ac138a9e34522da202ea4c48a3adfe7240e" + integrity sha512-/bqGXcHfyKgFWYwIgFr1QYDaR9e64pRKxgBNWNXPefPFRhgm+K3+a/dS0cUGEreWngets3dlr8w8SBRw2fCfFQ== dependencies: - "@vitest/spy" "1.1.0" - "@vitest/utils" "1.1.0" + "@vitest/spy" "1.2.1" + "@vitest/utils" "1.2.1" chai "^4.3.10" -"@vitest/runner@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.1.0.tgz#b3bf60f4a78f4324ca09811dd0f87b721a96b534" - integrity sha512-zdNLJ00pm5z/uhbWF6aeIJCGMSyTyWImy3Fcp9piRGvueERFlQFbUwCpzVce79OLm2UHk9iwaMSOaU9jVHgNVw== +"@vitest/runner@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.2.1.tgz#13e65b47eb04e572b99757e55f063f8f025822b2" + integrity sha512-zc2dP5LQpzNzbpaBt7OeYAvmIsRS1KpZQw4G3WM/yqSV1cQKNKwLGmnm79GyZZjMhQGlRcSFMImLjZaUQvNVZQ== dependencies: - "@vitest/utils" "1.1.0" + "@vitest/utils" "1.2.1" p-limit "^5.0.0" pathe "^1.1.1" -"@vitest/snapshot@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.1.0.tgz#b9924e4303382b43bb2c31061b173e69a6fb3437" - integrity sha512-5O/wyZg09V5qmNmAlUgCBqflvn2ylgsWJRRuPrnHEfDNT6tQpQ8O1isNGgo+VxofISHqz961SG3iVvt3SPK/QQ== +"@vitest/snapshot@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.2.1.tgz#bd2dcae2322b90bab1660421ff9dae73fc84ecc0" + integrity sha512-Tmp/IcYEemKaqAYCS08sh0vORLJkMr0NRV76Gl8sHGxXT5151cITJCET20063wk0Yr/1koQ6dnmP6eEqezmd/Q== dependencies: magic-string "^0.30.5" pathe "^1.1.1" pretty-format "^29.7.0" -"@vitest/spy@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.1.0.tgz#7f40697e4fc217ac8c3cc89a865d1751b263f561" - integrity sha512-sNOVSU/GE+7+P76qYo+VXdXhXffzWZcYIPQfmkiRxaNCSPiLANvQx5Mx6ZURJ/ndtEkUJEpvKLXqAYTKEY+lTg== +"@vitest/spy@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.2.1.tgz#2777444890de9d32e55e600e34a13b2074cabc18" + integrity sha512-vG3a/b7INKH7L49Lbp0IWrG6sw9j4waWAucwnksPB1r1FTJgV7nkBByd9ufzu6VWya/QTvQW4V9FShZbZIB2UQ== dependencies: tinyspy "^2.2.0" -"@vitest/utils@1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.1.0.tgz#d177a5f41bdb484bbb43c8d73a77ca782df068b5" - integrity sha512-z+s510fKmYz4Y41XhNs3vcuFTFhcij2YF7F8VQfMEYAAUfqQh0Zfg7+w9xdgFGhPf3tX3TicAe+8BDITk6ampQ== +"@vitest/utils@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.2.1.tgz#ad798cb13ec9e9e97b13be65d135e9e8e3c586aa" + integrity sha512-bsH6WVZYe/J2v3+81M5LDU8kW76xWObKIURpPrOXm2pjBniBu2MERI/XP60GpS4PHU3jyK50LUutOwrx4CyHUg== dependencies: diff-sequences "^29.6.3" + estree-walker "^3.0.3" loupe "^2.3.7" pretty-format "^29.7.0" -"@wdio/config@8.27.0": - version "8.27.0" - resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.27.0.tgz#c738d8108b5161cf3f80bb34d0e1f4d700b1a9ce" - integrity sha512-zYM5daeiBVVAbQj0ASymAt0RUsocLVIwKiUHNa8gg/1GsZnztGjetXExSp1gXlxtMVM5xWUSKjh6ceFK79gWDQ== +"@wdio/config@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@wdio/config/-/config-8.28.0.tgz#7b6928aa90d432cff35555b039dbae449b6e8235" + integrity sha512-uXav11uUZSqbYyXGLzyggO8togdm6Bjdjkg8f0zZe4nQpqKpLAkcH7jRiekhuj7oIV5hZai6w5YFhFy5nsw/QA== dependencies: - "@wdio/logger" "8.24.12" - "@wdio/types" "8.27.0" - "@wdio/utils" "8.27.0" + "@wdio/logger" "8.28.0" + "@wdio/types" "8.28.0" + "@wdio/utils" "8.28.0" decamelize "^6.0.0" deepmerge-ts "^5.0.0" glob "^10.2.2" import-meta-resolve "^4.0.0" -"@wdio/logger@8.24.12": - version "8.24.12" - resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-8.24.12.tgz#03cb8bb7ce7ee443e1dcd200a3b44270ae16a1f9" - integrity sha512-QisOiVIWKTUCf1H7S+DOtC+gruhlpimQrUXfWMTeeh672PvAJYnTpOJDWA+BtXfsikkUYFAzAaq8SeMJk8rqKg== +"@wdio/logger@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@wdio/logger/-/logger-8.28.0.tgz#ab97ee1a9f6a30305e1a07ff2b67fa23e1281e73" + integrity sha512-/s6zNCqwy1hoc+K4SJypis0Ud0dlJ+urOelJFO1x0G0rwDRWyFiUP6ijTaCcFxAm29jYEcEPWijl2xkVIHwOyA== dependencies: chalk "^5.1.2" loglevel "^1.6.0" @@ -3790,21 +3455,21 @@ dependencies: "@types/node" "^20.1.0" -"@wdio/types@8.27.0": - version "8.27.0" - resolved "https://registry.yarnpkg.com/@wdio/types/-/types-8.27.0.tgz#ef2e3a9ae083f08ee5fe5bf9e5dfc70cc55cebcb" - integrity sha512-LbP9FKh8r0uW9/dKhTIUCC1Su8PsP9TmzGKXkWt6/IMacgJiB/zW3u1CgyaLw9lG0UiQORHGoeJX9zB2HZAh4w== +"@wdio/types@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@wdio/types/-/types-8.28.0.tgz#9dd5189699b2b636db2fb2b6f205d6417b876053" + integrity sha512-4/mUn3IGNa1GTiV0PMOtl1sRqStpbHOQldxz4Vheh0lYNc15W12jXRm84CwGsV6UW93GO9W2K9EprFJsUjc9sg== dependencies: "@types/node" "^20.1.0" -"@wdio/utils@8.27.0": - version "8.27.0" - resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.27.0.tgz#6cb9b29649b4e301a959a8e8aea831edec635d55" - integrity sha512-4BY+JBQssVn003P5lA289uDMie3LtGinHze5btkcW9timB6VaU+EeZS4eKTPC0pziizLhteVvXYxv3YTpeeRfA== +"@wdio/utils@8.28.0": + version "8.28.0" + resolved "https://registry.yarnpkg.com/@wdio/utils/-/utils-8.28.0.tgz#df71392b0382b7e3ca62d24d3bf333ce83911038" + integrity sha512-v3xDJuQShLSfHW/Ee0y3z9ZtiV/UrILlucgKBCwCpLwHnO5HhfAH4Ehirt0yzQvYz+Pn9BuOXJImD/wsSbJtLw== dependencies: "@puppeteer/browsers" "^1.6.0" - "@wdio/logger" "8.24.12" - "@wdio/types" "8.27.0" + "@wdio/logger" "8.28.0" + "@wdio/types" "8.28.0" decamelize "^6.0.0" deepmerge-ts "^5.1.0" edgedriver "^5.3.5" @@ -3816,137 +3481,6 @@ split2 "^4.2.0" wait-port "^1.0.4" -"@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" - integrity sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q== - dependencies: - "@webassemblyjs/helper-numbers" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - -"@webassemblyjs/floating-point-hex-parser@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" - integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== - -"@webassemblyjs/helper-api-error@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" - integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== - -"@webassemblyjs/helper-buffer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz#b66d73c43e296fd5e88006f18524feb0f2c7c093" - integrity sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA== - -"@webassemblyjs/helper-numbers@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" - integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== - dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@xtuc/long" "4.2.2" - -"@webassemblyjs/helper-wasm-bytecode@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" - integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== - -"@webassemblyjs/helper-wasm-section@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz#ff97f3863c55ee7f580fd5c41a381e9def4aa577" - integrity sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - -"@webassemblyjs/ieee754@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" - integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== - dependencies: - "@xtuc/ieee754" "^1.2.0" - -"@webassemblyjs/leb128@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" - integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== - dependencies: - "@xtuc/long" "4.2.2" - -"@webassemblyjs/utf8@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" - integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== - -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz#c72fa8220524c9b416249f3d94c2958dfe70ceab" - integrity sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/helper-wasm-section" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-opt" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - "@webassemblyjs/wast-printer" "1.11.6" - -"@webassemblyjs/wasm-gen@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz#fb5283e0e8b4551cc4e9c3c0d7184a65faf7c268" - integrity sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wasm-opt@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz#d9a22d651248422ca498b09aa3232a81041487c2" - integrity sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-buffer" "1.11.6" - "@webassemblyjs/wasm-gen" "1.11.6" - "@webassemblyjs/wasm-parser" "1.11.6" - -"@webassemblyjs/wasm-parser@1.11.6", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz#bb85378c527df824004812bbdb784eea539174a1" - integrity sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@webassemblyjs/helper-api-error" "1.11.6" - "@webassemblyjs/helper-wasm-bytecode" "1.11.6" - "@webassemblyjs/ieee754" "1.11.6" - "@webassemblyjs/leb128" "1.11.6" - "@webassemblyjs/utf8" "1.11.6" - -"@webassemblyjs/wast-printer@1.11.6": - version "1.11.6" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz#a7bf8dd7e362aeb1668ff43f35cb849f188eff20" - integrity sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A== - dependencies: - "@webassemblyjs/ast" "1.11.6" - "@xtuc/long" "4.2.2" - -"@xtuc/ieee754@^1.2.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" - integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== - -"@xtuc/long@4.2.2": - version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" - integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== - "@yarnpkg/lockfile@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" @@ -4025,19 +3559,6 @@ abstract-logging@^2.0.1: resolved "https://registry.yarnpkg.com/abstract-logging/-/abstract-logging-2.0.1.tgz#6b0c371df212db7129b57d2e7fcf282b8bf1c839" integrity sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA== -accepts@~1.3.4: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -4048,26 +3569,21 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn-walk@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" - integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== +acorn-walk@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== acorn@^8.10.0, acorn@^8.9.0: version "8.10.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -acorn@^8.4.1, acorn@^8.7.1: +acorn@^8.4.1: version "8.7.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== -acorn@^8.8.2: - version "8.9.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.9.0.tgz#78a16e3b2bcc198c10822786fa6679e245db5b59" - integrity sha512-jaVNAFBHNLXspO543WnNNPZFRtavh3skAkITqD0/2aeMkKZTN+254PyhwxFYrk3vQ1xfY+2wbesJMs/JC8/PwQ== - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" @@ -4121,12 +3637,7 @@ ajv-formats@^2.1.1: dependencies: ajv "^8.0.0" -ajv-keywords@^3.5.2: - version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" - integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== - -ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -4232,13 +3743,6 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" -append-transform@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz" - integrity sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg== - dependencies: - default-require-extensions "^3.0.0" - "aproba@^1.0.3 || ^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" @@ -4497,7 +4001,7 @@ async-retry@^1.3.3: dependencies: retry "0.13.1" -async@^3.2.3, async@~3.2.2: +async@^3.2.3: version "3.2.4" resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== @@ -4585,11 +4089,6 @@ base64-js@^1.0.2, base64-js@^1.3.1: resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base64id@2.0.0, base64id@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" - integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== - base64url@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz" @@ -4732,24 +4231,6 @@ bn.js@^5.2.1: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== -body-parser@^1.19.0: - version "1.20.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.0.tgz#3de69bd89011c11573d7bfee6a64f11b6bd27cc5" - integrity sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.10.3" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - boolean@^3.0.1: version "3.2.0" resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.2.0.tgz#9e5294af4e98314494cbb17979fa54ca159f116b" @@ -4872,16 +4353,6 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.14.5: - version "4.21.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.2.tgz#59a400757465535954946a400b841ed37e2b4ecf" - integrity sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA== - dependencies: - caniuse-lite "^1.0.30001366" - electron-to-chromium "^1.4.188" - node-releases "^2.0.6" - update-browserslist-db "^1.0.4" - buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -4984,11 +4455,6 @@ byte-size@8.1.1: resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-8.1.1.tgz#3424608c62d59de5bfda05d31e0313c6174842ae" integrity sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg== -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - c-kzg@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/c-kzg/-/c-kzg-2.1.2.tgz#355eca750c1b70398f533be5dd33e7ffbde005d8" @@ -4997,24 +4463,6 @@ c-kzg@^2.1.2: bindings "^1.5.0" node-addon-api "^5.0.0" -c8@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/c8/-/c8-8.0.1.tgz#bafd60be680e66c5530ee69f621e45b1364af9fd" - integrity sha512-EINpopxZNH1mETuI0DzRA4MZpAUH+IFiRhnmFD3vFr3vdrgxqi3VfE3KL0AIL+zDq8rC9bZqwM/VDmmoe04y7w== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@istanbuljs/schema" "^0.1.3" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.2.0" - istanbul-lib-report "^3.0.1" - istanbul-reports "^3.1.6" - rimraf "^3.0.2" - test-exclude "^6.0.0" - v8-to-istanbul "^9.0.0" - yargs "^17.7.2" - yargs-parser "^21.1.1" - cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" @@ -5123,16 +4571,6 @@ cacheable-request@^7.0.2: normalize-url "^6.0.1" responselike "^2.0.0" -caching-transform@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz" - integrity sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA== - dependencies: - hasha "^5.0.0" - make-dir "^3.0.0" - package-hash "^4.0.0" - write-file-atomic "^3.0.0" - call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -5155,7 +4593,7 @@ camelcase-keys@^6.2.2: map-obj "^4.0.0" quick-lru "^4.0.1" -camelcase@^5.0.0, camelcase@^5.3.1: +camelcase@^5.3.1: version "5.3.1" resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== @@ -5165,11 +4603,6 @@ camelcase@^6.0.0: resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== -caniuse-lite@^1.0.30001366: - version "1.0.30001370" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001370.tgz#0a30d4f20d38b9e108cc5ae7cc62df9fe66cd5ba" - integrity sha512-3PDmaP56wz/qz7G508xzjx8C+MC2qEm4SYhSEzC9IBROo+dGXFWRuaXkWti0A9tuI00g+toiriVqxtWMgl350g== - case@^1.6.3: version "1.6.3" resolved "https://registry.npmjs.org/case/-/case-1.6.3.tgz" @@ -5180,14 +4613,7 @@ catering@^2.0.0, catering@^2.1.0, catering@^2.1.1: resolved "https://registry.yarnpkg.com/catering/-/catering-2.1.1.tgz#66acba06ed5ee28d5286133982a927de9a04b510" integrity sha512-K7Qy8O9p76sL3/3m7/zLKbRkyOlSZAgzEaLhyj2mXS8PsCud2Eo4hAb8aLtZqHh0QGqLcb9dlJSu6lHRVENm1w== -chai-as-promised@^7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.1.tgz" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== - dependencies: - check-error "^1.0.2" - -chai@^4.3.10, chai@^4.3.7, chai@^4.3.8: +chai@^4.3.10: version "4.3.10" resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.10.tgz#d784cec635e3b7e2ffb66446a63b4e33bd390384" integrity sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g== @@ -5215,7 +4641,7 @@ chalk@4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -5255,11 +4681,6 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= - check-error@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" @@ -5267,7 +4688,7 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -chokidar@3.5.3, chokidar@^3.5.1: +chokidar@3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -5292,11 +4713,6 @@ chownr@^2.0.0: resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== -chrome-trace-event@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" - integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== - chromium-bidi@0.4.16: version "0.4.16" resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.16.tgz#8a67bfdf6bb8804efc22765a82859d20724b46ab" @@ -5372,15 +4788,6 @@ cli-width@^4.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.0.0.tgz#a5622f6a3b0a9e3e711a25f099bf2399f608caf6" integrity sha512-ZksGS2xpa/bYkNzN3BAw1wEjsLV/ZKOf/CCrJ/QOBsxx6fOARIkwTutxp1XIOIohi6HKmOFjMoK/XaqDVUpEEw== -cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -5481,11 +4888,6 @@ color@3.0.x: color-convert "^1.9.1" color-string "^1.5.2" -colors@1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - colorspace@1.1.x: version "1.1.2" resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz" @@ -5502,16 +4904,6 @@ columnify@1.6.0: strip-ansi "^6.0.1" wcwidth "^1.0.0" -combine-source-map@~0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.8.0.tgz#a58d0df042c186fcf822a8e8015f5450d2d79a8b" - integrity sha512-UlxQ9Vw0b/Bt/KYwCFqdEwsQ1eL8d1gibiFb7lxQJFdvTgc2hIZi6ugsg+kyhzhPV+QEpUiEIwInIAIrgoEkrg== - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - combined-stream@^1.0.6, combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" @@ -5519,35 +4911,11 @@ combined-stream@^1.0.6, combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" -commander@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/commander/-/commander-1.0.4.tgz#5edeb1aee23c4fb541a6b70d692abef19669a2d3" - integrity sha512-Xz0JOF7NqSubDnWmw7qvX1FuIpCsV62ci/gkpa2NFlm+roeMniBtbxK8QePjs762ZGsuhKaGgcb83eaBiSJ16A== - dependencies: - keypress "0.1.x" - -commander@^2.20.0: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - commander@^9.3.0: version "9.5.0" resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== -commander@~2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - integrity sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A== - dependencies: - graceful-readlink ">= 1.0.0" - -commondir@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" - integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= - compare-func@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" @@ -5561,7 +4929,7 @@ compare-module-exports@^2.1.0: resolved "https://registry.npmjs.org/compare-module-exports/-/compare-module-exports-2.1.0.tgz" integrity sha512-3Lc0sTIuX1jmY2K2RrXRJOND6KsRTX2D4v3+eu1PDptsuJZVK4LZc852eZa9I+avj0NrUKlTNgqvccNOH6mbGg== -component-emitter@^1.3.0, component-emitter@~1.3.0: +component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -5601,16 +4969,6 @@ concat-stream@^2.0.0: readable-stream "^3.0.2" typedarray "^0.0.6" -connect@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.7.0.tgz#5d49348910caa5e07a01800b030d0c35f20484f8" - integrity sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ== - dependencies: - debug "2.6.9" - finalhandler "1.1.2" - parseurl "~1.3.3" - utils-merge "1.0.1" - console-browserify@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz" @@ -5633,11 +4991,6 @@ content-disposition@^0.5.3: dependencies: safe-buffer "5.2.1" -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - conventional-changelog-angular@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-6.0.0.tgz#a9a9494c28b7165889144fd5b91573c4aa9ca541" @@ -5711,43 +5064,16 @@ conventional-recommended-bump@7.0.1: git-semver-tags "^5.0.0" meow "^8.1.2" -convert-source-map@^1.6.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" - integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== - -convert-source-map@^1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" - integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== - dependencies: - safe-buffer "~5.1.1" - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -convert-source-map@~1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" - integrity sha512-Y8L5rp6jo+g9VEPgvqNfEopjTR4OTYct8lXlS8iVQdmnjDvbdbzYe9rjtFCB9egC86JoNCU61WRY+ScjkZpnIg== - -convert-source-map@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.2.0.tgz#44c08c2506f10fb3ca6fd888d5a3444cf8d6a669" - integrity sha512-S8g9WfpATYd4Qajgygr9CsIRSvd+omrKmaqLE0Lz4dSWprOFpWSqYTrXBTNrYqM+x4OaLlFWhJSOJHU8vuU1wA== - cookie@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -cookie@~0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - cookiejar@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" @@ -5763,14 +5089,6 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cors@~2.8.5: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - cosmiconfig@^8.2.0: version "8.3.6" resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" @@ -5924,11 +5242,6 @@ csv-stringify@^5.6.2: resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.2.tgz" integrity sha512-n3rIVbX6ylm1YsX2NEug9IaPV8xRnT+9/NNZbrA/bcHgOSSeqtWla6XnI/xmyu57wIw+ASCAoX1oM6EZtqJV0A== -custom-event@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" - integrity sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg== - dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -5984,23 +5297,11 @@ datastore-level@*, datastore-level@^10.1.1: it-take "^3.0.1" level "^8.0.0" -date-format@^4.0.11, date-format@^4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.13.tgz#87c3aab3a4f6f37582c5f5f63692d2956fa67890" - integrity sha512-bnYCwf8Emc3pTD8pXnre+wfnjGtfi5ncMDKy7+cWZXbmRAsdWkOQHrfC1yz/KiwP5thDp2kCHWYWKBX4HP1hoQ== - dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: version "4.3.1" resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" @@ -6008,7 +5309,7 @@ debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1: dependencies: ms "2.1.2" -debug@4.3.4, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4.3.4, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -6030,7 +5331,7 @@ decamelize-keys@^1.1.0: decamelize "^1.1.0" map-obj "^1.0.0" -decamelize@^1.1.0, decamelize@^1.2.0: +decamelize@^1.1.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -6102,13 +5403,6 @@ default-browser@^4.0.0: execa "^7.1.1" titleize "^3.0.0" -default-require-extensions@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz" - integrity sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg== - dependencies: - strip-bom "^4.0.0" - defaults@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" @@ -6209,11 +5503,6 @@ des.js@^1.0.0: inherits "^2.0.1" minimalistic-assert "^1.0.0" -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - detect-indent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" @@ -6229,10 +5518,10 @@ devtools-protocol@0.0.1147663: resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1147663.tgz#4ec5610b39a6250d1f87e6b9c7e16688ed0ac78e" integrity sha512-hyWmRrexdhbZ1tcJUGpO95ivbRhWXz++F4Ko+n21AY5PNln2ovoJw+8ZMNDTtip+CNFQfrtLVh/w4009dXO/eQ== -devtools-protocol@^0.0.1237913: - version "0.0.1237913" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1237913.tgz#ac0208ff0cbe9c53646753576b5c1d788e3caa38" - integrity sha512-Pxtmz2ZIqBkpU82HaIdsvCQBG94yTC4xajrEsWx9p38QKEfBCJktSazsHkrjf9j3dVVNPhg5LR21F6KWeXpjiQ== +devtools-protocol@^0.0.1245094: + version "0.0.1245094" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1245094.tgz#fc84014e144730edb59c0591a6629600b570e54f" + integrity sha512-c7Tk8wCk2bw+wuQbl8vDh/7rDboWY8TEtcuHj5Q8S9E4F0AJMGJBnp+OqBCTI+xuVeGitQHt04/Rp3tzUStJxg== dezalgo@^1.0.4: version "1.0.4" @@ -6242,11 +5531,6 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" -di@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" - integrity sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -6262,11 +5546,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -diff@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" - integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== - diffie-hellman@^5.0.0: version "5.0.3" resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz" @@ -6340,16 +5619,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-serialize@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" - integrity sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ== - dependencies: - custom-event "~1.0.0" - ent "~2.2.0" - extend "^3.0.0" - void-elements "^2.0.0" - domain-browser@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz" @@ -6414,11 +5683,6 @@ edgedriver@^5.3.5: unzipper "^0.10.14" which "^4.0.0" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - ejs@^3.1.7: version "3.1.9" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.9.tgz#03c9e8777fe12686a9effcef22303ca3d8eeb361" @@ -6426,11 +5690,6 @@ ejs@^3.1.7: dependencies: jake "^10.8.5" -electron-to-chromium@^1.4.188: - version "1.4.200" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.200.tgz#6e4c5266106688965b4ea7caa11f0dd315586854" - integrity sha512-nPyI7oHc8T64oSqRXrAt99gNMpk0SAgPHw/o+hkNKyb5+bcdnFtZcSO9FUJES5cVkVZvo8u4qiZ1gQILl8UXsA== - electron@^26.2.2: version "26.2.4" resolved "https://registry.yarnpkg.com/electron/-/electron-26.2.4.tgz#36616b2386b083c13ae9188f2d8ccf233c23404a" @@ -6468,11 +5727,6 @@ enabled@2.0.x: resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - encoding@^0.1.12, encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -6487,36 +5741,7 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -engine.io-parser@~5.0.3: - version "5.0.4" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.0.4.tgz#0b13f704fa9271b3ec4f33112410d8f3f41d0fc0" - integrity sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg== - -engine.io@~6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.2.0.tgz#003bec48f6815926f2b1b17873e576acd54f41d0" - integrity sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg== - dependencies: - "@types/cookie" "^0.4.1" - "@types/cors" "^2.8.12" - "@types/node" ">=10.0.0" - accepts "~1.3.4" - base64id "2.0.0" - cookie "~0.4.1" - cors "~2.8.5" - debug "~4.3.1" - engine.io-parser "~5.0.3" - ws "~8.2.3" - -enhanced-resolve@^5.0.0: - version "5.10.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz#0dc579c3bb2a1032e357ac45b8f3a6f3ad4fb1e6" - integrity sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - -enhanced-resolve@^5.12.0, enhanced-resolve@^5.15.0: +enhanced-resolve@^5.12.0: version "5.15.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz#1af946c7d93603eb88e9896cee4904dc012e9c35" integrity sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg== @@ -6531,11 +5756,6 @@ enquirer@~2.3.6: dependencies: ansi-colors "^4.1.1" -ent@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" - integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== - entities@^4.4.0: version "4.5.0" resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -6734,11 +5954,6 @@ es-abstract@^1.22.1: unbox-primitive "^1.0.2" which-typed-array "^1.1.11" -es-module-lexer@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.3.0.tgz#6be9c9e0b4543a60cd166ff6f8b4e9dae0b0c16f" - integrity sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA== - es-set-tostringtag@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz#338d502f6f674301d710b80c8592de8a15f09cd8" @@ -6764,7 +5979,7 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -es6-error@^4.0.1, es6-error@^4.1.1: +es6-error@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz" integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== @@ -6874,11 +6089,6 @@ eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" -eslint-plugin-chai-expect@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-3.0.0.tgz#812d7384756177b2d424040cb3c20e78606db1b2" - integrity sha512-NS0YBcToJl+BRKBSMCwRs/oHJIX67fG5Gvb4tGked+9Wnd1/PzKijd82B2QVKcSSOwRe+pp4RAJ2AULeck4eQw== - eslint-plugin-es@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz" @@ -6910,14 +6120,6 @@ eslint-plugin-import@^2.28.1: semver "^6.3.1" tsconfig-paths "^3.14.2" -eslint-plugin-mocha@^10.2.0: - version "10.2.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-mocha/-/eslint-plugin-mocha-10.2.0.tgz#15b05ce5be4b332bb0d76826ec1c5ebf67102ad6" - integrity sha512-ZhdxzSZnd1P9LqDPF0DBcFLpRIGdh1zkF2JHnQklKQOvrQtT73kdP5K9V2mzvbLR+cCAO9OI48NXK/Ax9/ciCQ== - dependencies: - eslint-utils "^3.0.0" - rambda "^7.4.0" - eslint-plugin-prettier@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz#6887780ed95f7708340ec79acfdf60c35b9be57a" @@ -6926,13 +6128,12 @@ eslint-plugin-prettier@^5.0.0: prettier-linter-helpers "^1.0.0" synckit "^0.8.5" -eslint-scope@5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +eslint-plugin-vitest@^0.3.20: + version "0.3.20" + resolved "https://registry.yarnpkg.com/eslint-plugin-vitest/-/eslint-plugin-vitest-0.3.20.tgz#9c4e02dd0252ad359b1e02dbcfbe4cf7ad8d091a" + integrity sha512-O05k4j9TGMOkkghj9dRgpeLDyOSiVIxQWgNDPfhYPm5ioJsehcYV/zkRLekQs+c8+RBCVXucSED3fYOyy2EoWA== dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" + "@typescript-eslint/utils" "^6.15.0" eslint-scope@^7.2.2: version "7.2.2" @@ -6949,23 +6150,11 @@ eslint-utils@^2.0.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - eslint-visitor-keys@^1.1.0: version "1.3.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint-visitor-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz" - integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== - eslint-visitor-keys@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" @@ -7066,11 +6255,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz" @@ -7182,7 +6366,7 @@ events@1.1.1: resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw== -events@^3.0.0, events@^3.2.0, events@^3.3.0: +events@^3.0.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -7272,11 +6456,6 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -7520,28 +6699,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -find-cache-dir@^3.2.0: - version "3.3.1" - resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz" - integrity sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ== - dependencies: - commondir "^1.0.1" - make-dir "^3.0.2" - pkg-dir "^4.1.0" - find-my-way@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-7.6.0.tgz#f1e271fd1aafe87e87860662f9940124274f73c7" @@ -7600,11 +6757,6 @@ flatted@^3.1.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== -flatted@^3.2.5: - version "3.2.6" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" - integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== - fn.name@1.x.x: version "1.1.0" resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" @@ -7627,14 +6779,6 @@ foreach@^2.0.5: resolved "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz" integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" @@ -7697,11 +6841,6 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fromentries@^1.2.0: - version "1.3.2" - resolved "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz" - integrity sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg== - fs-constants@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" @@ -7870,12 +7009,7 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" -gensync@^1.0.0-beta.1: - version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - -get-caller-file@^2.0.1, get-caller-file@^2.0.5: +get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== @@ -7938,11 +7072,6 @@ get-iterator@^2.0.1: resolved "https://registry.yarnpkg.com/get-iterator/-/get-iterator-2.0.1.tgz#a904829f61bace789e0d64bd1a504c511a015c3f" integrity sha512-7HuY/hebu4gryTDT7O/XY/fvY9wRByEGdK6QOa4of8npTcv0+NS6frFKABcf6S9EBAsveTuKTsZQQBFMMNILIg== -get-package-type@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" - integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== - get-pkg-repo@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" @@ -8071,11 +7200,6 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob-to-regexp@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" - integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== - glob@7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -8111,7 +7235,7 @@ glob@^10.2.2: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: +glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -8177,11 +7301,6 @@ global-agent@^3.0.0: semver "^7.3.2" serialize-error "^7.0.1" -globals@^11.1.0: - version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - globals@^13.19.0: version "13.20.0" resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" @@ -8254,7 +7373,7 @@ graceful-fs@4.2.11, graceful-fs@^4.2.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -8264,11 +7383,6 @@ graceful-fs@^4.2.6: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== -"graceful-readlink@>= 1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" - integrity sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w== - grapheme-splitter@^1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" @@ -8364,14 +7478,6 @@ hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -hasha@^5.0.0: - version "5.2.2" - resolved "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz" - integrity sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ== - dependencies: - is-stream "^2.0.0" - type-fest "^0.8.0" - hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -8553,13 +7659,6 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -8567,6 +7666,13 @@ iconv-lite@0.6.3, iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@1.1.13: version "1.1.13" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" @@ -8690,13 +7796,6 @@ init-package-json@5.0.0: validate-npm-package-license "^3.0.4" validate-npm-package-name "^5.0.0" -inline-source-map@~0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" - integrity sha512-0mVWSSbNDvedDWIN4wxLsdPM4a7cIPcpyMxj3QZ406QRwQ6ePGB1YIHxVPjqpcUGbWQ5C+nHTwGNWAGvt7ggVA== - dependencies: - source-map "~0.5.3" - inquirer@^8.2.4: version "8.2.4" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4" @@ -8885,13 +7984,6 @@ is-core-module@^2.13.0: dependencies: has "^1.0.3" -is-core-module@^2.2.0, is-core-module@^2.5.0: - version "2.10.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" - integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== - dependencies: - has "^1.0.3" - is-core-module@^2.3.0: version "2.5.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz" @@ -8899,6 +7991,13 @@ is-core-module@^2.3.0: dependencies: has "^1.0.3" +is-core-module@^2.5.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.10.0.tgz#9012ede0a91c69587e647514e1d5277019e728ed" + integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== + dependencies: + has "^1.0.3" + is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69" @@ -9164,11 +8263,6 @@ is-typed-array@^1.1.3: foreach "^2.0.5" has-symbols "^1.0.1" -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" @@ -9186,11 +8280,6 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - is-wsl@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" @@ -9198,11 +8287,6 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -9213,11 +8297,6 @@ isarray@^2.0.5: resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isbinaryfile@^4.0.8: - version "4.0.10" - resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" - integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -9243,51 +8322,16 @@ isomorphic-ws@^5.0.0: resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz#e5529148912ecb9b451b46ed44d53dae1ce04bbf" integrity sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw== -istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.0.0-alpha.1: +istanbul-lib-coverage@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== -istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - istanbul-lib-coverage@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-hook@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz" - integrity sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ== - dependencies: - append-transform "^2.0.0" - -istanbul-lib-instrument@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - -istanbul-lib-processinfo@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz" - integrity sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw== - dependencies: - archy "^1.0.0" - cross-spawn "^7.0.0" - istanbul-lib-coverage "^3.0.0-alpha.1" - make-dir "^3.0.0" - p-map "^3.0.0" - rimraf "^3.0.0" - uuid "^3.3.3" - istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" @@ -9306,15 +8350,6 @@ istanbul-lib-report@^3.0.1: make-dir "^4.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz" - integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^3.0.0" - source-map "^0.6.1" - istanbul-lib-source-maps@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" @@ -9324,14 +8359,6 @@ istanbul-lib-source-maps@^4.0.1: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz" - integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - istanbul-reports@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" @@ -9555,15 +8582,6 @@ jest-get-type@^29.6.3: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-worker@^27.4.5: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - jmespath@0.15.0: version "0.15.0" resolved "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz" @@ -9579,17 +8597,12 @@ js-sha3@0.8.0: resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== -js-string-escape@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" - integrity sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@3.14.1, js-yaml@^3.10.0, js-yaml@^3.13.1: +js-yaml@3.14.1, js-yaml@^3.10.0: version "3.14.1" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== @@ -9631,11 +8644,6 @@ jsdom@^23.0.1: ws "^8.14.2" xml-name-validator "^5.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" @@ -9646,7 +8654,7 @@ json-parse-better-errors@^1.0.1: resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== -json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: +json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== @@ -9692,13 +8700,6 @@ json5@^1.0.2: dependencies: minimist "^1.2.0" -json5@^2.1.2: - version "2.2.0" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - json5@^2.2.2: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -9735,114 +8736,11 @@ jsonpointer@^5.0.0: resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559" integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ== -just-extend@^4.0.2: - version "4.2.1" - resolved "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz" - integrity sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg== - jwt-simple@0.5.6: version "0.5.6" resolved "https://registry.npmjs.org/jwt-simple/-/jwt-simple-0.5.6.tgz" integrity sha512-40aUybvhH9t2h71ncA1/1SbtTNCVZHgsTsTgqPUxGWDmUDrXyDf2wMNQKEbdBjbf4AI+fQhbECNTV6lWxQKUzg== -karma-chai@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/karma-chai/-/karma-chai-0.1.0.tgz#bee5ad40400517811ae34bb945f762909108b79a" - integrity sha512-mqKCkHwzPMhgTYca10S90aCEX9+HjVjjrBFAsw36Zj7BlQNbokXXCAe6Ji04VUMsxcY5RLP7YphpfO06XOubdg== - -karma-chrome-launcher@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-3.2.0.tgz#eb9c95024f2d6dfbb3748d3415ac9b381906b9a9" - integrity sha512-rE9RkUPI7I9mAxByQWkGJFXfFD6lE4gC5nPuZdobf/QdTEJI6EU4yIay/cfU/xV4ZxlM5JiTv7zWYgA64NpS5Q== - dependencies: - which "^1.2.1" - -karma-cli@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/karma-cli/-/karma-cli-2.0.0.tgz#481548d28661af4cc68f3d8e09708f17d2cba931" - integrity sha512-1Kb28UILg1ZsfqQmeELbPzuEb5C6GZJfVIk0qOr8LNYQuYWmAaqP16WpbpKEjhejDrDYyYOwwJXSZO6u7q5Pvw== - dependencies: - resolve "^1.3.3" - -karma-electron@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/karma-electron/-/karma-electron-7.3.0.tgz#269897d2566262e6ddc594a3d408b84275014a5c" - integrity sha512-JCwAZxtzLo+Qk6HD8MqlU+c6mB7A5jZYNb+ftbMNxutnmi1hzb8/wIqJzpw087R7jV5ZzNHujMq8mStI5n4Q6Q== - dependencies: - async "~3.2.2" - combine-source-map "~0.8.0" - commander "~2.9.0" - convert-source-map "~1.2.0" - js-string-escape "~1.0.0" - minstache "~1.2.0" - xtend "~4.0.1" - -karma-firefox-launcher@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-2.1.2.tgz#9a38cc783c579a50f3ed2a82b7386186385cfc2d" - integrity sha512-VV9xDQU1QIboTrjtGVD4NCfzIH7n01ZXqy/qpBhnOeGVOkG5JYPEm8kuSd7psHE6WouZaQ9Ool92g8LFweSNMA== - dependencies: - is-wsl "^2.2.0" - which "^2.0.1" - -karma-mocha@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-2.0.1.tgz#4b0254a18dfee71bdbe6188d9a6861bf86b0cd7d" - integrity sha512-Tzd5HBjm8his2OA4bouAsATYEpZrp9vC7z5E5j4C5Of5Rrs1jY67RAwXNcVmd/Bnk1wgvQRou0zGVLey44G4tQ== - dependencies: - minimist "^1.2.3" - -karma-spec-reporter@^0.0.36: - version "0.0.36" - resolved "https://registry.yarnpkg.com/karma-spec-reporter/-/karma-spec-reporter-0.0.36.tgz#c54dc155dec2ded1f92ea68dbbdd67fcedbef350" - integrity sha512-11bvOl1x6ryKZph7kmbmMpbi8vsngEGxGOoeTlIcDaH3ab3j8aPJnZ+r+K/SS0sBSGy5VGkGYO2+hLct7hw/6w== - dependencies: - colors "1.4.0" - -karma-webpack@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-5.0.0.tgz#2a2c7b80163fe7ffd1010f83f5507f95ef39f840" - integrity sha512-+54i/cd3/piZuP3dr54+NcFeKOPnys5QeM1IY+0SPASwrtHsliXUiCL50iW+K9WWA7RvamC4macvvQ86l3KtaA== - dependencies: - glob "^7.1.3" - minimatch "^3.0.4" - webpack-merge "^4.1.5" - -karma@^6.4.2: - version "6.4.2" - resolved "https://registry.yarnpkg.com/karma/-/karma-6.4.2.tgz#a983f874cee6f35990c4b2dcc3d274653714de8e" - integrity sha512-C6SU/53LB31BEgRg+omznBEMY4SjHU3ricV6zBcAe1EeILKkeScr+fZXtaI5WyDbkVowJxxAI6h73NcFPmXolQ== - dependencies: - "@colors/colors" "1.5.0" - body-parser "^1.19.0" - braces "^3.0.2" - chokidar "^3.5.1" - connect "^3.7.0" - di "^0.0.1" - dom-serialize "^2.2.1" - glob "^7.1.7" - graceful-fs "^4.2.6" - http-proxy "^1.18.1" - isbinaryfile "^4.0.8" - lodash "^4.17.21" - log4js "^6.4.1" - mime "^2.5.2" - minimatch "^3.0.4" - mkdirp "^0.5.5" - qjobs "^1.2.0" - range-parser "^1.2.1" - rimraf "^3.0.2" - socket.io "^4.4.1" - source-map "^0.6.1" - tmp "^0.2.1" - ua-parser-js "^0.7.30" - yargs "^16.1.1" - -keypress@0.1.x: - version "0.1.0" - resolved "https://registry.yarnpkg.com/keypress/-/keypress-0.1.0.tgz#4a3188d4291b66b4f65edb99f806aa9ae293592a" - integrity sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA== - keyv@^4.0.0, keyv@^4.5.3: version "4.5.4" resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" @@ -10096,11 +8994,6 @@ load-json-file@^4.0.0: pify "^3.0.0" strip-bom "^3.0.0" -loader-runner@^4.2.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" - integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== - loady@~0.0.5: version "0.0.5" resolved "https://registry.npmjs.org/loady/-/loady-0.0.5.tgz" @@ -10184,16 +9077,6 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== -lodash.flattendeep@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz" - integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz" - integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= - lodash.ismatch@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" @@ -10204,11 +9087,6 @@ lodash.isplainobject@^4.0.6: resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== -lodash.memoize@~3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" - integrity sha512-eDn9kqrAmVUC1wmZvlQ6Uhde44n+tXpqPrN8olQJbttgh0oKclk+SF54P47VEGE9CEiMeRwAP8BaM7UHvBkz2A== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -10244,7 +9122,7 @@ lodash.zip@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" integrity sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: +lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10265,17 +9143,6 @@ log-symbols@^5.1.0: chalk "^5.0.0" is-unicode-supported "^1.1.0" -log4js@^6.4.1: - version "6.6.0" - resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.6.0.tgz#e8fd00143d1e0ecf1d10959bb69b90b1b30137f3" - integrity sha512-3v8R7fd45UB6THucSht6wN2/7AZEruQbXdjygPZcxt5TA/msO6si9CN5MefUuKXbYnJHTBnYcx4famwcyQd+sA== - dependencies: - date-format "^4.0.11" - debug "^4.3.4" - flatted "^3.2.5" - rfdc "^1.3.0" - streamroller "^3.1.1" - logform@^2.3.2, logform@^2.4.0: version "2.5.1" resolved "https://registry.yarnpkg.com/logform/-/logform-2.5.1.tgz#44c77c34becd71b3a42a3970c77929e52c6ed48b" @@ -10366,13 +9233,13 @@ magic-string@^0.30.3, magic-string@^0.30.5: dependencies: "@jridgewell/sourcemap-codec" "^1.4.15" -magicast@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.2.tgz#42dcade5573ed8f10f5540f9d04964e21dba9130" - integrity sha512-Fjwkl6a0syt9TFN0JSYpOybxiMCkYNEeOTnOTNRbjphirLakznZXAqrXgj/7GG3D1dvETONNwrBfinvAbpunDg== +magicast@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/magicast/-/magicast-0.3.3.tgz#a15760f982deec9dabc5f314e318d7c6bddcb27b" + integrity sha512-ZbrP1Qxnpoes8sz47AM0z08U+jW6TyRgZzcWy3Ma3vDhJttwMwAFDMMQFobwdBxByBD46JYmxRzeF7w2+wJEuw== dependencies: - "@babel/parser" "^7.23.3" - "@babel/types" "^7.23.3" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" source-map-js "^1.0.2" make-dir@4.0.0, make-dir@^4.0.0: @@ -10390,7 +9257,7 @@ make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" -make-dir@^3.0.0, make-dir@^3.0.2: +make-dir@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -10519,11 +9386,6 @@ md5.js@^1.3.4: inherits "^2.0.1" safe-buffer "^5.1.2" -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - memory-level@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/memory-level/-/memory-level-1.0.0.tgz#7323c3fd368f9af2f71c3cd76ba403a17ac41692" @@ -10582,7 +9444,7 @@ micro-ftch@^0.3.1: resolved "https://registry.yarnpkg.com/micro-ftch/-/micro-ftch-0.3.1.tgz#6cb83388de4c1f279a034fb0cf96dfc050853c5f" integrity sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg== -micromatch@^4.0.0, micromatch@^4.0.4: +micromatch@^4.0.4: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -10603,14 +9465,14 @@ mime-db@1.52.0: resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@2.6.0, mime@^2.5.2: +mime@2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== @@ -10674,6 +9536,13 @@ minimatch@5.0.1: dependencies: brace-expansion "^2.0.1" +minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -10702,13 +9571,6 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - minimist-options@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" @@ -10718,7 +9580,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== @@ -10822,13 +9684,6 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -minstache@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minstache/-/minstache-1.2.0.tgz#ff1cc403ac2844f68dbf18c662129be7eb0efc41" - integrity sha512-VSAeaiKXHIKifdNHCalWmFvChtLrNirwhDZd0yeEO57WXCT+uJYN3RPAusvLi3z7VlwFBBtDX80bG7aHkcMAmg== - dependencies: - commander "1.0.4" - mitt@3.0.0, mitt@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.0.tgz#69ef9bd5c80ff6f57473e8d89326d01c414be0bd" @@ -10839,7 +9694,7 @@ mkdirp-classic@^0.5.2: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -"mkdirp@>=0.5 0", mkdirp@^0.5.5: +"mkdirp@>=0.5 0": version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -10925,15 +9780,10 @@ mortice@^3.0.1: p-queue "^7.2.0" p-timeout "^6.0.0" -mrmime@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.1.tgz#5f90c825fad4bdd41dc914eff5d1a8cfdaf24f27" - integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== - -ms@2.0.0: +mrmime@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== ms@2.1.2: version "2.1.2" @@ -11039,12 +9889,12 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= -negotiator@0.6.3, negotiator@^0.6.2, negotiator@^0.6.3: +negotiator@^0.6.2, negotiator@^0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== -neo-async@^2.6.0, neo-async@^2.6.2: +neo-async@^2.6.0: version "2.6.2" resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== @@ -11059,17 +9909,6 @@ nice-try@^1.0.4: resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -nise@^5.1.4: - version "5.1.4" - resolved "https://registry.yarnpkg.com/nise/-/nise-5.1.4.tgz#491ce7e7307d4ec546f5a659b2efe94a18b4bbc0" - integrity sha512-8+Ib8rRJ4L0o3kfmyVCL7gzrohyDe0cMFTBa2d364yIrEGMEoetznKJx899YxjybU6bL9SQkYPSBBs1gyYs8Xg== - dependencies: - "@sinonjs/commons" "^2.0.0" - "@sinonjs/fake-timers" "^10.0.2" - "@sinonjs/text-encoding" "^0.7.1" - just-extend "^4.0.2" - path-to-regexp "^1.7.0" - node-addon-api@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -11199,18 +10038,6 @@ node-machine-id@1.1.12: resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ== -node-preload@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz" - integrity sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ== - dependencies: - process-on-spawn "^1.0.0" - -node-releases@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503" - integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg== - node-stdlib-browser@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.2.0.tgz#5ddcfdf4063b88fb282979a1aa6ddab9728d5e4c" @@ -11513,40 +10340,7 @@ nx@16.9.0, "nx@>=16.5.1 < 17": "@nx/nx-win32-arm64-msvc" "16.9.0" "@nx/nx-win32-x64-msvc" "16.9.0" -nyc@^15.1.0: - version "15.1.0" - resolved "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz" - integrity sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A== - dependencies: - "@istanbuljs/load-nyc-config" "^1.0.0" - "@istanbuljs/schema" "^0.1.2" - caching-transform "^4.0.0" - convert-source-map "^1.7.0" - decamelize "^1.2.0" - find-cache-dir "^3.2.0" - find-up "^4.1.0" - foreground-child "^2.0.0" - get-package-type "^0.1.0" - glob "^7.1.6" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-hook "^3.0.0" - istanbul-lib-instrument "^4.0.0" - istanbul-lib-processinfo "^2.0.2" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - make-dir "^3.0.0" - node-preload "^0.2.1" - p-map "^3.0.0" - process-on-spawn "^1.0.0" - resolve-from "^5.0.0" - rimraf "^3.0.0" - signal-exit "^3.0.2" - spawn-wrap "^2.0.0" - test-exclude "^6.0.0" - yargs "^15.0.2" - -object-assign@^4, object-assign@^4.1.1: +object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -11642,20 +10436,6 @@ on-exit-leak-free@^2.1.0: resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.0.tgz#5c703c968f7e7f851885f6459bf8a8a57edc9cc4" integrity sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w== -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== - dependencies: - ee-first "1.1.1" - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -11855,13 +10635,6 @@ p-map@4.0.0, p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== - dependencies: - aggregate-error "^3.0.0" - p-pipe@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" @@ -11953,16 +10726,6 @@ pac-resolver@^7.0.0: ip "^1.1.8" netmask "^2.0.2" -package-hash@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz" - integrity sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ== - dependencies: - graceful-fs "^4.1.15" - hasha "^5.0.0" - lodash.flattendeep "^4.4.0" - release-zalgo "^1.0.0" - pacote@^15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" @@ -12054,11 +10817,6 @@ parse5@^7.1.2: dependencies: entities "^4.4.0" -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - path-browserify@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz" @@ -12117,13 +10875,6 @@ path-scurry@^1.10.1, path-scurry@^1.6.1: lru-cache "^9.1.1 || ^10.0.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -12232,7 +10983,7 @@ pino@^8.12.0: sonic-boom "^3.1.0" thread-stream "^2.0.0" -pkg-dir@^4.1.0, pkg-dir@^4.2.0: +pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== @@ -12310,13 +11061,6 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -process-on-spawn@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz" - integrity sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg== - dependencies: - fromentries "^1.2.0" - process-warning@^2.0.0, process-warning@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-2.2.0.tgz#008ec76b579820a8e5c35d81960525ca64feb626" @@ -12542,18 +11286,6 @@ puppeteer-core@^20.9.0: devtools-protocol "0.0.1147663" ws "8.13.0" -qjobs@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.2.0.tgz#c45e9c61800bd087ef88d7e256423bdd49e5d071" - integrity sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg== - -qs@6.10.3: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - qs@^6.11.0, qs@^6.11.1: version "6.11.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" @@ -12616,11 +11348,6 @@ race-signal@^1.0.1, race-signal@^1.0.2: resolved "https://registry.yarnpkg.com/race-signal/-/race-signal-1.0.2.tgz#e42379fba0cec4ee8dab7c9bbbd4aa6e0d14c25f" integrity sha512-o3xNv0iTcIDQCXFlF6fPAMEBRjFxssgGoRqLbg06m+AdzEXXLUmoNOoUHTVz2NoBI8hHwKFKoC6IqyNtWr2bww== -rambda@^7.4.0: - version "7.5.0" - resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe" - integrity sha512-y/M9weqWAH4iopRd7EHDEQQvpFPHj1AA3oHozE9tfITHUtTR7Z9PSlIRRG2l1GuW7sefC1cXFfIcF+cgnShdBA== - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" @@ -12636,26 +11363,11 @@ randomfill@^1.0.3: randombytes "^2.0.5" safe-buffer "^5.1.0" -range-parser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - rate-limiter-flexible@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/rate-limiter-flexible/-/rate-limiter-flexible-4.0.0.tgz#4754706216f0b442e7527b1367e42b7682145010" integrity sha512-SkA18LEPqJJKHixi6E7tzBKTXbj9gu5wPyfTykPVRZR5JGSw0dMCjtZsjlfuabVY940pu28Wu87NZN4FhztnyQ== -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -12838,13 +11550,6 @@ regexpp@^3.0.0: resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz" integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q== -release-zalgo@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz" - integrity sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA= - dependencies: - es6-error "^4.0.1" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -12855,11 +11560,6 @@ require-from-string@^2.0.2: resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -12892,14 +11592,7 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve-typescript-plugin@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/resolve-typescript-plugin/-/resolve-typescript-plugin-2.0.1.tgz#ae4a1a81372b1e3389239268ac774bcc2780f4e3" - integrity sha512-n0FdUHSo8vkT6omKdE+Gda7api6PzIwsoYH4RTH0tUpRq46hk8dOcWZpzBwpoJyjSz3OxHIC/hKGL8LB8B09GQ== - dependencies: - tslib "2.5.0" - -resolve@^1.10.0, resolve@^1.22.1, resolve@^1.3.3: +resolve@^1.10.0, resolve@^1.22.1: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -12924,14 +11617,6 @@ resolve@^1.17.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.3.2: - version "1.20.0" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz" - integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - responselike@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc" @@ -13205,24 +11890,6 @@ saxes@^6.0.0: dependencies: xmlchars "^2.2.0" -schema-utils@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" - integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - -schema-utils@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" - integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== - dependencies: - "@types/json-schema" "^7.0.8" - ajv "^6.12.5" - ajv-keywords "^3.5.2" - scrypt-js@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" @@ -13238,7 +11905,7 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -13250,7 +11917,7 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.0.0, semver@^6.1.0, semver@^6.2.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -13283,13 +11950,6 @@ serialize-javascript@6.0.0: dependencies: randombytes "^2.1.0" -serialize-javascript@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" - integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== - dependencies: - randombytes "^2.1.0" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" @@ -13405,42 +12065,13 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -sinon-chai@^3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/sinon-chai/-/sinon-chai-3.7.0.tgz#cfb7dec1c50990ed18c153f1840721cf13139783" - integrity sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g== - -sinon@^15.0.3: - version "15.0.3" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-15.0.3.tgz#38005fcd80827177b6aa0245f82401d9ec88994b" - integrity sha512-si3geiRkeovP7Iel2O+qGL4NrO9vbMf3KsrJEi0ghP1l5aBkB5UxARea5j0FUsSqH3HLBh0dQPAyQ8fObRUqHw== - dependencies: - "@sinonjs/commons" "^3.0.0" - "@sinonjs/fake-timers" "^10.0.2" - "@sinonjs/samsam" "^8.0.0" - diff "^5.1.0" - nise "^5.1.4" - supports-color "^7.2.0" - -sinon@^16.0.0: - version "16.0.0" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-16.0.0.tgz#06da4e63624b946c9d7e67cce21c2f67f40f23a9" - integrity sha512-B8AaZZm9CT5pqe4l4uWJztfD/mOTa7dL8Qo0W4+s+t74xECOgSZDDQCBjNgIK3+n4kyxQrSTv2V5ul8K25qkiQ== - dependencies: - "@sinonjs/commons" "^3.0.0" - "@sinonjs/fake-timers" "^10.3.0" - "@sinonjs/samsam" "^8.0.0" - diff "^5.1.0" - nise "^5.1.4" - supports-color "^7.2.0" - -sirv@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.3.tgz#ca5868b87205a74bef62a469ed0296abceccd446" - integrity sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA== +sirv@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" + integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" totalist "^3.0.0" slash@3.0.0, slash@^3.0.0: @@ -13477,32 +12108,6 @@ snappyjs@^0.7.0: resolved "https://registry.yarnpkg.com/snappyjs/-/snappyjs-0.7.0.tgz#6096eac06382700ae7fdefa579dea5e2aa20f51c" integrity sha512-u5iEEXkMe2EInQio6Wv9LWHOQYRDbD2O9hzS27GpT/lwfIQhTCnHCTqedqHIHe9ZcvQo+9au6vngQayipz1NYw== -socket.io-adapter@~2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz#b50a4a9ecdd00c34d4c8c808224daa1a786152a6" - integrity sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg== - -socket.io-parser@~4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.5.tgz#cb404382c32324cc962f27f3a44058cf6e0552df" - integrity sha512-sNjbT9dX63nqUFIOv95tTVm6elyIU4RvB1m8dOeZt+IgWwcWklFDOdmGcfo3zSiRsnR/3pJkjY5lfoGqEe4Eig== - dependencies: - "@types/component-emitter" "^1.2.10" - component-emitter "~1.3.0" - debug "~4.3.1" - -socket.io@^4.4.1: - version "4.5.1" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.5.1.tgz#aa7e73f8a6ce20ee3c54b2446d321bbb6b1a9029" - integrity sha512-0y9pnIso5a9i+lJmsCdtmTTgJFFSvNQKDnPQRz28mGNnxbmqYg2QPtJTLFxhymFZhAIn50eHAKzJeiNaKr+yUQ== - dependencies: - accepts "~1.3.4" - base64id "~2.0.0" - debug "~4.3.2" - engine.io "~6.2.0" - socket.io-adapter "~2.4.0" - socket.io-parser "~4.0.4" - socks-proxy-agent@^6.0.0: version "6.1.1" resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz" @@ -13565,7 +12170,7 @@ source-map-js@^1.0.2: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@^0.5.21, source-map-support@~0.5.20: +source-map-support@^0.5.21: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -13573,28 +12178,11 @@ source-map-support@^0.5.21, source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.5.0, source-map@~0.5.3: - version "0.5.7" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spawn-wrap@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz" - integrity sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg== - dependencies: - foreground-child "^2.0.0" - is-windows "^1.0.2" - make-dir "^3.0.0" - rimraf "^3.0.0" - signal-exit "^3.0.2" - which "^2.0.1" - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -13710,11 +12298,6 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - std-env@^3.5.0: version "3.6.0" resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.6.0.tgz#94807562bddc68fa90f2e02c5fd5b6865bb4e98e" @@ -13778,15 +12361,6 @@ stream-to-it@^0.2.2: dependencies: get-iterator "^1.0.2" -streamroller@^3.1.1: - version "3.1.2" - resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.1.2.tgz#abd444560768b340f696307cf84d3f46e86c0e63" - integrity sha512-wZswqzbgGGsXYIrBYhOE0yP+nQ6XRk7xDcYwuQAGTYXdyAUmvgVFE0YU1g5pvQT0m7GBaQfYcSnlHbapuK0H0A== - dependencies: - date-format "^4.0.13" - debug "^4.3.4" - fs-extra "^8.1.0" - streamx@^2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" @@ -14030,7 +12604,7 @@ supertest@^6.3.3: methods "^1.1.2" superagent "^8.0.5" -supports-color@8.1.1, supports-color@^8.0.0: +supports-color@8.1.1: version "8.1.1" resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== @@ -14044,7 +12618,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0, supports-color@^7.2.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -14074,7 +12648,7 @@ systeminformation@^5.17.12: resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.21.7.tgz#53ef75daaf5d756d015f4bb02e059126ccac74f2" integrity sha512-K3LjnajrazTLTD61+87DFg8IXFk5ljx6nSBqB8pQLtC1UPivAjDtTYGPZ8jaBFxcesPaCOkvLRtBq+RFscrsLw== -tapable@^2.1.1, tapable@^2.2.0: +tapable@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== @@ -14165,27 +12739,6 @@ temp-dir@1.0.0: resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" integrity sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ== -terser-webpack-plugin@^5.3.7: - version "5.3.9" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" - integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.17" - jest-worker "^27.4.5" - schema-utils "^3.1.1" - serialize-javascript "^6.0.1" - terser "^5.16.8" - -terser@^5.16.8: - version "5.18.2" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.18.2.tgz#ff3072a0faf21ffd38f99acc9a0ddf7b5f07b948" - integrity sha512-Ah19JS86ypbJzTzvUCX7KOsEIhDaRONungA4aYBjEP3JZRf4ocuDzTg4QWZnPn9DEMiMYGJPiSOy7aykoCc70w== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" @@ -14395,16 +12948,6 @@ ts-api-utils@^1.0.1: resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.0.1.tgz#8144e811d44c749cd65b2da305a032510774452d" integrity sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A== -ts-loader@^9.4.4: - version "9.4.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" - integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== - dependencies: - chalk "^4.1.0" - enhanced-resolve "^5.0.0" - micromatch "^4.0.0" - semver "^7.3.4" - ts-node@^10.8.1, ts-node@^10.9.1: version "10.9.1" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" @@ -14458,11 +13001,6 @@ tslib@2.4.0, tslib@^2.3.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - tslib@^1.10.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" @@ -14529,7 +13067,7 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" -type-detect@4.0.8, type-detect@^4.0.0, type-detect@^4.0.8: +type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== @@ -14569,7 +13107,7 @@ type-fest@^0.6.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== -type-fest@^0.8.0, type-fest@^0.8.1: +type-fest@^0.8.1: version "0.8.1" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== @@ -14584,14 +13122,6 @@ type-fest@^3.0.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-3.7.2.tgz#08f83ee3229b63077e95c9035034d32905969457" integrity sha512-f9BHrLjRJ4MYkfOsnC/53PNDzZJcVo14MqLp2+hXE39p5bgwqohxR5hDZztwxlbxmIVuvC2EFAKrAkokq23PLA== -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -14631,13 +13161,6 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -14661,11 +13184,6 @@ typescript-docs-verifier@^2.5.0: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -ua-parser-js@^0.7.30: - version "0.7.33" - resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532" - integrity sha512-s8ax/CeZdK9R/56Sui0WM6y9OFREJarMRHqLB2EwkovemBxNQ+Bqu8GAsUnVcXKgphb++ghr/B2BZx4mahujPw== - ufo@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.3.1.tgz#e085842f4627c41d4c1b60ebea1f75cdab4ce86b" @@ -14783,11 +13301,6 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -14814,14 +13327,6 @@ upath@2.0.1: resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== -update-browserslist-db@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38" - integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -14907,11 +13412,6 @@ util@^0.12.4, util@^0.12.5: is-typed-array "^1.1.3" which-typed-array "^1.1.2" -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - uuid@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" @@ -14950,15 +13450,6 @@ v8-compile-cache@2.3.0: resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^9.0.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" - integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - v8-to-istanbul@^9.2.0: version "9.2.0" resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" @@ -14990,15 +13481,10 @@ validate-npm-package-name@^3.0.0: dependencies: builtins "^1.0.3" -vary@^1: - version "1.1.2" - resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -vite-node@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.1.0.tgz#0ebcb7398692e378954786dfba28e905e28a76b4" - integrity sha512-jV48DDUxGLEBdHCQvxL1mEh7+naVy+nhUUUaPAZLd3FJgXuxQiewHcfeZebbJ6onDqNGkP4r3MhQ342PRlG81Q== +vite-node@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.2.1.tgz#bca96ae91b2b1ee9a7aa73685908362d70ce26a8" + integrity sha512-fNzHmQUSOY+y30naohBvSW7pPn/xn3Ib/uqm+5wAJQJiqQsU0NBR78XdRJb04l4bOFKjpTWld0XAfkKlrDbySg== dependencies: cac "^6.7.14" debug "^4.3.4" @@ -15006,10 +13492,10 @@ vite-node@1.1.0: picocolors "^1.0.0" vite "^5.0.0" -vite-plugin-node-polyfills@^0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.18.0.tgz#2ad147960f7a35dbbb1c9f9c1ae928bd0f438c1e" - integrity sha512-zkdLD3gpOhLFyxYRMJ5apk0RcODhomuS3XQgExowiX8naoc251JfcP3toqnfDlMdF0xuPYahre/H38xAcq8ApA== +vite-plugin-node-polyfills@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.19.0.tgz#54338c47d29fa4c3a19fcd369001331290094c81" + integrity sha512-AhdVxAmVnd1doUlIRGUGV6ZRPfB9BvIwDF10oCOmL742IsvsFIAV4tSMxSfu5e0Px0QeJLgWVOSbtHIvblzqMw== dependencies: "@rollup/plugin-inject" "^5.0.5" node-stdlib-browser "^1.2.0" @@ -15034,22 +13520,22 @@ vite@^5.0.0: optionalDependencies: fsevents "~2.3.3" -vitest-when@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/vitest-when/-/vitest-when-0.3.0.tgz#663d4274f1e7302bd24ec00dda8269d20b2eff04" - integrity sha512-wYfmzd+GkvdNNhbeb/40PnKpetUP5I7qxvdbu1OAXRXaLrnLfSrJTa/dMIbqqrc8SA0vhonpw5p0RHDXwhDM1Q== +vitest-when@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/vitest-when/-/vitest-when-0.3.1.tgz#72db1c0a8e76fae81f8fc21c6da3c769f8e7f8bb" + integrity sha512-qZt4VmuvGtkLEqUpq5AJHQtdfhU8wJH+eXHk+WBo8kFT5zdfVV06+vFgYzvuSOq73srlCEsJ4VJqX7uBtOwWLg== -vitest@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.1.0.tgz#47ba67c564aa137b53b0197d2a992908e7f5b04d" - integrity sha512-oDFiCrw7dd3Jf06HoMtSRARivvyjHJaTxikFxuqJjO76U436PqlVw1uLn7a8OSPrhSfMGVaRakKpA2lePdw79A== - dependencies: - "@vitest/expect" "1.1.0" - "@vitest/runner" "1.1.0" - "@vitest/snapshot" "1.1.0" - "@vitest/spy" "1.1.0" - "@vitest/utils" "1.1.0" - acorn-walk "^8.3.0" +vitest@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.2.1.tgz#9afb705826a2c6260a71b625d28b49117833dce6" + integrity sha512-TRph8N8rnSDa5M2wKWJCMnztCZS9cDcgVTQ6tsTFTG/odHJ4l5yNVqvbeDJYJRZ6is3uxaEpFs8LL6QM+YFSdA== + dependencies: + "@vitest/expect" "1.2.1" + "@vitest/runner" "1.2.1" + "@vitest/snapshot" "1.2.1" + "@vitest/spy" "1.2.1" + "@vitest/utils" "1.2.1" + acorn-walk "^8.3.2" cac "^6.7.14" chai "^4.3.10" debug "^4.3.4" @@ -15063,7 +13549,7 @@ vitest@^1.1.0: tinybench "^2.5.1" tinypool "^0.8.1" vite "^5.0.0" - vite-node "1.1.0" + vite-node "1.2.1" why-is-node-running "^2.2.2" vm-browserify@^1.0.1: @@ -15071,11 +13557,6 @@ vm-browserify@^1.0.1: resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -void-elements@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" - integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== - w3c-xmlserializer@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz#f925ba26855158594d907313cedd1476c5967f6c" @@ -15092,14 +13573,6 @@ wait-port@^1.0.4, wait-port@^1.1.0: commander "^9.3.0" debug "^4.3.4" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== - dependencies: - glob-to-regexp "^0.4.1" - graceful-fs "^4.1.2" - wcwidth@^1.0.0, wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz" @@ -15323,40 +13796,40 @@ web3@^4.0.3: web3-utils "^4.0.3" web3-validator "^1.0.2" -webdriver@8.27.0: - version "8.27.0" - resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.27.0.tgz#27e936a03c08b2d72ed6bd01a6a46f8189ef0abf" - integrity sha512-n1IA+rR3u84XxU9swiKUM06BkEC0GDimfZkBML57cny+utQOUbdM/mBpqCUnkWX/RBz/p2EfHdKNyOs3/REaog== +webdriver@8.28.0: + version "8.28.0" + resolved "https://registry.yarnpkg.com/webdriver/-/webdriver-8.28.0.tgz#8d07eca1b23cc3dd46484ed3a91cbd256a5c6a77" + integrity sha512-1ASMK+sNfVh5rdaRRk+eFLIfae93ViXHJBpuJemeORwZkfOJNF2CNSZl5uK2e6+nzbkY2cjM6QsZwfhL3lCiRg== dependencies: "@types/node" "^20.1.0" "@types/ws" "^8.5.3" - "@wdio/config" "8.27.0" - "@wdio/logger" "8.24.12" + "@wdio/config" "8.28.0" + "@wdio/logger" "8.28.0" "@wdio/protocols" "8.24.12" - "@wdio/types" "8.27.0" - "@wdio/utils" "8.27.0" + "@wdio/types" "8.28.0" + "@wdio/utils" "8.28.0" deepmerge-ts "^5.1.0" got "^12.6.1" ky "^0.33.0" ws "^8.8.0" -webdriverio@^8.27.0: - version "8.27.0" - resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.27.0.tgz#4068b0164ab66bfb62d6eb6b8d97df2d140922d5" - integrity sha512-Qh5VCiBjEmxnmXcL1QEFoDzFqTtaWKrXriuU5G0yHKCModGAt2G7IHTkAok3CpmkVJfZpEvY630aP1MvgDtFhw== +webdriverio@^8.28.0: + version "8.28.0" + resolved "https://registry.yarnpkg.com/webdriverio/-/webdriverio-8.28.0.tgz#ad94292b7b1466aac205d993a93da528c6665626" + integrity sha512-rRVE8pvcxAEqnhhC70oMFkUZ82YWbpXYyzKgfl2LKBue13AHaiN5qWncsJv29rqREIim0dNj6q2JuuUTDFm1gg== dependencies: "@types/node" "^20.1.0" - "@wdio/config" "8.27.0" - "@wdio/logger" "8.24.12" + "@wdio/config" "8.28.0" + "@wdio/logger" "8.28.0" "@wdio/protocols" "8.24.12" "@wdio/repl" "8.24.12" - "@wdio/types" "8.27.0" - "@wdio/utils" "8.27.0" + "@wdio/types" "8.28.0" + "@wdio/utils" "8.28.0" archiver "^6.0.0" aria-query "^5.0.0" css-shorthand-properties "^1.1.1" css-value "^0.0.1" - devtools-protocol "^0.0.1237913" + devtools-protocol "^0.0.1245094" grapheme-splitter "^1.0.2" import-meta-resolve "^4.0.0" is-plain-obj "^4.1.0" @@ -15368,7 +13841,7 @@ webdriverio@^8.27.0: resq "^1.9.1" rgb2hex "0.2.5" serialize-error "^11.0.1" - webdriver "8.27.0" + webdriver "8.28.0" webidl-conversions@^3.0.0: version "3.0.1" @@ -15380,48 +13853,6 @@ webidl-conversions@^7.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== -webpack-merge@^4.1.5: - version "4.2.2" - resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" - integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== - dependencies: - lodash "^4.17.15" - -webpack-sources@^3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" - integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== - -webpack@^5.88.2: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== - dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" - acorn "^8.7.1" - acorn-import-assertions "^1.9.0" - browserslist "^4.14.5" - chrome-trace-event "^1.0.2" - enhanced-resolve "^5.15.0" - es-module-lexer "^1.2.1" - eslint-scope "5.1.1" - events "^3.2.0" - glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" - json-parse-even-better-errors "^2.3.1" - loader-runner "^4.2.0" - mime-types "^2.1.27" - neo-async "^2.6.2" - schema-utils "^3.2.0" - tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" - watchpack "^2.4.0" - webpack-sources "^3.2.3" - whatwg-encoding@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz#d0f4ef769905d426e1688f3e34381a99b60b76e5" @@ -15468,11 +13899,6 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" -which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - which-typed-array@^1.1.11: version "1.1.11" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" @@ -15509,7 +13935,7 @@ which-typed-array@^1.1.9: has-tostringtag "^1.0.0" is-typed-array "^1.1.10" -which@^1.2.1, which@^1.2.9: +which@^1.2.9: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -15627,15 +14053,6 @@ workerpool@6.2.1: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" @@ -15667,16 +14084,6 @@ write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -15718,11 +14125,6 @@ ws@^8.14.2, ws@^8.8.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== -ws@~8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== - xml-name-validator@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-5.0.0.tgz#82be9b957f7afdacf961e5980f1bf227c0bf7673" @@ -15769,11 +14171,6 @@ xxhash-wasm@1.0.2: resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-1.0.2.tgz#ecc0f813219b727af4d5f3958ca6becee2f2f1ff" integrity sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A== -y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -15804,14 +14201,6 @@ yargs-parser@21.1.1, yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" @@ -15827,7 +14216,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0, yargs@^16.1.1, yargs@^16.2.0: +yargs@16.2.0, yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -15853,7 +14242,7 @@ yargs@17.7.1, yargs@^17.5.1, yargs@^17.6.2, yargs@^17.7.1: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@17.7.2, yargs@^17.7.2: +yargs@17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -15866,23 +14255,6 @@ yargs@17.7.2, yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^15.0.2: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - yargs@^17.1.1: version "17.6.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.6.2.tgz#2e23f2944e976339a1ee00f18c77fedee8332541" From b93cfb907facb14a890cf73988a652907d91bd38 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 22 Jan 2024 19:36:30 +0100 Subject: [PATCH 54/70] chore: extend chiado config from gnosis config (#6329) --- .../config/src/chainConfig/networks/chiado.ts | 19 ++++++------------- .../config/src/chainConfig/networks/gnosis.ts | 8 +++++--- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/packages/config/src/chainConfig/networks/chiado.ts b/packages/config/src/chainConfig/networks/chiado.ts index 284071f25bf8..0b7af5eaefec 100644 --- a/packages/config/src/chainConfig/networks/chiado.ts +++ b/packages/config/src/chainConfig/networks/chiado.ts @@ -1,32 +1,23 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; -import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {gnosisChainConfig as gnosis} from "./gnosis.js"; export const chiadoChainConfig: ChainConfig = { - ...mainnet, + ...gnosis, // NOTE: Only add diff values - PRESET_BASE: PresetName.gnosis, CONFIG_NAME: "chiado", // Transition TERMINAL_TOTAL_DIFFICULTY: BigInt("231707791542740786049188744689299064356246512"), - TERMINAL_BLOCK_HASH: b("0x0000000000000000000000000000000000000000000000000000000000000000"), - TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: Infinity, - SECONDS_PER_SLOT: 5, - SECONDS_PER_ETH1_BLOCK: 6, - ETH1_FOLLOW_DISTANCE: 1024, - CHURN_LIMIT_QUOTIENT: 4096, - - // Ethereum Goerli testnet + // Deposit contract DEPOSIT_CHAIN_ID: 10200, DEPOSIT_NETWORK_ID: 10200, DEPOSIT_CONTRACT_ADDRESS: b("0xb97036A26259B7147018913bD58a774cf91acf25"), - // Dec 8, 2021, 13:00 UTC + // 10 October 2022 10:00:00 GMT+0000 MIN_GENESIS_TIME: 1665396000, MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 6000, GENESIS_FORK_VERSION: b("0x0000006f"), @@ -41,4 +32,6 @@ export const chiadoChainConfig: ChainConfig = { // Capella CAPELLA_FORK_VERSION: b("0x0300006f"), CAPELLA_FORK_EPOCH: 244224, // Wed May 24 2023 13:12:00 GMT+0000 + // Deneb + DENEB_FORK_VERSION: b("0x0400006f"), }; diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index c952352f8438..22c038ba747a 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -13,15 +13,14 @@ export const gnosisChainConfig: ChainConfig = { // Transition TERMINAL_TOTAL_DIFFICULTY: BigInt("8626000000000000000000058750000000000000000000"), - TERMINAL_BLOCK_HASH: b("0x0000000000000000000000000000000000000000000000000000000000000000"), - TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH: Infinity, + // Time parameters SECONDS_PER_SLOT: 5, SECONDS_PER_ETH1_BLOCK: 6, ETH1_FOLLOW_DISTANCE: 1024, CHURN_LIMIT_QUOTIENT: 4096, - // Ethereum Goerli testnet + // Deposit contract DEPOSIT_CHAIN_ID: 100, DEPOSIT_NETWORK_ID: 100, DEPOSIT_CONTRACT_ADDRESS: b("0x0b98057ea310f4d31f2a452b414647007d1645d9"), @@ -41,4 +40,7 @@ export const gnosisChainConfig: ChainConfig = { // Capella CAPELLA_FORK_VERSION: b("0x03000064"), CAPELLA_FORK_EPOCH: 648704, // 2023-08-01T11:34:20.000Z + // Deneb + DENEB_FORK_VERSION: b("0x04000064"), + DENEB_FORK_EPOCH: Infinity, }; From 4e49dbca4c6b2f8b2138a66bbb1e8c23a925bf8c Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 22 Jan 2024 19:41:58 +0100 Subject: [PATCH 55/70] fix: improve handling of non-integer builder boost factor values (#6332) --- .../validator-management/vc-configuration.md | 2 +- packages/cli/src/cmds/validator/handler.ts | 16 +++++++++++++--- packages/cli/src/cmds/validator/options.ts | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/docs/pages/validator-management/vc-configuration.md b/docs/pages/validator-management/vc-configuration.md index cf8f3acae060..a1077997cd77 100644 --- a/docs/pages/validator-management/vc-configuration.md +++ b/docs/pages/validator-management/vc-configuration.md @@ -103,7 +103,7 @@ With Lodestar's `--builder.selection` validator options, you can select: #### Calculating builder boost factor with examples -To calculate the builder boost factor setting, you need to know what percentage you will accept a builder block for against a local execution block using the following formula: `100*100/(100+percentage)`. +To calculate the builder boost factor setting, you need to know what percentage you will accept a builder block for against a local execution block using the following formula: `100*100/(100+percentage)`. The value passed to `--builder.boostFactor` must be a valid number without decimals. Example 1: I will only accept a builder block with 25% more value than the local execution block. ``` diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 5eca9bc741d9..91789c99ee3b 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -227,7 +227,7 @@ function getProposerConfigFromArgs( selection: parseBuilderSelection( args["builder.selection"] ?? (args["builder"] ? defaultOptions.builderAliasSelection : undefined) ), - boostFactor: args["builder.boostFactor"] !== undefined ? BigInt(args["builder.boostFactor"]) : undefined, + boostFactor: parseBuilderBoostFactor(args["builder.boostFactor"]), }, }; @@ -266,7 +266,7 @@ function parseBuilderSelection(builderSelection?: string): routes.validator.Buil case "executiononly": break; default: - throw Error("Invalid input for builder selection, check help."); + throw new YargsError("Invalid input for builder selection, check help"); } } return builderSelection as routes.validator.BuilderSelection; @@ -280,9 +280,19 @@ function parseBroadcastValidation(broadcastValidation?: string): routes.beacon.B case "consensus_and_equivocation": break; default: - throw Error("Invalid input for broadcastValidation, check help"); + throw new YargsError("Invalid input for broadcastValidation, check help"); } } return broadcastValidation as routes.beacon.BroadcastValidation; } + +function parseBuilderBoostFactor(boostFactor?: string): bigint | undefined { + if (boostFactor === undefined) return; + + if (!/^\d+$/.test(boostFactor)) { + throw new YargsError("Invalid input for builder boost factor, must be a valid number without decimals"); + } + + return BigInt(boostFactor); +} diff --git a/packages/cli/src/cmds/validator/options.ts b/packages/cli/src/cmds/validator/options.ts index cddb34981ce1..ecc8ad32ca87 100644 --- a/packages/cli/src/cmds/validator/options.ts +++ b/packages/cli/src/cmds/validator/options.ts @@ -45,7 +45,7 @@ export type IValidatorCliArgs = AccountValidatorArgs & builder?: boolean; "builder.selection"?: string; - "builder.boostFactor"?: bigint; + "builder.boostFactor"?: string; useProduceBlockV3?: boolean; broadcastValidation?: string; From 1f38b1b96cb2aa6e942aae506d818f054bb8480f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 13:44:16 -0500 Subject: [PATCH 56/70] chore(deps): bump vite from 5.0.6 to 5.0.12 (#6331) Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 5.0.6 to 5.0.12. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/v5.0.12/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v5.0.12/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index c39d68175f13..27754c484466 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13510,9 +13510,9 @@ vite-plugin-top-level-await@^1.4.1: uuid "^9.0.1" vite@^5.0.0: - version "5.0.6" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.6.tgz#f9e13503a4c5ccd67312c67803dec921f3bdea7c" - integrity sha512-MD3joyAEBtV7QZPl2JVVUai6zHms3YOmLR+BpMzLlX2Yzjfcc4gTgNi09d/Rua3F4EtC8zdwPU8eQYyib4vVMQ== + version "5.0.12" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.12.tgz#8a2ffd4da36c132aec4adafe05d7adde38333c47" + integrity sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w== dependencies: esbuild "^0.19.3" postcss "^8.4.32" From 9b44056293e6e896a9ee8c297a9c3c97a1c5d88f Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 23 Jan 2024 08:25:12 +0100 Subject: [PATCH 57/70] feat: update configs to be able to support Deneb on all networks (#6328) * Move `MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS` from constants to config * Align structure / comments with consensus spec * Add references to preset / config files * Rename directory and files that contain config values * Add comment to networking params --- .../src/chain/archiver/archiveBlocks.ts | 4 ++-- packages/beacon-node/src/chain/blocks/types.ts | 4 ++-- .../reqresp/beaconBlocksMaybeBlobsByRange.ts | 4 ++-- .../network/gossip/scoringParameters.test.ts | 2 +- packages/cli/src/networks/dev.ts | 2 +- packages/config/package.json | 4 ++-- .../{presets => configs}/mainnet.ts | 18 +++++++++++++++++- .../{presets => configs}/minimal.ts | 15 +++++++++++++++ packages/config/src/chainConfig/default.ts | 4 ++-- .../config/src/chainConfig/networks/chiado.ts | 3 +++ .../src/chainConfig/networks/ephemery.ts | 2 +- .../config/src/chainConfig/networks/gnosis.ts | 5 ++++- .../config/src/chainConfig/networks/goerli.ts | 5 ++++- .../config/src/chainConfig/networks/holesky.ts | 2 +- .../config/src/chainConfig/networks/mainnet.ts | 2 +- .../config/src/chainConfig/networks/ropsten.ts | 2 +- .../config/src/chainConfig/networks/sepolia.ts | 4 ++-- packages/config/src/chainConfig/types.ts | 10 ++++++++-- packages/config/src/configs.ts | 4 ++++ packages/config/src/presets.ts | 4 ---- packages/params/src/index.ts | 1 - packages/params/src/presets/gnosis.ts | 3 +++ packages/params/src/presets/mainnet.ts | 4 +++- packages/params/src/presets/minimal.ts | 10 +++------- packages/validator/src/util/params.ts | 5 ++++- 25 files changed, 86 insertions(+), 37 deletions(-) rename packages/config/src/chainConfig/{presets => configs}/mainnet.ts (86%) rename packages/config/src/chainConfig/{presets => configs}/minimal.ts (88%) create mode 100644 packages/config/src/configs.ts delete mode 100644 packages/config/src/presets.ts diff --git a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts index c88aa6cbf5ed..27934a6bae1f 100644 --- a/packages/beacon-node/src/chain/archiver/archiveBlocks.ts +++ b/packages/beacon-node/src/chain/archiver/archiveBlocks.ts @@ -2,7 +2,7 @@ import {fromHexString} from "@chainsafe/ssz"; import {Epoch, Slot, RootHex} from "@lodestar/types"; import {IForkChoice} from "@lodestar/fork-choice"; import {Logger, toHex} from "@lodestar/utils"; -import {ForkSeq, SLOTS_PER_EPOCH, MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS} from "@lodestar/params"; +import {ForkSeq, SLOTS_PER_EPOCH} from "@lodestar/params"; import {computeEpochAtSlot, computeStartSlotAtEpoch} from "@lodestar/state-transition"; import {KeyValue} from "@lodestar/db"; import {ChainForkConfig} from "@lodestar/config"; @@ -83,7 +83,7 @@ export async function archiveBlocks( // Delete expired blobs // Keep only `[max(GENESIS_EPOCH, current_epoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS), current_epoch]` if (finalizedPostDeneb) { - const blobSidecarsMinEpoch = currentEpoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS; + const blobSidecarsMinEpoch = currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS; if (blobSidecarsMinEpoch >= config.DENEB_FORK_EPOCH) { const slotsToDelete = await db.blobSidecarsArchive.keys({lt: computeStartSlotAtEpoch(blobSidecarsMinEpoch)}); if (slotsToDelete.length > 0) { diff --git a/packages/beacon-node/src/chain/blocks/types.ts b/packages/beacon-node/src/chain/blocks/types.ts index aff5a64c9929..2fd16fa64705 100644 --- a/packages/beacon-node/src/chain/blocks/types.ts +++ b/packages/beacon-node/src/chain/blocks/types.ts @@ -1,7 +1,7 @@ import {CachedBeaconStateAllForks, computeEpochAtSlot, DataAvailableStatus} from "@lodestar/state-transition"; import {MaybeValidExecutionStatus} from "@lodestar/fork-choice"; import {allForks, deneb, Slot} from "@lodestar/types"; -import {ForkSeq, MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS} from "@lodestar/params"; +import {ForkSeq} from "@lodestar/params"; import {ChainForkConfig} from "@lodestar/config"; export enum BlockInputType { @@ -36,7 +36,7 @@ export function blockRequiresBlobs(config: ChainForkConfig, blockSlot: Slot, clo return ( config.getForkSeq(blockSlot) >= ForkSeq.deneb && // Only request blobs if they are recent enough - computeEpochAtSlot(blockSlot) >= computeEpochAtSlot(clockSlot) - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS + computeEpochAtSlot(blockSlot) >= computeEpochAtSlot(clockSlot) - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS ); } diff --git a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts index 41d3e901c41d..e57c3e5b7c8e 100644 --- a/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts +++ b/packages/beacon-node/src/network/reqresp/beaconBlocksMaybeBlobsByRange.ts @@ -1,6 +1,6 @@ import {ChainForkConfig} from "@lodestar/config"; import {deneb, Epoch, phase0, allForks, Slot} from "@lodestar/types"; -import {ForkSeq, MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS} from "@lodestar/params"; +import {ForkSeq} from "@lodestar/params"; import {computeEpochAtSlot} from "@lodestar/state-transition"; import {BlockInput, BlockSource, getBlockInput} from "../../chain/blocks/types.js"; @@ -37,7 +37,7 @@ export async function beaconBlocksMaybeBlobsByRange( } // Only request blobs if they are recent enough - else if (computeEpochAtSlot(startSlot) >= currentEpoch - MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { + else if (computeEpochAtSlot(startSlot) >= currentEpoch - config.MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS) { const [allBlocks, allBlobSidecars] = await Promise.all([ network.sendBeaconBlocksByRange(peerId, request), network.sendBlobSidecarsByRange(peerId, request), diff --git a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts index 6805f00ced1b..7ef09af2cd89 100644 --- a/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts +++ b/packages/beacon-node/test/unit-mainnet/network/gossip/scoringParameters.test.ts @@ -2,7 +2,7 @@ import {describe, it, expect} from "vitest"; import {TopicScoreParams} from "@chainsafe/libp2p-gossipsub/score"; import {ATTESTATION_SUBNET_COUNT, ForkName, SLOTS_PER_EPOCH} from "@lodestar/params"; import {createBeaconConfig} from "@lodestar/config"; -import {mainnetChainConfig} from "@lodestar/config/presets"; +import {mainnetChainConfig} from "@lodestar/config/configs"; import {computeGossipPeerScoreParams, gossipScoreThresholds} from "../../../../src/network/gossip/scoringParameters.js"; import {stringifyGossipTopic} from "../../../../src/network/gossip/topic.js"; import {GossipType} from "../../../../src/network/index.js"; diff --git a/packages/cli/src/networks/dev.ts b/packages/cli/src/networks/dev.ts index 77d55bc6a32d..ff8afc127dcc 100644 --- a/packages/cli/src/networks/dev.ts +++ b/packages/cli/src/networks/dev.ts @@ -1,5 +1,5 @@ import {gnosisChainConfig} from "@lodestar/config/networks"; -import {minimalChainConfig, mainnetChainConfig} from "@lodestar/config/presets"; +import {minimalChainConfig, mainnetChainConfig} from "@lodestar/config/configs"; import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; let chainConfig; diff --git a/packages/config/package.json b/packages/config/package.json index c52a070b69fd..3b0a649e78c5 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -19,8 +19,8 @@ "./networks": { "import": "./lib/networks.js" }, - "./presets": { - "import": "./lib/presets.js" + "./configs": { + "import": "./lib/configs.js" } }, "typesVersions": { diff --git a/packages/config/src/chainConfig/presets/mainnet.ts b/packages/config/src/chainConfig/configs/mainnet.ts similarity index 86% rename from packages/config/src/chainConfig/presets/mainnet.ts rename to packages/config/src/chainConfig/configs/mainnet.ts index 2c02643a032c..f9c17ce1cb8e 100644 --- a/packages/config/src/chainConfig/presets/mainnet.ts +++ b/packages/config/src/chainConfig/configs/mainnet.ts @@ -3,7 +3,11 @@ import {fromHexString as b} from "@chainsafe/ssz"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; +// Mainnet config +// https://github.com/ethereum/consensus-specs/blob/dev/configs/mainnet.yaml + export const chainConfig: ChainConfig = { + // Extends the mainnet preset PRESET_BASE: PresetName.mainnet, CONFIG_NAME: "mainnet", @@ -41,7 +45,7 @@ export const chainConfig: ChainConfig = { CAPELLA_FORK_VERSION: b("0x03000000"), CAPELLA_FORK_EPOCH: 194048, // April 12 (epoch: 194048 slot: 6209536 UTC: 4/12/2023, 10:27:35 PM) - // DENEB + // Deneb DENEB_FORK_VERSION: b("0x04000000"), DENEB_FORK_EPOCH: Infinity, @@ -68,9 +72,14 @@ export const chainConfig: ChainConfig = { EJECTION_BALANCE: 16000000000, // 2**2 (= 4) MIN_PER_EPOCH_CHURN_LIMIT: 4, + // 2**3 (= 8) MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8, // 2**16 (= 65,536) CHURN_LIMIT_QUOTIENT: 65536, + + // Fork choice + // --------------------------------------------------------------- + // 40% PROPOSER_SCORE_BOOST: 40, // Deposit contract @@ -79,4 +88,11 @@ export const chainConfig: ChainConfig = { DEPOSIT_CHAIN_ID: 1, DEPOSIT_NETWORK_ID: 1, DEPOSIT_CONTRACT_ADDRESS: b("0x00000000219ab540356cBB839Cbe05303d7705Fa"), + + // Networking + // --------------------------------------------------------------- + + // Deneb + // `2**12` (= 4096 epochs, ~18 days) + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, }; diff --git a/packages/config/src/chainConfig/presets/minimal.ts b/packages/config/src/chainConfig/configs/minimal.ts similarity index 88% rename from packages/config/src/chainConfig/presets/minimal.ts rename to packages/config/src/chainConfig/configs/minimal.ts index d790032bcee1..6c0a13d8abb2 100644 --- a/packages/config/src/chainConfig/presets/minimal.ts +++ b/packages/config/src/chainConfig/configs/minimal.ts @@ -3,6 +3,9 @@ import {fromHexString as b} from "@chainsafe/ssz"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; +// Minimal config +// https://github.com/ethereum/consensus-specs/blob/dev/configs/minimal.yaml + export const chainConfig: ChainConfig = { // Extends the minimal preset PRESET_BASE: PresetName.minimal, @@ -66,9 +69,14 @@ export const chainConfig: ChainConfig = { EJECTION_BALANCE: 16000000000, // 2**2 (= 4) MIN_PER_EPOCH_CHURN_LIMIT: 2, + // [customized] MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4, // [customized] scale queue churn at much lower validator counts for testing CHURN_LIMIT_QUOTIENT: 32, + + // Fork choice + // --------------------------------------------------------------- + // 40% PROPOSER_SCORE_BOOST: 40, // Deposit contract @@ -78,4 +86,11 @@ export const chainConfig: ChainConfig = { DEPOSIT_NETWORK_ID: 5, // Configured on a per testnet basis DEPOSIT_CONTRACT_ADDRESS: b("0x1234567890123456789012345678901234567890"), + + // Networking + // --------------------------------------------------------------- + + // Deneb + // `2**12` (= 4096 epochs, ~18 days) + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 4096, }; diff --git a/packages/config/src/chainConfig/default.ts b/packages/config/src/chainConfig/default.ts index 368f2afd067d..d778c9b82447 100644 --- a/packages/config/src/chainConfig/default.ts +++ b/packages/config/src/chainConfig/default.ts @@ -1,7 +1,7 @@ import {ACTIVE_PRESET, PresetName} from "@lodestar/params"; import {ChainConfig} from "./types.js"; -import {chainConfig as mainnet} from "./presets/mainnet.js"; -import {chainConfig as minimal} from "./presets/minimal.js"; +import {chainConfig as mainnet} from "./configs/mainnet.js"; +import {chainConfig as minimal} from "./configs/minimal.js"; let defaultChainConfig: ChainConfig; diff --git a/packages/config/src/chainConfig/networks/chiado.ts b/packages/config/src/chainConfig/networks/chiado.ts index 0b7af5eaefec..01739cf1d4eb 100644 --- a/packages/config/src/chainConfig/networks/chiado.ts +++ b/packages/config/src/chainConfig/networks/chiado.ts @@ -3,6 +3,9 @@ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; import {gnosisChainConfig as gnosis} from "./gnosis.js"; +// Chiado beacon chain config: +// https://github.com/gnosischain/configs/blob/main/chiado/config.yaml + export const chiadoChainConfig: ChainConfig = { ...gnosis, diff --git a/packages/config/src/chainConfig/networks/ephemery.ts b/packages/config/src/chainConfig/networks/ephemery.ts index 5557767550bb..29e3f7b92d01 100644 --- a/packages/config/src/chainConfig/networks/ephemery.ts +++ b/packages/config/src/chainConfig/networks/ephemery.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; // Ephemery dynamic beacon chain config: // https://github.com/ephemery-testnet/ephemery-genesis/blob/master/cl-config.yaml diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index 22c038ba747a..6f3ccfed39e6 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -2,7 +2,10 @@ import {fromHexString as b} from "@chainsafe/ssz"; import {PresetName} from "@lodestar/params"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; + +// Gnosis beacon chain config: +// https://github.com/gnosischain/configs/blob/main/mainnet/config.yaml export const gnosisChainConfig: ChainConfig = { ...mainnet, diff --git a/packages/config/src/chainConfig/networks/goerli.ts b/packages/config/src/chainConfig/networks/goerli.ts index f1fc0ab2418c..b90f79f4e272 100644 --- a/packages/config/src/chainConfig/networks/goerli.ts +++ b/packages/config/src/chainConfig/networks/goerli.ts @@ -1,7 +1,10 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; + +// Goerli beacon chain config: +// https://github.com/eth-clients/goerli/blob/main/prater/config.yaml export const goerliChainConfig: ChainConfig = { ...mainnet, diff --git a/packages/config/src/chainConfig/networks/holesky.ts b/packages/config/src/chainConfig/networks/holesky.ts index e255369ccbaa..3115caf1ab76 100644 --- a/packages/config/src/chainConfig/networks/holesky.ts +++ b/packages/config/src/chainConfig/networks/holesky.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; // Holesky beacon chain config: // https://github.com/eth-clients/holesky/blob/main/custom_config_data/config.yaml diff --git a/packages/config/src/chainConfig/networks/mainnet.ts b/packages/config/src/chainConfig/networks/mainnet.ts index 1ae9858523e2..24584ad8442b 100644 --- a/packages/config/src/chainConfig/networks/mainnet.ts +++ b/packages/config/src/chainConfig/networks/mainnet.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; export const mainnetChainConfig: ChainConfig = { ...mainnet, diff --git a/packages/config/src/chainConfig/networks/ropsten.ts b/packages/config/src/chainConfig/networks/ropsten.ts index a94419c9140b..6bb7811ccba3 100644 --- a/packages/config/src/chainConfig/networks/ropsten.ts +++ b/packages/config/src/chainConfig/networks/ropsten.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; // Ropsten beacon chain config: // https://github.com/eth-clients/merge-testnets/blob/main/ropsten-beacon-chain/config.yaml diff --git a/packages/config/src/chainConfig/networks/sepolia.ts b/packages/config/src/chainConfig/networks/sepolia.ts index c81fda37b4c6..a3598299e294 100644 --- a/packages/config/src/chainConfig/networks/sepolia.ts +++ b/packages/config/src/chainConfig/networks/sepolia.ts @@ -1,10 +1,10 @@ /* eslint-disable @typescript-eslint/naming-convention */ import {fromHexString as b} from "@chainsafe/ssz"; import {ChainConfig} from "../types.js"; -import {chainConfig as mainnet} from "../presets/mainnet.js"; +import {chainConfig as mainnet} from "../configs/mainnet.js"; // Sepolia beacon chain config: -// https://github.com/eth-clients/merge-testnets/blob/main/sepolia-beacon-chain/config.yaml +// https://github.com/eth-clients/sepolia/blob/main/bepolia/config.yaml export const sepoliaChainConfig: ChainConfig = { ...mainnet, diff --git a/packages/config/src/chainConfig/types.ts b/packages/config/src/chainConfig/types.ts index 4818ef9ee0aa..20e8119332f3 100644 --- a/packages/config/src/chainConfig/types.ts +++ b/packages/config/src/chainConfig/types.ts @@ -56,13 +56,16 @@ export type ChainConfig = { MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: number; CHURN_LIMIT_QUOTIENT: number; - // Proposer boost + // Fork choice PROPOSER_SCORE_BOOST: number; // Deposit contract DEPOSIT_CHAIN_ID: number; DEPOSIT_NETWORK_ID: number; DEPOSIT_CONTRACT_ADDRESS: Uint8Array; + + // Networking + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: number; }; export const chainConfigTypes: SpecTypes = { @@ -109,13 +112,16 @@ export const chainConfigTypes: SpecTypes = { MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: "number", CHURN_LIMIT_QUOTIENT: "number", - // Proposer boost + // Fork choice PROPOSER_SCORE_BOOST: "number", // Deposit contract DEPOSIT_CHAIN_ID: "number", DEPOSIT_NETWORK_ID: "number", DEPOSIT_CONTRACT_ADDRESS: "bytes", + + // Networking + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: "number", }; /** Allows values in a Spec file */ diff --git a/packages/config/src/configs.ts b/packages/config/src/configs.ts new file mode 100644 index 000000000000..9aded2b5190b --- /dev/null +++ b/packages/config/src/configs.ts @@ -0,0 +1,4 @@ +import {chainConfig as mainnetChainConfig} from "./chainConfig/configs/mainnet.js"; +import {chainConfig as minimalChainConfig} from "./chainConfig/configs/minimal.js"; + +export {mainnetChainConfig, minimalChainConfig}; diff --git a/packages/config/src/presets.ts b/packages/config/src/presets.ts deleted file mode 100644 index 542c01ece33d..000000000000 --- a/packages/config/src/presets.ts +++ /dev/null @@ -1,4 +0,0 @@ -import {chainConfig as mainnetChainConfig} from "./chainConfig/presets/mainnet.js"; -import {chainConfig as minimalChainConfig} from "./chainConfig/presets/minimal.js"; - -export {mainnetChainConfig, minimalChainConfig}; diff --git a/packages/params/src/index.ts b/packages/params/src/index.ts index e0623537d7f0..d111d090b8c3 100644 --- a/packages/params/src/index.ts +++ b/packages/params/src/index.ts @@ -179,7 +179,6 @@ export const SYNC_COMMITTEE_SUBNET_SIZE = Math.floor(SYNC_COMMITTEE_SIZE / SYNC_ export const MAX_REQUEST_BLOCKS = 2 ** 10; // 1024 export const MAX_REQUEST_BLOCKS_DENEB = 2 ** 7; // 128 export const MAX_REQUEST_BLOB_SIDECARS = MAX_REQUEST_BLOCKS_DENEB * MAX_BLOBS_PER_BLOCK; -export const MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS = 2 ** 12; // 4096 epochs, ~18 days // Lightclient pre-computed /** diff --git a/packages/params/src/presets/gnosis.ts b/packages/params/src/presets/gnosis.ts index 2356e7d3d69e..412c38a6eb82 100644 --- a/packages/params/src/presets/gnosis.ts +++ b/packages/params/src/presets/gnosis.ts @@ -1,6 +1,9 @@ import {BeaconPreset} from "../types.js"; import {mainnetPreset} from "./mainnet.js"; +// Gnosis preset +// https://github.com/gnosischain/specs/tree/master/consensus/preset/gnosis + /* eslint-disable @typescript-eslint/naming-convention */ export const gnosisPreset: BeaconPreset = { ...mainnetPreset, diff --git a/packages/params/src/presets/mainnet.ts b/packages/params/src/presets/mainnet.ts index 9b591103edf5..42a705a07f03 100644 --- a/packages/params/src/presets/mainnet.ts +++ b/packages/params/src/presets/mainnet.ts @@ -1,5 +1,8 @@ import {BeaconPreset} from "../types.js"; +// Mainnet preset +// https://github.com/ethereum/consensus-specs/tree/dev/presets/mainnet + /* eslint-disable @typescript-eslint/naming-convention */ export const mainnetPreset: BeaconPreset = { // Misc @@ -111,7 +114,6 @@ export const mainnetPreset: BeaconPreset = { // DENEB /////////// - // https://github.com/ethereum/consensus-specs/blob/dev/presets/mainnet/eip4844.yaml FIELD_ELEMENTS_PER_BLOB: 4096, MAX_BLOB_COMMITMENTS_PER_BLOCK: 4096, MAX_BLOBS_PER_BLOCK: 6, diff --git a/packages/params/src/presets/minimal.ts b/packages/params/src/presets/minimal.ts index ad86cbf89e61..b940841a0429 100644 --- a/packages/params/src/presets/minimal.ts +++ b/packages/params/src/presets/minimal.ts @@ -1,5 +1,8 @@ import {BeaconPreset} from "../types.js"; +// Minimal preset +// https://github.com/ethereum/consensus-specs/tree/dev/presets/minimal + /* eslint-disable @typescript-eslint/naming-convention */ export const minimalPreset: BeaconPreset = { // Misc @@ -42,12 +45,6 @@ export const minimalPreset: BeaconPreset = { EPOCHS_PER_ETH1_VOTING_PERIOD: 4, // [customized] smaller state SLOTS_PER_HISTORICAL_ROOT: 64, - /* - // 2**8 (= 256) epochs - MIN_VALIDATOR_WITHDRAWABILITY_DELAY: 256, - // [customized] higher frequency of committee turnover and faster time to acceptable voluntary exit - SHARD_COMMITTEE_PERIOD: 64, - */ // 2**2 (= 4) epochs MIN_EPOCHS_TO_INACTIVITY_PENALTY: 4, @@ -118,7 +115,6 @@ export const minimalPreset: BeaconPreset = { // DENEB /////////// - // https://github.com/ethereum/consensus-specs/blob/dev/presets/minimal/eip4844.yaml FIELD_ELEMENTS_PER_BLOB: 4096, MAX_BLOB_COMMITMENTS_PER_BLOCK: 16, MAX_BLOBS_PER_BLOCK: 6, diff --git a/packages/validator/src/util/params.ts b/packages/validator/src/util/params.ts index 1431f4f3c56e..006ae3fadbbb 100644 --- a/packages/validator/src/util/params.ts +++ b/packages/validator/src/util/params.ts @@ -121,7 +121,7 @@ function getSpecCriticalParams(localConfig: ChainConfig): Record Date: Tue, 23 Jan 2024 15:04:35 +0100 Subject: [PATCH 58/70] feat: schedule deneb on chiado (#6342) --- packages/config/src/chainConfig/networks/chiado.ts | 1 + packages/config/src/chainConfig/networks/gnosis.ts | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/packages/config/src/chainConfig/networks/chiado.ts b/packages/config/src/chainConfig/networks/chiado.ts index 01739cf1d4eb..43b13a210dac 100644 --- a/packages/config/src/chainConfig/networks/chiado.ts +++ b/packages/config/src/chainConfig/networks/chiado.ts @@ -37,4 +37,5 @@ export const chiadoChainConfig: ChainConfig = { CAPELLA_FORK_EPOCH: 244224, // Wed May 24 2023 13:12:00 GMT+0000 // Deneb DENEB_FORK_VERSION: b("0x0400006f"), + DENEB_FORK_EPOCH: 516608, // Wed Jan 31 2024 18:15:40 GMT+0000 }; diff --git a/packages/config/src/chainConfig/networks/gnosis.ts b/packages/config/src/chainConfig/networks/gnosis.ts index 6f3ccfed39e6..7bafaa0225b1 100644 --- a/packages/config/src/chainConfig/networks/gnosis.ts +++ b/packages/config/src/chainConfig/networks/gnosis.ts @@ -23,11 +23,17 @@ export const gnosisChainConfig: ChainConfig = { ETH1_FOLLOW_DISTANCE: 1024, CHURN_LIMIT_QUOTIENT: 4096, + // Validator cycle + MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 2, + // Deposit contract DEPOSIT_CHAIN_ID: 100, DEPOSIT_NETWORK_ID: 100, DEPOSIT_CONTRACT_ADDRESS: b("0x0b98057ea310f4d31f2a452b414647007d1645d9"), + // Networking + MIN_EPOCHS_FOR_BLOB_SIDECARS_REQUESTS: 16384, + // Dec 8, 2021, 13:00 UTC MIN_GENESIS_TIME: 1638968400, MIN_GENESIS_ACTIVE_VALIDATOR_COUNT: 4096, From 43994ba8ef665c98d7ec6dcbb5338ebf5906f249 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Tue, 23 Jan 2024 17:05:04 +0100 Subject: [PATCH 59/70] fix: update beacon max-old-space-size to 8192 (#6343) * feat: increase default memory limit to 8GB * Revise comments --- Dockerfile | 6 +++--- docker-compose.yml | 6 +++--- docs/pages/tools/flamegraphs.md | 2 +- lodestar | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 5a9541e06f1a..a9e597c2fb9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,9 +39,9 @@ FROM node:20-alpine WORKDIR /usr/app COPY --from=build_deps /usr/app . -# NodeJS applications have a default memory limit of 2.5GB. -# This limit is bit tight for a Prater node, it is recommended to raise the limit +# NodeJS applications have a default memory limit of 4GB on most machines. +# This limit is bit tight for a Mainnet node, it is recommended to raise the limit # since memory may spike during certain network conditions. -ENV NODE_OPTIONS=--max-old-space-size=4096 +ENV NODE_OPTIONS=--max-old-space-size=8192 ENTRYPOINT ["node", "./packages/cli/bin/lodestar"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index cab1245d351e..d8c6122e3537 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,11 +11,11 @@ services: - "9000:9000" # P2P port # - "9596:9596" # REST API port command: beacon --dataDir /data --rest --rest.address 0.0.0.0 --metrics --logFile /logs/beacon.log --logFileLevel debug --logFileDailyRotate 5 - # NodeJS applications have a default memory limit of 2.5GB. - # This limit is bit tight for a Prater node, it is recommended to raise the limit + # NodeJS applications have a default memory limit of 4GB on most machines. + # This limit is bit tight for a Mainnet node, it is recommended to raise the limit # since memory may spike during certain network conditions. environment: - NODE_OPTIONS: --max-old-space-size=4096 + NODE_OPTIONS: --max-old-space-size=8192 prometheus: build: docker/prometheus diff --git a/docs/pages/tools/flamegraphs.md b/docs/pages/tools/flamegraphs.md index d6f45303a9aa..119cc7dc10e5 100644 --- a/docs/pages/tools/flamegraphs.md +++ b/docs/pages/tools/flamegraphs.md @@ -18,7 +18,7 @@ Next we need to update the Lodestar service by modifying the start script. We ne ```sh node \ --perf-basic-prof \ - --max-old-space-size=4096 \ + --max-old-space-size=8192 \ /usr/src/lodestar/packages/cli/bin/lodestar \ beacon \ --rcConfig /home/devops/beacon/rcconfig.yml diff --git a/lodestar b/lodestar index 2101d94b77cb..0b20ba4c9bcd 100755 --- a/lodestar +++ b/lodestar @@ -2,6 +2,6 @@ # Convenience script to run the lodestar binary from built source # -# ./lodestar.sh beacon --network prater +# ./lodestar.sh beacon --network mainnet -node --trace-deprecation --max-old-space-size=4096 ./packages/cli/bin/lodestar.js "$@" \ No newline at end of file +node --trace-deprecation --max-old-space-size=8192 ./packages/cli/bin/lodestar.js "$@" \ No newline at end of file From 92ed3479a6ac59b75d100b9738ee437b2e80a748 Mon Sep 17 00:00:00 2001 From: Phil Ngo Date: Tue, 23 Jan 2024 11:06:39 -0500 Subject: [PATCH 60/70] v1.15.0 --- lerna.json | 2 +- packages/api/package.json | 10 +++++----- packages/beacon-node/package.json | 26 +++++++++++++------------- packages/cli/package.json | 26 +++++++++++++------------- packages/config/package.json | 6 +++--- packages/db/package.json | 8 ++++---- packages/flare/package.json | 14 +++++++------- packages/fork-choice/package.json | 12 ++++++------ packages/light-client/package.json | 14 +++++++------- packages/logger/package.json | 6 +++--- packages/params/package.json | 2 +- packages/prover/package.json | 18 +++++++++--------- packages/reqresp/package.json | 12 ++++++------ packages/spec-test-util/package.json | 8 ++++---- packages/state-transition/package.json | 10 +++++----- packages/test-utils/package.json | 6 +++--- packages/types/package.json | 4 ++-- packages/utils/package.json | 2 +- packages/validator/package.json | 18 +++++++++--------- 19 files changed, 102 insertions(+), 102 deletions(-) diff --git a/lerna.json b/lerna.json index 487caa95b0a2..2a9439d49715 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useNx": true, - "version": "1.14.0", + "version": "1.15.0", "stream": true, "command": { "version": { diff --git a/packages/api/package.json b/packages/api/package.json index e1a52c47b489..533961953b9a 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -71,10 +71,10 @@ "dependencies": { "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "eventsource": "^2.0.2", "qs": "^6.11.1" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 3ddde8540670..8ce625fb0d54 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -121,18 +121,18 @@ "@libp2p/peer-id-factory": "^4.0.3", "@libp2p/prometheus-metrics": "^3.0.10", "@libp2p/tcp": "9.0.10", - "@lodestar/api": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/db": "^1.14.0", - "@lodestar/fork-choice": "^1.14.0", - "@lodestar/light-client": "^1.14.0", - "@lodestar/logger": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/reqresp": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", - "@lodestar/validator": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/db": "^1.15.0", + "@lodestar/fork-choice": "^1.15.0", + "@lodestar/light-client": "^1.15.0", + "@lodestar/logger": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/reqresp": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", + "@lodestar/validator": "^1.15.0", "@multiformats/multiaddr": "^12.1.3", "@types/datastore-level": "^3.0.0", "buffer-xor": "^2.0.2", diff --git a/packages/cli/package.json b/packages/cli/package.json index 243dee688417..616dce9d4f68 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@chainsafe/lodestar", - "version": "1.14.0", + "version": "1.15.0", "description": "Command line interface for lodestar", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -66,17 +66,17 @@ "@libp2p/crypto": "^3.0.4", "@libp2p/peer-id": "^4.0.4", "@libp2p/peer-id-factory": "^4.0.3", - "@lodestar/api": "^1.14.0", - "@lodestar/beacon-node": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/db": "^1.14.0", - "@lodestar/light-client": "^1.14.0", - "@lodestar/logger": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", - "@lodestar/validator": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/beacon-node": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/db": "^1.15.0", + "@lodestar/light-client": "^1.15.0", + "@lodestar/logger": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", + "@lodestar/validator": "^1.15.0", "@multiformats/multiaddr": "^12.1.3", "@types/lockfile": "^1.0.2", "bip39": "^3.1.0", @@ -97,7 +97,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.14.0", + "@lodestar/test-utils": "^1.15.0", "@types/debug": "^4.1.7", "@types/expand-tilde": "^2.0.0", "@types/got": "^9.6.12", diff --git a/packages/config/package.json b/packages/config/package.json index 3b0a649e78c5..a36da8c6240a 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/config", - "version": "1.14.0", + "version": "1.15.0", "description": "Chain configuration required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -65,7 +65,7 @@ ], "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/types": "^1.14.0" + "@lodestar/params": "^1.15.0", + "@lodestar/types": "^1.15.0" } } diff --git a/packages/db/package.json b/packages/db/package.json index d99b21d80b9b..f11e5b48995c 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/db", - "version": "1.14.0", + "version": "1.15.0", "description": "DB modules of Lodestar", "author": "ChainSafe Systems", "homepage": "https://github.com/ChainSafe/lodestar#readme", @@ -38,13 +38,13 @@ }, "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/config": "^1.15.0", + "@lodestar/utils": "^1.15.0", "@types/levelup": "^4.3.3", "it-all": "^3.0.4", "level": "^8.0.0" }, "devDependencies": { - "@lodestar/logger": "^1.14.0" + "@lodestar/logger": "^1.15.0" } } diff --git a/packages/flare/package.json b/packages/flare/package.json index 7417cf93c63d..93973110ab8a 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/flare", - "version": "1.14.0", + "version": "1.15.0", "description": "Beacon chain debugging tool", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,12 +60,12 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/bls-keygen": "^0.3.0", - "@lodestar/api": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "source-map-support": "^0.5.21", "yargs": "^17.7.1" }, diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 495c67a8e80b..606dec811bbc 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": "./lib/index.js", "types": "./lib/index.d.ts", @@ -39,11 +39,11 @@ }, "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0" + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0" }, "keywords": [ "ethereum", diff --git a/packages/light-client/package.json b/packages/light-client/package.json index dee231409730..456600cbd0bc 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -70,12 +70,12 @@ "@chainsafe/bls": "7.1.1", "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/api": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "mitt": "^3.0.0", "strict-event-emitter-types": "^2.0.0" }, diff --git a/packages/logger/package.json b/packages/logger/package.json index 2f450ee5be12..f1a5ddad1a06 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -66,14 +66,14 @@ }, "types": "lib/index.d.ts", "dependencies": { - "@lodestar/utils": "^1.14.0", + "@lodestar/utils": "^1.15.0", "winston": "^3.8.2", "winston-daily-rotate-file": "^4.7.1", "winston-transport": "^4.5.0" }, "devDependencies": { "@chainsafe/threads": "^1.11.1", - "@lodestar/test-utils": "^1.14.0", + "@lodestar/test-utils": "^1.15.0", "@types/triple-beam": "^1.3.2", "rimraf": "^4.4.1", "triple-beam": "^1.3.0" diff --git a/packages/params/package.json b/packages/params/package.json index 2586c73566aa..d41dae06816e 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/params", - "version": "1.14.0", + "version": "1.15.0", "description": "Chain parameters required for lodestar", "author": "ChainSafe Systems", "license": "Apache-2.0", diff --git a/packages/prover/package.json b/packages/prover/package.json index 05f7c33579b4..600f4b4d4d75 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -72,13 +72,13 @@ "@ethereumjs/tx": "^4.1.2", "@ethereumjs/util": "^8.0.6", "@ethereumjs/vm": "^6.4.2", - "@lodestar/api": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/light-client": "^1.14.0", - "@lodestar/logger": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/light-client": "^1.15.0", + "@lodestar/logger": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "ethereum-cryptography": "^1.2.0", "find-up": "^6.3.0", "http-proxy": "^1.18.1", @@ -87,7 +87,7 @@ "yargs": "^17.7.1" }, "devDependencies": { - "@lodestar/test-utils": "^1.14.0", + "@lodestar/test-utils": "^1.15.0", "@types/http-proxy": "^1.17.10", "@types/yargs": "^17.0.24", "axios": "^1.3.4", diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index c19af565c397..3856177449d3 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -56,9 +56,9 @@ "dependencies": { "@chainsafe/fast-crc32c": "^4.1.1", "@libp2p/interface": "^1.1.1", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/utils": "^1.15.0", "it-all": "^3.0.4", "it-pipe": "^3.0.1", "snappy": "^7.2.2", @@ -67,8 +67,8 @@ "uint8arraylist": "^2.4.7" }, "devDependencies": { - "@lodestar/logger": "^1.14.0", - "@lodestar/types": "^1.14.0", + "@lodestar/logger": "^1.15.0", + "@lodestar/types": "^1.15.0", "libp2p": "1.1.1" }, "peerDependencies": { diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 899d6438d939..f8d953e408fd 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/spec-test-util", - "version": "1.14.0", + "version": "1.15.0", "description": "Spec test suite generator from yaml test files", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -62,13 +62,13 @@ "blockchain" ], "dependencies": { - "@lodestar/utils": "^1.14.0", + "@lodestar/utils": "^1.15.0", "async-retry": "^1.3.3", "axios": "^1.3.4", - "vitest": "^1.2.1", "rimraf": "^4.4.1", "snappyjs": "^0.7.0", - "tar": "^6.1.13" + "tar": "^6.1.13", + "vitest": "^1.2.1" }, "devDependencies": { "@types/async-retry": "1.4.3", diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index cbde9b062177..8a1aea19f140 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -63,10 +63,10 @@ "@chainsafe/persistent-merkle-tree": "^0.6.1", "@chainsafe/persistent-ts": "^0.19.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/config": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "bigint-buffer": "^1.1.5", "buffer-xor": "^2.0.2" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index d4a1df589e8f..038cd743bdd7 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -1,7 +1,7 @@ { "name": "@lodestar/test-utils", "private": true, - "version": "1.14.0", + "version": "1.15.0", "description": "Test utilities reused across other packages", "author": "ChainSafe Systems", "license": "Apache-2.0", @@ -60,8 +60,8 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/bls-keystore": "^3.0.0", - "@lodestar/params": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/params": "^1.15.0", + "@lodestar/utils": "^1.15.0", "axios": "^1.3.4", "testcontainers": "^10.2.1", "tmp": "^0.2.1", diff --git a/packages/types/package.json b/packages/types/package.json index b51acbef6801..1e9b811becfa 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": { ".": { @@ -73,7 +73,7 @@ "types": "lib/index.d.ts", "dependencies": { "@chainsafe/ssz": "^0.14.0", - "@lodestar/params": "^1.14.0" + "@lodestar/params": "^1.15.0" }, "keywords": [ "ethereum", diff --git a/packages/utils/package.json b/packages/utils/package.json index fcc0f5ac36c1..fa1dd4fdd829 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -11,7 +11,7 @@ "bugs": { "url": "https://github.com/ChainSafe/lodestar/issues" }, - "version": "1.14.0", + "version": "1.15.0", "type": "module", "exports": "./lib/index.js", "files": [ diff --git a/packages/validator/package.json b/packages/validator/package.json index 92c3e92d04a1..020792107c3b 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -1,6 +1,6 @@ { "name": "@lodestar/validator", - "version": "1.14.0", + "version": "1.15.0", "description": "A Typescript implementation of the validator client", "author": "ChainSafe Systems", "license": "LGPL-3.0", @@ -49,18 +49,18 @@ "dependencies": { "@chainsafe/bls": "7.1.1", "@chainsafe/ssz": "^0.14.0", - "@lodestar/api": "^1.14.0", - "@lodestar/config": "^1.14.0", - "@lodestar/db": "^1.14.0", - "@lodestar/params": "^1.14.0", - "@lodestar/state-transition": "^1.14.0", - "@lodestar/types": "^1.14.0", - "@lodestar/utils": "^1.14.0", + "@lodestar/api": "^1.15.0", + "@lodestar/config": "^1.15.0", + "@lodestar/db": "^1.15.0", + "@lodestar/params": "^1.15.0", + "@lodestar/state-transition": "^1.15.0", + "@lodestar/types": "^1.15.0", + "@lodestar/utils": "^1.15.0", "bigint-buffer": "^1.1.5", "strict-event-emitter-types": "^2.0.0" }, "devDependencies": { - "@lodestar/test-utils": "^1.14.0", + "@lodestar/test-utils": "^1.15.0", "bigint-buffer": "^1.1.5", "rimraf": "^4.4.1" } From 01d47b9a0901c9f03a01ef68c819f4e592cbfd8b Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 25 Jan 2024 02:00:48 -0800 Subject: [PATCH 61/70] chore: align test scripts (#6339) * chore: align yarn test scripts * fix: handle prover stratup failure * fix: lint * chore: improve test guide * chore: introduce top level download-spec-tests script * chore: remove pretest scripts --- CONTRIBUTING.md | 8 ++++++++ package.json | 1 + packages/api/package.json | 3 +-- packages/beacon-node/package.json | 1 - packages/cli/package.json | 1 - packages/config/package.json | 2 +- packages/db/package.json | 1 - packages/flare/package.json | 2 +- packages/fork-choice/package.json | 1 - packages/light-client/package.json | 3 +-- packages/logger/package.json | 2 +- packages/params/package.json | 2 +- packages/prover/package.json | 1 - packages/prover/test/e2e/cli/cmds/start.test.ts | 6 ++++-- packages/reqresp/package.json | 1 - packages/spec-test-util/package.json | 2 +- packages/state-transition/package.json | 1 + packages/test-utils/package.json | 1 - packages/types/package.json | 1 + packages/utils/package.json | 1 - packages/validator/package.json | 3 +-- 21 files changed, 23 insertions(+), 21 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4e67c4d226b..4074c47e88e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,14 @@ To run tests: - :test_tube: Run `yarn check-types` to check TypeScript types. - :test_tube: Run `yarn lint` to run the linter (ESLint). +Note that to run `test:e2e`, first ensure that the environment is correctly setup by running the `run_e2e_env.sh` script. + +```sh +GETH_DOCKER_IMAGE=ethereum/client-go:v1.11.6 NETHERMIND_DOCKER_IMAGE=nethermind/nethermind:1.18.0 ./scripts/run_e2e_env.sh start +``` + +Similarly, run `yarn download-spec-tests` before running `yarn test:spec`. + Contributing to tests: - Test must not depend on external live resources, such that running tests for a commit must be deterministic: diff --git a/package.json b/package.json index 93b364359a38..5d7a90f27e6f 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "test:browsers": "lerna run test:browsers", "test:e2e": "lerna run test:e2e --concurrency 1", "test:e2e:sim": "lerna run test:e2e:sim", + "download-spec-tests": "lerna run download-spec-tests", "test:spec": "lerna run test:spec", "test-coverage:unit": "c8 --config .c8rc.json --report-dir coverage/unit/ --all npm run test:unit", "test-coverage:browsers": "c8 --config .c8rc.json --report-dir coverage/browsers/ --all npm run test:browsers", diff --git a/packages/api/package.json b/packages/api/package.json index e1a52c47b489..0aa48470296d 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -63,8 +63,7 @@ "coverage": "codecov -F lodestar-api", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", - "test": "yarn test:unit && yarn test:e2e", + "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index 3ddde8540670..7b1bf0206011 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -75,7 +75,6 @@ "coverage": "codecov -F lodestar", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", "test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/", "test:unit:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/unit-mainnet", diff --git a/packages/cli/package.json b/packages/cli/package.json index 243dee688417..368637c8983a 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -30,7 +30,6 @@ "docs:build": "node --loader ts-node/esm ./docsgen/index.ts", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test:unit": "vitest --run --dir test/unit/", "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", "test:sim:multifork": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/multi_fork.test.ts", diff --git a/packages/config/package.json b/packages/config/package.json index 3b0a649e78c5..12c16f383fa8 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -49,7 +49,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", + "test": "yarn test:unit", "test:unit": "yarn vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, diff --git a/packages/db/package.json b/packages/db/package.json index d99b21d80b9b..64d499bd7fc1 100644 --- a/packages/db/package.json +++ b/packages/db/package.json @@ -31,7 +31,6 @@ "coverage": "codecov -F lodestar-fork-choice", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/flare/package.json b/packages/flare/package.json index 7417cf93c63d..8106e2b85c7f 100644 --- a/packages/flare/package.json +++ b/packages/flare/package.json @@ -43,7 +43,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", + "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, diff --git a/packages/fork-choice/package.json b/packages/fork-choice/package.json index 495c67a8e80b..6436a4299ff5 100644 --- a/packages/fork-choice/package.json +++ b/packages/fork-choice/package.json @@ -32,7 +32,6 @@ "coverage": "codecov -F lodestar-fork-choice", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/light-client/package.json b/packages/light-client/package.json index dee231409730..f09f4fdaffb9 100644 --- a/packages/light-client/package.json +++ b/packages/light-client/package.json @@ -57,8 +57,7 @@ "coverage": "codecov -F lodestar-light-client", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", - "test": "yarn test:unit && yarn test:e2e", + "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/logger/package.json b/packages/logger/package.json index 2f450ee5be12..f5efd6587bb4 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -55,7 +55,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", + "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/params/package.json b/packages/params/package.json index 2586c73566aa..ae2bb4d66cc2 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -52,7 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "test": "yarn run check-types", + "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/prover/package.json b/packages/prover/package.json index 05f7c33579b4..15066cfd81ce 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -51,7 +51,6 @@ "coverage": "codecov -F lodestar-api", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --dir test/unit/", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", diff --git a/packages/prover/test/e2e/cli/cmds/start.test.ts b/packages/prover/test/e2e/cli/cmds/start.test.ts index da0c9dceb405..8888b3ce84d5 100644 --- a/packages/prover/test/e2e/cli/cmds/start.test.ts +++ b/packages/prover/test/e2e/cli/cmds/start.test.ts @@ -43,7 +43,7 @@ describe("prover/start", () => { }); describe("when started", () => { - let proc: childProcess.ChildProcess; + let proc: childProcess.ChildProcess | null = null; const paramsFilePath = path.join("/tmp", "e2e-test-env", "params.json"); const web3: Web3 = new Web3(proxyUrl); @@ -74,7 +74,9 @@ describe("prover/start", () => { }, 50000); afterAll(async () => { - await stopChildProcess(proc); + if (proc) { + await stopChildProcess(proc); + } }); it("should respond to verified calls", async () => { diff --git a/packages/reqresp/package.json b/packages/reqresp/package.json index c19af565c397..9ac7472cd6cf 100644 --- a/packages/reqresp/package.json +++ b/packages/reqresp/package.json @@ -48,7 +48,6 @@ "coverage": "codecov -F lodestar-api", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index 899d6438d939..5e6461863947 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -46,7 +46,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", + "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --passWithNoTests --dir test/unit/", "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", "check-readme": "typescript-docs-verifier" diff --git a/packages/state-transition/package.json b/packages/state-transition/package.json index cbde9b062177..acba374e6e64 100644 --- a/packages/state-transition/package.json +++ b/packages/state-transition/package.json @@ -52,6 +52,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", + "test": "yarn test:unit", "test:unit": "vitest --run --dir test/unit/", "check-readme": "typescript-docs-verifier" }, diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index d4a1df589e8f..b1aaf3b16a33 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -44,7 +44,6 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/types/package.json b/packages/types/package.json index b51acbef6801..4497098c14f4 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -61,6 +61,7 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", + "test": "yarn test:unit", "test:constants:minimal": "LODESTAR_PRESET=minimal vitest --run --dir test/constants/", "test:constants:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/constants/", "test:unit": "wrapper() { yarn test:constants:minimal $@ && yarn test:constants:mainnet $@ && vitest --run --dir test/unit/ $@; }; wrapper", diff --git a/packages/utils/package.json b/packages/utils/package.json index fcc0f5ac36c1..db3ed9e06986 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -30,7 +30,6 @@ "check-types": "tsc && vitest --run --typecheck --dir test/types/", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test:unit": "vitest --run --dir test/unit", "test:browsers": "yarn test:browsers:chrome && yarn test:browsers:firefox && yarn test:browsers:electron", "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", diff --git a/packages/validator/package.json b/packages/validator/package.json index 92c3e92d04a1..9b8fc03c942d 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -27,9 +27,8 @@ "check-types": "tsc", "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", - "pretest": "yarn run check-types", "test:unit": "vitest --run --dir test/unit/", - "test": "yarn test:unit", + "test": "yarn test:unit && yarn test:e2e", "test:spec": "vitest --run --config vitest.config.spec.ts --dir test/spec/", "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --config vitest.config.e2e.ts --dir test/e2e", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", From 347c95fb0da219b5a4d551b7ce014f2ceda7ae48 Mon Sep 17 00:00:00 2001 From: g11tech Date: Fri, 26 Jan 2024 22:28:28 +0530 Subject: [PATCH 62/70] feat: allow builder boost factor to be configured via proposer config file (#6357) * feat: allow builder boost factor to be configured via proposer config file * reuse parseBuilderBoostFactor fn * re-shuffle fns and add builder selection validation --- packages/cli/src/cmds/validator/handler.ts | 29 +------------- packages/cli/src/util/proposerConfig.ts | 38 ++++++++++++++++++- .../validator/parseProposerConfig.test.ts | 3 ++ .../validator/proposerConfigs/validData.yaml | 2 + 4 files changed, 42 insertions(+), 30 deletions(-) diff --git a/packages/cli/src/cmds/validator/handler.ts b/packages/cli/src/cmds/validator/handler.ts index 91789c99ee3b..a98eb0755ad0 100644 --- a/packages/cli/src/cmds/validator/handler.ts +++ b/packages/cli/src/cmds/validator/handler.ts @@ -22,6 +22,7 @@ import {GlobalArgs} from "../../options/index.js"; import {YargsError, cleanOldLogFiles, getDefaultGraffiti, mkdir, parseLoggerArgs} from "../../util/index.js"; import {onGracefulShutdown, parseFeeRecipient, parseProposerConfig} from "../../util/index.js"; import {getVersionData} from "../../util/version.js"; +import {parseBuilderSelection, parseBuilderBoostFactor} from "../../util/proposerConfig.js"; import {getAccountPaths, getValidatorPaths} from "./paths.js"; import {IValidatorCliArgs, validatorMetricsDefaultOptions, validatorMonitoringDefaultOptions} from "./options.js"; import {getSignersFromArgs} from "./signers/index.js"; @@ -254,24 +255,6 @@ function getProposerConfigFromArgs( return valProposerConfig; } -function parseBuilderSelection(builderSelection?: string): routes.validator.BuilderSelection | undefined { - if (builderSelection) { - switch (builderSelection) { - case "maxprofit": - break; - case "builderalways": - break; - case "builderonly": - break; - case "executiononly": - break; - default: - throw new YargsError("Invalid input for builder selection, check help"); - } - } - return builderSelection as routes.validator.BuilderSelection; -} - function parseBroadcastValidation(broadcastValidation?: string): routes.beacon.BroadcastValidation | undefined { if (broadcastValidation) { switch (broadcastValidation) { @@ -286,13 +269,3 @@ function parseBroadcastValidation(broadcastValidation?: string): routes.beacon.B return broadcastValidation as routes.beacon.BroadcastValidation; } - -function parseBuilderBoostFactor(boostFactor?: string): bigint | undefined { - if (boostFactor === undefined) return; - - if (!/^\d+$/.test(boostFactor)) { - throw new YargsError("Invalid input for builder boost factor, must be a valid number without decimals"); - } - - return BigInt(boostFactor); -} diff --git a/packages/cli/src/util/proposerConfig.ts b/packages/cli/src/util/proposerConfig.ts index 2f3c71236255..661c81ee63af 100644 --- a/packages/cli/src/util/proposerConfig.ts +++ b/packages/cli/src/util/proposerConfig.ts @@ -8,6 +8,7 @@ import {routes} from "@lodestar/api"; import {parseFeeRecipient} from "./feeRecipient.js"; import {readFile} from "./file.js"; +import {YargsError} from "./index.js"; type ProposerConfig = ValidatorProposerConfig["defaultConfig"]; @@ -20,6 +21,7 @@ type ProposerConfigFileSection = { // for js-yaml gas_limit?: number; selection?: routes.validator.BuilderSelection; + boost_factor?: bigint; }; }; @@ -57,7 +59,7 @@ function parseProposerConfigSection( overrideConfig?: ProposerConfig ): ProposerConfig { const {graffiti, strict_fee_recipient_check, fee_recipient, builder} = proposerFileSection; - const {gas_limit, selection: builderSelection} = builder || {}; + const {gas_limit, selection: builderSelection, boost_factor} = builder || {}; if (graffiti !== undefined && typeof graffiti !== "string") { throw Error("graffiti is not 'string"); @@ -79,6 +81,9 @@ function parseProposerConfigSection( throw Error("(Number.isNaN(Number(gas_limit)) 2"); } } + if (boost_factor !== undefined && typeof boost_factor !== "string") { + throw Error("boost_factor is not 'string"); + } return { graffiti: overrideConfig?.graffiti ?? graffiti, @@ -88,7 +93,8 @@ function parseProposerConfigSection( feeRecipient: overrideConfig?.feeRecipient ?? (fee_recipient ? parseFeeRecipient(fee_recipient) : undefined), builder: { gasLimit: overrideConfig?.builder?.gasLimit ?? (gas_limit !== undefined ? Number(gas_limit) : undefined), - selection: overrideConfig?.builder?.selection ?? builderSelection, + selection: overrideConfig?.builder?.selection ?? parseBuilderSelection(builderSelection), + boostFactor: overrideConfig?.builder?.boostFactor ?? parseBuilderBoostFactor(boost_factor), }, }; } @@ -98,3 +104,31 @@ export function readProposerConfigDir(filepath: string, filename: string): Propo const proposerConfigJSON = JSON.parse(proposerConfigStr) as ProposerConfigFileSection; return proposerConfigJSON; } + +export function parseBuilderSelection(builderSelection?: string): routes.validator.BuilderSelection | undefined { + if (builderSelection) { + switch (builderSelection) { + case "maxprofit": + break; + case "builderalways": + break; + case "builderonly": + break; + case "executiononly": + break; + default: + throw new YargsError("Invalid input for builder selection, check help"); + } + } + return builderSelection as routes.validator.BuilderSelection; +} + +export function parseBuilderBoostFactor(boostFactor?: string): bigint | undefined { + if (boostFactor === undefined) return; + + if (!/^\d+$/.test(boostFactor)) { + throw new YargsError("Invalid input for builder boost factor, must be a valid number without decimals"); + } + + return BigInt(boostFactor); +} diff --git a/packages/cli/test/unit/validator/parseProposerConfig.test.ts b/packages/cli/test/unit/validator/parseProposerConfig.test.ts index fcb6933f035b..993d9640e47c 100644 --- a/packages/cli/test/unit/validator/parseProposerConfig.test.ts +++ b/packages/cli/test/unit/validator/parseProposerConfig.test.ts @@ -17,6 +17,7 @@ const testValue = { builder: { gasLimit: 30000000, selection: undefined, + boostFactor: undefined, }, }, "0xa4855c83d868f772a579133d9f23818008417b743e8447e235d8eb78b1d8f8a9f63f98c551beb7de254400f89592314d": { @@ -26,6 +27,7 @@ const testValue = { builder: { gasLimit: 35000000, selection: routes.validator.BuilderSelection.MaxProfit, + boostFactor: BigInt(18446744073709551616), }, }, }, @@ -36,6 +38,7 @@ const testValue = { builder: { gasLimit: 30000000, selection: routes.validator.BuilderSelection.BuilderAlways, + boostFactor: BigInt(100), }, }, }; diff --git a/packages/cli/test/unit/validator/proposerConfigs/validData.yaml b/packages/cli/test/unit/validator/proposerConfigs/validData.yaml index 6b7e7074b118..5ea7e1bebea7 100644 --- a/packages/cli/test/unit/validator/proposerConfigs/validData.yaml +++ b/packages/cli/test/unit/validator/proposerConfigs/validData.yaml @@ -10,6 +10,7 @@ proposer_config: builder: gas_limit: "35000000" selection: "maxprofit" + boost_factor: "18446744073709551616" default_config: graffiti: 'default graffiti' strict_fee_recipient_check: "true" @@ -17,3 +18,4 @@ default_config: builder: gas_limit: "30000000" selection: "builderalways" + boost_factor: "100" From 6adbd27c85f6fbb3a2a17ef4552274e985319c02 Mon Sep 17 00:00:00 2001 From: g11tech Date: Sat, 27 Jan 2024 22:37:49 +0530 Subject: [PATCH 63/70] fix: ignore forkchoice invalidations if latestValidHash not found (#6361) * fix: ignore forkchoice invalidations if latestValidHash not found * rename for better understanding * update the lvh search start index * apply feedback --- .../blocks/verifyBlocksExecutionPayloads.ts | 4 +- .../fork-choice/src/protoArray/interface.ts | 2 +- .../fork-choice/src/protoArray/protoArray.ts | 45 ++++++++++--------- .../protoArray/executionStatusUpdates.test.ts | 10 ++--- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts index 5dbe104c9541..91242d879f85 100644 --- a/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts +++ b/packages/beacon-node/src/chain/blocks/verifyBlocksExecutionPayloads.ts @@ -319,7 +319,7 @@ export async function verifyBlockExecutionPayload( const lvhResponse = { executionStatus, latestValidExecHash: execResult.latestValidHash, - invalidateFromBlockHash: toHexString(block.message.parentRoot), + invalidateFromParentBlockRoot: toHexString(block.message.parentRoot), }; const execError = new BlockError(block, { code: BlockErrorCode.EXECUTION_ENGINE_ERROR, @@ -416,7 +416,7 @@ function getSegmentErrorResponse( invalidSegmentLVH = { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: lvhResponse.latestValidExecHash, - invalidateFromBlockHash: parentBlock.blockRoot, + invalidateFromParentBlockRoot: parentBlock.blockRoot, }; } } diff --git a/packages/fork-choice/src/protoArray/interface.ts b/packages/fork-choice/src/protoArray/interface.ts index 1910ad2b4206..003a3c8f9f1e 100644 --- a/packages/fork-choice/src/protoArray/interface.ts +++ b/packages/fork-choice/src/protoArray/interface.ts @@ -29,7 +29,7 @@ export type LVHValidResponse = { export type LVHInvalidResponse = { executionStatus: ExecutionStatus.Invalid; latestValidExecHash: RootHex | null; - invalidateFromBlockHash: RootHex; + invalidateFromParentBlockRoot: RootHex; }; export type LVHExecResponse = LVHValidResponse | LVHInvalidResponse; diff --git a/packages/fork-choice/src/protoArray/protoArray.ts b/packages/fork-choice/src/protoArray/protoArray.ts index 62f50b03771c..eaa86b2f0ee1 100644 --- a/packages/fork-choice/src/protoArray/protoArray.ts +++ b/packages/fork-choice/src/protoArray/protoArray.ts @@ -279,32 +279,33 @@ export class ProtoArray { // Mark chain ii) as Invalid if LVH is found and non null, else only invalidate invalid_payload // if its in fcU. // - const {invalidateFromBlockHash, latestValidExecHash} = execResponse; - const invalidateFromIndex = this.indices.get(invalidateFromBlockHash); - if (invalidateFromIndex === undefined) { - throw Error(`Unable to find invalidateFromBlockHash=${invalidateFromBlockHash} in forkChoice`); + const {invalidateFromParentBlockRoot, latestValidExecHash} = execResponse; + const invalidateFromParentIndex = this.indices.get(invalidateFromParentBlockRoot); + if (invalidateFromParentIndex === undefined) { + throw Error(`Unable to find invalidateFromParentBlockRoot=${invalidateFromParentBlockRoot} in forkChoice`); } const latestValidHashIndex = - latestValidExecHash !== null ? this.getNodeIndexFromLVH(latestValidExecHash, invalidateFromIndex) : null; + latestValidExecHash !== null ? this.getNodeIndexFromLVH(latestValidExecHash, invalidateFromParentIndex) : null; if (latestValidHashIndex === null) { /** - * If the LVH is null or not found, represented with latestValidHashIndex=undefined, - * then just invalidate the invalid_payload and bug out. + * The LVH (latest valid hash) is null or not found. * - * Ideally in not found scenario we should invalidate the entire chain upwards, but - * it is possible (and observed in the testnets) that the EL was + * The spec gives an allowance for the EL being able to return a nullish LVH if it could not + * "determine" one. There are two interpretations: * - * i) buggy: that the LVH was not really the parent of the invalid block, but on - * some side chain - * ii) lazy: that invalidation was result of simple check and the EL just - * responded with a bogus LVH + * - "the LVH is unknown" - simply throw and move on. We can't determine which chain to invalidate + * since we don't know which ancestor is valid. * - * So we will just invalidate the current payload and let future responses take care - * to be as robust as possible. + * - "the LVH doesn't exist" - this means that the entire ancestor chain is invalid, and should + * be marked as such. + * + * The more robust approach is to treat nullish LVH as "the LVH is unknown" rather than + * "the LVH doesn't exist". The alternative means that we will poison a valid chain when the + * EL is lazy (or buggy) with its LVH response. */ - this.invalidateNodeByIndex(invalidateFromIndex); + throw Error(`Unable to find latestValidExecHash=${latestValidExecHash} in the forkchoice`); } else { - this.propagateInValidExecutionStatusByIndex(invalidateFromIndex, latestValidHashIndex, currentSlot); + this.propagateInValidExecutionStatusByIndex(invalidateFromParentIndex, latestValidHashIndex, currentSlot); } } } @@ -333,12 +334,12 @@ export class ProtoArray { */ private propagateInValidExecutionStatusByIndex( - invalidateFromIndex: number, + invalidateFromParentIndex: number, latestValidHashIndex: number, currentSlot: Slot ): void { - // Pass 1: mark invalidateFromIndex and its parents invalid - let invalidateIndex: number | undefined = invalidateFromIndex; + // Pass 1: mark invalidateFromParentIndex and its parents invalid + let invalidateIndex: number | undefined = invalidateFromParentIndex; while (invalidateIndex !== undefined && invalidateIndex > latestValidHashIndex) { const invalidNode = this.invalidateNodeByIndex(invalidateIndex); invalidateIndex = invalidNode.parent; @@ -368,8 +369,8 @@ export class ProtoArray { }); } - private getNodeIndexFromLVH(latestValidExecHash: RootHex, ancestorOfIndex: number): number | null { - let nodeIndex = this.nodes[ancestorOfIndex].parent; + private getNodeIndexFromLVH(latestValidExecHash: RootHex, ancestorFromIndex: number): number | null { + let nodeIndex: number | undefined = ancestorFromIndex; while (nodeIndex !== undefined && nodeIndex >= 0) { const node = this.getNodeFromIndex(nodeIndex); if ( diff --git a/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts b/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts index 94e5cd3ac9a0..e6916f24800f 100644 --- a/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts +++ b/packages/fork-choice/test/unit/protoArray/executionStatusUpdates.test.ts @@ -149,7 +149,7 @@ describe("executionStatus / normal updates", () => { { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: "2C", - invalidateFromBlockHash: "3C", + invalidateFromParentBlockRoot: "3C", }, 3 ); @@ -212,7 +212,7 @@ describe("executionStatus / normal updates", () => { { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: "1A", - invalidateFromBlockHash: "3A", + invalidateFromParentBlockRoot: "3A", }, 3 ); @@ -259,7 +259,7 @@ describe("executionStatus / invalidate all postmerge chain", () => { { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: "0x0000000000000000000000000000000000000000000000000000000000000000", - invalidateFromBlockHash: "3B", + invalidateFromParentBlockRoot: "3B", }, 3 ); @@ -336,7 +336,7 @@ describe("executionStatus / poision forkchoice if we invalidate previous valid", { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: "0x0000000000000000000000000000000000000000000000000000000000000000", - invalidateFromBlockHash: "3A", + invalidateFromParentBlockRoot: "3A", }, 3 ) @@ -373,7 +373,7 @@ describe("executionStatus / poision forkchoice if we validate previous invalid", { executionStatus: ExecutionStatus.Invalid, latestValidExecHash: "0x0000000000000000000000000000000000000000000000000000000000000000", - invalidateFromBlockHash: "3B", + invalidateFromParentBlockRoot: "3B", }, 3 ); From 291e17867becb3884fe502542bcede5bae1fc5b1 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Mon, 29 Jan 2024 01:55:48 -0500 Subject: [PATCH 64/70] feat: add down-scoring for metadata ssz size error (#6366) --- packages/beacon-node/src/network/reqresp/score.ts | 1 + packages/reqresp/src/request/errors.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/beacon-node/src/network/reqresp/score.ts b/packages/beacon-node/src/network/reqresp/score.ts index 6aca573a9ca9..c74b645c9909 100644 --- a/packages/beacon-node/src/network/reqresp/score.ts +++ b/packages/beacon-node/src/network/reqresp/score.ts @@ -24,6 +24,7 @@ export function onOutgoingReqRespError(e: RequestError, method: ReqRespMethod): switch (e.type.code) { case RequestErrorCode.INVALID_REQUEST: case RequestErrorCode.INVALID_RESPONSE_SSZ: + case RequestErrorCode.SSZ_OVER_MAX_SIZE: return PeerAction.LowToleranceError; case RequestErrorCode.SERVER_ERROR: diff --git a/packages/reqresp/src/request/errors.ts b/packages/reqresp/src/request/errors.ts index ccc3c12f97a1..0078ad5d2ecf 100644 --- a/packages/reqresp/src/request/errors.ts +++ b/packages/reqresp/src/request/errors.ts @@ -31,6 +31,8 @@ export enum RequestErrorCode { RESP_TIMEOUT = "REQUEST_ERROR_RESP_TIMEOUT", /** Request rate limited */ REQUEST_RATE_LIMITED = "REQUEST_ERROR_RATE_LIMITED", + /** */ + SSZ_OVER_MAX_SIZE = "SSZ_SNAPPY_ERROR_OVER_SSZ_MAX_SIZE", } type RequestErrorType = @@ -47,7 +49,8 @@ type RequestErrorType = | {code: RequestErrorCode.EMPTY_RESPONSE} | {code: RequestErrorCode.TTFB_TIMEOUT} | {code: RequestErrorCode.RESP_TIMEOUT} - | {code: RequestErrorCode.REQUEST_RATE_LIMITED}; + | {code: RequestErrorCode.REQUEST_RATE_LIMITED} + | {code: RequestErrorCode.SSZ_OVER_MAX_SIZE}; export const REQUEST_ERROR_CLASS_NAME = "RequestError"; From cbf349c73d7730c11d7295c27a61fbf36225df52 Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 29 Jan 2024 00:53:35 -0800 Subject: [PATCH 65/70] feat: blob sidecars can be filtered by indices (#6337) * feat: blob sidecars can be filtered by indices * fix: properly filter blobs * fix: type indices as number * chore: remove use of set * fix: make stringify more robust * Update packages/beacon-node/src/api/impl/beacon/blocks/index.ts Co-authored-by: Nico Flaig * fix: cleanup * fix: remove useless types --------- Co-authored-by: Nico Flaig --- .../api/src/beacon/routes/beacon/block.ts | 19 ++++++++++++++++--- .../api/test/unit/beacon/oapiSpec.test.ts | 6 ------ .../api/test/unit/beacon/testData/beacon.ts | 2 +- packages/api/test/utils/checkAgainstSpec.ts | 15 ++++++++++++--- .../src/api/impl/beacon/blocks/index.ts | 5 +++-- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/api/src/beacon/routes/beacon/block.ts b/packages/api/src/beacon/routes/beacon/block.ts index 95a32097028d..c1f1e723e358 100644 --- a/packages/api/src/beacon/routes/beacon/block.ts +++ b/packages/api/src/beacon/routes/beacon/block.ts @@ -229,8 +229,12 @@ export type Api = { * Retrieves BlobSidecar included in requested block. * @param blockId Block identifier. * Can be one of: "head" (canonical head in node's view), "genesis", "finalized", \, \. + * @param indices Array of indices for blob sidecars to request for in the specified block. Returns all blob sidecars in the block if not specified. */ - getBlobSidecars(blockId: BlockId): Promise< + getBlobSidecars( + blockId: BlockId, + indices?: number[] + ): Promise< ApiClientResponse<{ [HttpStatusCode.OK]: {executionOptimistic: ExecutionOptimistic; data: deneb.BlobSidecars}; }> @@ -270,7 +274,7 @@ export type ReqTypes = { publishBlockV2: {body: unknown; query: {broadcast_validation?: string}}; publishBlindedBlock: {body: unknown}; publishBlindedBlockV2: {body: unknown; query: {broadcast_validation?: string}}; - getBlobSidecars: BlockIdOnlyReq; + getBlobSidecars: {params: {block_id: string}; query: {indices?: number[]}}; }; export function getReqSerializers(config: ChainForkConfig): ReqSerializers { @@ -356,7 +360,16 @@ export function getReqSerializers(config: ChainForkConfig): ReqSerializers ({ + params: {block_id: String(block_id)}, + query: {indices}, + }), + parseReq: ({params, query}) => [params.block_id, query.indices], + schema: { + query: {indices: Schema.UintArray}, + }, + }, }; } diff --git a/packages/api/test/unit/beacon/oapiSpec.test.ts b/packages/api/test/unit/beacon/oapiSpec.test.ts index 15a10bfeb6f7..f7d6cb9a077c 100644 --- a/packages/api/test/unit/beacon/oapiSpec.test.ts +++ b/packages/api/test/unit/beacon/oapiSpec.test.ts @@ -130,12 +130,6 @@ const ignoredProperties: Record = { */ getHealth: {request: ["query.syncing_status"]}, - /** - * https://github.com/ChainSafe/lodestar/issues/6185 - * - must have required property 'query' - */ - getBlobSidecars: {request: ["query"]}, - /* https://github.com/ChainSafe/lodestar/issues/4638 /query - must have required property 'skip_randao_verification' diff --git a/packages/api/test/unit/beacon/testData/beacon.ts b/packages/api/test/unit/beacon/testData/beacon.ts index 7fa8368c590b..6d6bc6576f56 100644 --- a/packages/api/test/unit/beacon/testData/beacon.ts +++ b/packages/api/test/unit/beacon/testData/beacon.ts @@ -71,7 +71,7 @@ export const testData: GenericServerTestCases = { res: undefined, }, getBlobSidecars: { - args: ["head"], + args: ["head", [0]], res: {executionOptimistic: true, data: ssz.deneb.BlobSidecars.defaultValue()}, }, diff --git a/packages/api/test/utils/checkAgainstSpec.ts b/packages/api/test/utils/checkAgainstSpec.ts index ed65279bca22..c887f66e95e6 100644 --- a/packages/api/test/utils/checkAgainstSpec.ts +++ b/packages/api/test/utils/checkAgainstSpec.ts @@ -199,12 +199,21 @@ function prettyAjvErrors(errors: ErrorObject[] | null | undefined): string { return errors.map((e) => `${e.instancePath ?? "."} - ${e.message}`).join("\n"); } +type StringifiedProperty = string | StringifiedProperty[]; + +function stringifyProperty(value: unknown): StringifiedProperty { + if (typeof value === "number") { + return value.toString(10); + } else if (Array.isArray(value)) { + return value.map(stringifyProperty); + } + return String(value); +} + function stringifyProperties(obj: Record): Record { for (const key of Object.keys(obj)) { const value = obj[key]; - if (typeof value === "number") { - obj[key] = value.toString(10); - } + obj[key] = stringifyProperty(value); } return obj; diff --git a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts index f2e29f00fe57..6fde04bc737c 100644 --- a/packages/beacon-node/src/api/impl/beacon/blocks/index.ts +++ b/packages/beacon-node/src/api/impl/beacon/blocks/index.ts @@ -406,7 +406,7 @@ export function getBeaconBlockApi({ await publishBlock(signedBlockOrContents, opts); }, - async getBlobSidecars(blockId) { + async getBlobSidecars(blockId, indices) { const {block, executionOptimistic} = await resolveBlockId(chain, blockId); const blockRoot = config.getForkTypes(block.message.slot).BeaconBlock.hashTreeRoot(block.message); @@ -418,9 +418,10 @@ export function getBeaconBlockApi({ if (!blobSidecars) { throw Error(`blobSidecars not found in db for slot=${block.message.slot} root=${toHexString(blockRoot)}`); } + return { executionOptimistic, - data: blobSidecars, + data: indices ? blobSidecars.filter(({index}) => indices.includes(index)) : blobSidecars, }; }, }; From 54c20699d2395ba0ac658616b8a227fc52ccc414 Mon Sep 17 00:00:00 2001 From: Nico Flaig Date: Mon, 29 Jan 2024 18:15:27 +0100 Subject: [PATCH 66/70] fix: ignore stale keystore lockfiles (#6363) * fix: ignore stale keystore lockfiles * Update error message if lockfile is already acquired * Update keymanager lockfile e2e tests --- packages/cli/package.json | 4 +- packages/cli/src/util/lockfile.ts | 54 +++++++++++-------- .../test/e2e/importKeystoresFromApi.test.ts | 8 +-- .../decryptKeystoreDefinitions.test.ts | 13 +++-- packages/db/src/controller/level.ts | 2 +- yarn.lock | 19 +++---- 6 files changed, 55 insertions(+), 45 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index c16baf13c25f..8531db5b633f 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -77,7 +77,6 @@ "@lodestar/utils": "^1.15.0", "@lodestar/validator": "^1.15.0", "@multiformats/multiaddr": "^12.1.3", - "@types/lockfile": "^1.0.2", "bip39": "^3.1.0", "deepmerge": "^4.3.1", "ethers": "^6.7.0", @@ -86,9 +85,9 @@ "got": "^11.8.6", "inquirer": "^9.1.5", "js-yaml": "^4.1.0", - "lockfile": "^1.0.4", "lodash": "^4.17.21", "prom-client": "^15.1.0", + "proper-lockfile": "^4.1.2", "rimraf": "^4.4.1", "source-map-support": "^0.5.21", "uint8arrays": "^4.0.9", @@ -102,6 +101,7 @@ "@types/got": "^9.6.12", "@types/inquirer": "^9.0.3", "@types/lodash": "^4.14.192", + "@types/proper-lockfile": "^4.1.4", "@types/yargs": "^17.0.24" } } diff --git a/packages/cli/src/util/lockfile.ts b/packages/cli/src/util/lockfile.ts index 65933e8f2897..f7a6ddf4d57d 100644 --- a/packages/cli/src/util/lockfile.ts +++ b/packages/cli/src/util/lockfile.ts @@ -1,29 +1,21 @@ -export type Lockfile = { - lockSync(path: string): void; - unlockSync(path: string): void; -}; - -const lockFile: Lockfile = (await import("lockfile")) as Lockfile; - -function getLockFilepath(filepath: string): string { - return `${filepath}.lock`; -} - -/** - * When lockfile is imported, it registers listeners to process - * Since it's only used by the validator client, require lazily to not pollute - * beacon_node client context - */ -function getLockFile(): Lockfile { - return lockFile; -} +import {lockSync, unlockSync} from "proper-lockfile"; /** * Creates a .lock file for `filepath`, argument passed must not be the lock path * @param filepath File to lock, i.e. `keystore_0001.json` */ export function lockFilepath(filepath: string): void { - getLockFile().lockSync(getLockFilepath(filepath)); + try { + lockSync(filepath, { + // Allows to lock files that do not exist + realpath: false, + }); + } catch (e) { + if (isLockfileError(e) && e.code === "ELOCKED") { + e.message = `${filepath} is already in use by another process`; + } + throw e; + } } /** @@ -31,7 +23,23 @@ export function lockFilepath(filepath: string): void { * @param filepath File to unlock, i.e. `keystore_0001.json` */ export function unlockFilepath(filepath: string): void { - // Does not throw if the lock file is already deleted - // https://github.com/npm/lockfile/blob/6590779867ee9bdc5dbebddc962640759892bb91/lockfile.js#L68 - getLockFile().unlockSync(getLockFilepath(filepath)); + try { + unlockSync(filepath, { + // Allows to unlock files that do not exist + realpath: false, + }); + } catch (e) { + if (isLockfileError(e) && e.code === "ENOTACQUIRED") { + // Do not throw if the lock file is already deleted + return; + } + throw e; + } +} + +// https://github.com/moxystudio/node-proper-lockfile/blob/9f8c303c91998e8404a911dc11c54029812bca69/lib/lockfile.js#L53 +export type LockfileError = Error & {code: "ELOCKED" | "ENOTACQUIRED"}; + +function isLockfileError(e: unknown): e is LockfileError { + return e instanceof Error && (e as LockfileError).code !== undefined; } diff --git a/packages/cli/test/e2e/importKeystoresFromApi.test.ts b/packages/cli/test/e2e/importKeystoresFromApi.test.ts index bb91d467b86a..1cf5f107e226 100644 --- a/packages/cli/test/e2e/importKeystoresFromApi.test.ts +++ b/packages/cli/test/e2e/importKeystoresFromApi.test.ts @@ -95,10 +95,10 @@ describe("import keystores from api", function () { validator.on("exit", (code) => { if (code !== null && code > 0) { // process should exit with code > 0, and an error related to locks. Sample error: - // vc 351591: ✖ Error: EEXIST: file already exists, open '/tmp/tmp-351554-dMctEAj7sJIz/import-keystores-test/keystores/0x8be678633e927aa0435addad5dcd5283fef6110d91362519cd6d43e61f6c017d724fa579cc4b2972134e050b6ba120c0/voting-keystore.json.lock' - // at Object.openSync (node:fs:585:3) - // at Module.exports.lockSync (/home/lion/Code/eth2.0/lodestar/node_modules/lockfile/lockfile.js:277:17) - if (/EEXIST.*voting-keystore\.json\.lock/.test(vcProc2Stderr.read())) { + // vc 351591: ✖ Error: /tmp/tmp-5080-lwNxdM5Ok9ya/import-keystores-test/keystores/0x8be678633e927aa0435addad5dcd5283fef6110d91362519cd6d43e61f6c017d724fa579cc4b2972134e050b6ba120c0/voting-keystore.json is already in use by another process + // at /home/runner/actions-runner/_work/lodestar/lodestar/node_modules/proper-lockfile/lib/lockfile.js:68:47 + // ... more stack trace + if (/Error.*voting-keystore\.json is already in use by another process/.test(vcProc2Stderr.read())) { resolve(); } else { reject(Error(`Second validator proc exited with unknown error. stderr:\n${vcProc2Stderr.read()}`)); diff --git a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts index f24b83ae43a6..0f4173604405 100644 --- a/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts +++ b/packages/cli/test/unit/validator/decryptKeystoreDefinitions.test.ts @@ -7,6 +7,7 @@ import {cachedSeckeysHex} from "../../utils/cachedKeys.js"; import {testFilesDir} from "../../utils.js"; import {decryptKeystoreDefinitions} from "../../../src/cmds/validator/keymanager/decryptKeystoreDefinitions.js"; import {LocalKeystoreDefinition} from "../../../src/cmds/validator/keymanager/interface.js"; +import {LockfileError, unlockFilepath} from "../../../src/util/lockfile.js"; describe("decryptKeystoreDefinitions", () => { vi.setConfig({testTimeout: 100_000}); @@ -22,6 +23,10 @@ describe("decryptKeystoreDefinitions", () => { let definitions: LocalKeystoreDefinition[] = []; beforeEach(async () => { + // remove lockfiles from proper-lockfile cache + for (const {keystorePath} of definitions) { + unlockFilepath(keystorePath); + } rimraf.sync(dataDir); rimraf.sync(importFromDir); @@ -46,7 +51,9 @@ describe("decryptKeystoreDefinitions", () => { expect(fs.existsSync(cacheFilePath)).toBe(true); // remove lockfiles created during cache file preparation - rimraf.sync(path.join(importFromDir, "*.lock"), {glob: true}); + for (const {keystorePath} of definitions) { + unlockFilepath(keystorePath); + } }); testDecryptKeystoreDefinitions(cacheFilePath); @@ -75,14 +82,14 @@ describe("decryptKeystoreDefinitions", () => { await decryptKeystoreDefinitions(definitions, {logger: console, signal, cacheFilePath}); expect.fail("Second decrypt should fail due to failure to get lockfile"); } catch (e) { - expect((e as Error).message.startsWith("EEXIST: file already exists")).toBe(true); + expect((e as LockfileError).code).toBe("ELOCKED"); } }); it("decrypt keystores if lockfiles already exist if ignoreLockFile=true", async () => { await decryptKeystoreDefinitions(definitions, {logger: console, signal, cacheFilePath}); - // lockfiles should exist after the first run + await decryptKeystoreDefinitions(definitions, {logger: console, signal, cacheFilePath, ignoreLockFile: true}); }); } diff --git a/packages/db/src/controller/level.ts b/packages/db/src/controller/level.ts index 3eed75958e3e..2cea8681c95b 100644 --- a/packages/db/src/controller/level.ts +++ b/packages/db/src/controller/level.ts @@ -52,7 +52,7 @@ export class LevelDbController implements DatabaseController Date: Tue, 30 Jan 2024 00:17:23 +0700 Subject: [PATCH 67/70] fix: stabilize unknown block sync e2e test (#6364) fix: stabalize unknown block sync e2e test --- .../test/e2e/sync/unknownBlockSync.test.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts index a51beaf7b961..e64adfc94888 100644 --- a/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts +++ b/packages/beacon-node/test/e2e/sync/unknownBlockSync.test.ts @@ -12,7 +12,7 @@ import {waitForEvent} from "../../utils/events/resolver.js"; import {getAndInitDevValidators} from "../../utils/node/validator.js"; import {ChainEvent} from "../../../src/chain/index.js"; import {NetworkEvent} from "../../../src/network/index.js"; -import {connect} from "../../utils/network.js"; +import {connect, onPeerConnect} from "../../utils/network.js"; import {testLogger, LogLevel, TestLoggerOpts} from "../../utils/logger.js"; import {BlockError, BlockErrorCode} from "../../../src/chain/errors/index.js"; import {BlockSource, getBlockInput} from "../../../src/chain/blocks/types.js"; @@ -48,7 +48,7 @@ describe("sync / unknown block sync", function () { for (const {id, event} of testCases) { it(id, async function () { // the node needs time to transpile/initialize bls worker threads - const genesisSlotsDelay = 7; + const genesisSlotsDelay = 4; const genesisTime = Math.floor(Date.now() / 1000) + genesisSlotsDelay * testParams.SECONDS_PER_SLOT; const testLoggerOpts: TestLoggerOpts = { level: LogLevel.info, @@ -71,6 +71,7 @@ describe("sync / unknown block sync", function () { chain: {blsVerifyAllMainThread: true}, }, validatorCount, + genesisTime, logger: loggerNodeA, }); @@ -100,7 +101,7 @@ describe("sync / unknown block sync", function () { chain: {blsVerifyAllMainThread: true}, }, validatorCount, - genesisTime: bn.chain.getHeadState().genesisTime, + genesisTime, logger: loggerNodeB, }); @@ -116,7 +117,11 @@ describe("sync / unknown block sync", function () { ({block}) => block === headSummary.blockRoot ); + const connected = Promise.all([onPeerConnect(bn2.network), onPeerConnect(bn.network)]); await connect(bn2.network, bn.network); + await connected; + loggerNodeA.info("Node A connected to Node B"); + const headInput = getBlockInput.preDeneb(config, head, BlockSource.gossip, null); switch (event) { @@ -147,4 +152,4 @@ describe("sync / unknown block sync", function () { await waitForSynced; }); } -}, {timeout: 30_000}); +}, {timeout: 40_000}); From ed43a988bf7acbe25fad9988434a1ade3ed6016e Mon Sep 17 00:00:00 2001 From: Julien Date: Mon, 29 Jan 2024 09:53:35 -0800 Subject: [PATCH 68/70] chore: align vitest config filenames (#6369) --- CONTRIBUTING.md | 2 +- packages/beacon-node/package.json | 10 +++++----- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 .../{vitest.config.spec.ts => vitest.spec.config.ts} | 0 packages/cli/package.json | 2 +- .../cli/{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 packages/logger/package.json | 2 +- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 packages/params/package.json | 2 +- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 packages/prover/package.json | 2 +- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 packages/spec-test-util/package.json | 2 +- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 packages/validator/package.json | 4 ++-- .../{vitest.config.e2e.ts => vitest.e2e.config.ts} | 0 .../{vitest.config.spec.ts => vitest.spec.config.ts} | 0 17 files changed, 13 insertions(+), 13 deletions(-) rename packages/beacon-node/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/beacon-node/{vitest.config.spec.ts => vitest.spec.config.ts} (100%) rename packages/cli/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/logger/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/params/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/prover/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/spec-test-util/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/validator/{vitest.config.e2e.ts => vitest.e2e.config.ts} (100%) rename packages/validator/{vitest.config.spec.ts => vitest.spec.config.ts} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4074c47e88e8..75fc18a95da9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -65,7 +65,7 @@ If you observe following error running any of the test files that means you are - To then run only that failed test you can run against a specific file as use vitest's filters to run only one case ```sh -LODESTAR_PRESET=minimal yarn vitest --run --config vitest.config.spec.ts test/spec/phase0/sanity.test.ts +LODESTAR_PRESET=minimal yarn vitest --run --config vitest.spec.config.ts test/spec/phase0/sanity.test.ts ``` ## Docker diff --git a/packages/beacon-node/package.json b/packages/beacon-node/package.json index aab75c458d56..174ed8cbb125 100644 --- a/packages/beacon-node/package.json +++ b/packages/beacon-node/package.json @@ -79,17 +79,17 @@ "test:unit:minimal": "vitest --run --segfaultRetry 3 --dir test/unit/", "test:unit:mainnet": "LODESTAR_PRESET=mainnet vitest --run --dir test/unit-mainnet", "test:unit": "wrapper() { yarn test:unit:minimal $@ && yarn test:unit:mainnet $@; }; wrapper", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --config vitest.config.e2e.ts --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --segfaultRetry 3 --config vitest.e2e.config.ts --dir test/e2e", "test:sim": "vitest --run test/sim/**/*.test.ts", "test:sim:merge-interop": "vitest --run test/sim/merge-interop.test.ts", "test:sim:mergemock": "vitest --run test/sim/mergemock.test.ts", "test:sim:withdrawals": "vitest --run test/sim/withdrawal-interop.test.ts", "test:sim:blobs": "vitest --run test/sim/4844-interop.test.ts", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", - "test:spec:bls": "vitest --run --config vitest.config.spec.ts --dir test/spec/bls/", - "test:spec:general": "vitest --run --config vitest.config.spec.ts --dir test/spec/general/", - "test:spec:minimal": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.spec.ts --dir test/spec/presets/", - "test:spec:mainnet": "LODESTAR_PRESET=mainnet vitest --run --config vitest.config.spec.ts --dir test/spec/presets/", + "test:spec:bls": "vitest --run --config vitest.spec.config.ts --dir test/spec/bls/", + "test:spec:general": "vitest --run --config vitest.spec.config.ts --dir test/spec/general/", + "test:spec:minimal": "LODESTAR_PRESET=minimal vitest --run --config vitest.spec.config.ts --dir test/spec/presets/", + "test:spec:mainnet": "LODESTAR_PRESET=mainnet vitest --run --config vitest.spec.config.ts --dir test/spec/presets/", "test:spec": "yarn test:spec:bls && yarn test:spec:general && yarn test:spec:minimal && yarn test:spec:mainnet", "check-readme": "typescript-docs-verifier" }, diff --git a/packages/beacon-node/vitest.config.e2e.ts b/packages/beacon-node/vitest.e2e.config.ts similarity index 100% rename from packages/beacon-node/vitest.config.e2e.ts rename to packages/beacon-node/vitest.e2e.config.ts diff --git a/packages/beacon-node/vitest.config.spec.ts b/packages/beacon-node/vitest.spec.config.ts similarity index 100% rename from packages/beacon-node/vitest.config.spec.ts rename to packages/beacon-node/vitest.spec.config.ts diff --git a/packages/cli/package.json b/packages/cli/package.json index 8531db5b633f..d21e523696ef 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -31,7 +31,7 @@ "lint": "eslint --color --ext .ts src/ test/", "lint:fix": "yarn run lint --fix", "test:unit": "vitest --run --dir test/unit/", - "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", + "test:e2e": "vitest --run --config vitest.e2e.config.ts --dir test/e2e/", "test:sim:multifork": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/multi_fork.test.ts", "test:sim:mixedclient": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/mixed_client.test.ts", "test:sim:endpoints": "LODESTAR_PRESET=minimal node --loader ts-node/esm test/sim/endpoints.test.ts", diff --git a/packages/cli/vitest.config.e2e.ts b/packages/cli/vitest.e2e.config.ts similarity index 100% rename from packages/cli/vitest.config.e2e.ts rename to packages/cli/vitest.e2e.config.ts diff --git a/packages/logger/package.json b/packages/logger/package.json index fd82a7651b3f..e8d32622ae95 100644 --- a/packages/logger/package.json +++ b/packages/logger/package.json @@ -61,7 +61,7 @@ "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.e2e.config.ts --dir test/e2e", "check-readme": "typescript-docs-verifier" }, "types": "lib/index.d.ts", diff --git a/packages/logger/vitest.config.e2e.ts b/packages/logger/vitest.e2e.config.ts similarity index 100% rename from packages/logger/vitest.config.e2e.ts rename to packages/logger/vitest.e2e.config.ts diff --git a/packages/params/package.json b/packages/params/package.json index ebd4116f16b1..bd5259c4712d 100644 --- a/packages/params/package.json +++ b/packages/params/package.json @@ -58,7 +58,7 @@ "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e/", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.e2e.config.ts --dir test/e2e/", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/params/vitest.config.e2e.ts b/packages/params/vitest.e2e.config.ts similarity index 100% rename from packages/params/vitest.config.e2e.ts rename to packages/params/vitest.e2e.config.ts diff --git a/packages/prover/package.json b/packages/prover/package.json index 36433fa8d567..b5c7eac31033 100644 --- a/packages/prover/package.json +++ b/packages/prover/package.json @@ -57,7 +57,7 @@ "test:browsers:chrome": "vitest --run --browser chrome --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:firefox": "vitest --run --browser firefox --config ./vitest.browser.config.ts --dir test/unit", "test:browsers:electron": "echo 'Electron tests will be introduced back in the future as soon vitest supports electron.'", - "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.config.e2e.ts --dir test/e2e", + "test:e2e": "LODESTAR_PRESET=minimal vitest --run --config vitest.e2e.config.ts --dir test/e2e", "check-readme": "typescript-docs-verifier", "generate-fixtures": "node --loader ts-node/esm scripts/generate_fixtures.ts" }, diff --git a/packages/prover/vitest.config.e2e.ts b/packages/prover/vitest.e2e.config.ts similarity index 100% rename from packages/prover/vitest.config.e2e.ts rename to packages/prover/vitest.e2e.config.ts diff --git a/packages/spec-test-util/package.json b/packages/spec-test-util/package.json index c2c202a72614..7e9a82b16035 100644 --- a/packages/spec-test-util/package.json +++ b/packages/spec-test-util/package.json @@ -48,7 +48,7 @@ "lint:fix": "yarn run lint --fix", "test": "yarn test:unit && yarn test:e2e", "test:unit": "vitest --run --passWithNoTests --dir test/unit/", - "test:e2e": "vitest --run --config vitest.config.e2e.ts --dir test/e2e/", + "test:e2e": "vitest --run --config vitest.e2e.config.ts --dir test/e2e/", "check-readme": "typescript-docs-verifier" }, "repository": { diff --git a/packages/spec-test-util/vitest.config.e2e.ts b/packages/spec-test-util/vitest.e2e.config.ts similarity index 100% rename from packages/spec-test-util/vitest.config.e2e.ts rename to packages/spec-test-util/vitest.e2e.config.ts diff --git a/packages/validator/package.json b/packages/validator/package.json index 5a2dcb55c2ba..5b913ad84a63 100644 --- a/packages/validator/package.json +++ b/packages/validator/package.json @@ -29,8 +29,8 @@ "lint:fix": "yarn run lint --fix", "test:unit": "vitest --run --dir test/unit/", "test": "yarn test:unit && yarn test:e2e", - "test:spec": "vitest --run --config vitest.config.spec.ts --dir test/spec/", - "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --config vitest.config.e2e.ts --dir test/e2e", + "test:spec": "vitest --run --config vitest.spec.config.ts --dir test/spec/", + "test:e2e": "LODESTAR_PRESET=mainnet vitest --run --config vitest.e2e.config.ts --dir test/e2e", "download-spec-tests": "node --loader=ts-node/esm test/spec/downloadTests.ts", "coverage": "codecov -F lodestar-validator", "check-readme": "typescript-docs-verifier" diff --git a/packages/validator/vitest.config.e2e.ts b/packages/validator/vitest.e2e.config.ts similarity index 100% rename from packages/validator/vitest.config.e2e.ts rename to packages/validator/vitest.e2e.config.ts diff --git a/packages/validator/vitest.config.spec.ts b/packages/validator/vitest.spec.config.ts similarity index 100% rename from packages/validator/vitest.config.spec.ts rename to packages/validator/vitest.spec.config.ts From 8b354f2087cac8abea6f478b8bda6fe09ebdc528 Mon Sep 17 00:00:00 2001 From: Matthew Keil Date: Tue, 30 Jan 2024 16:17:20 +0700 Subject: [PATCH 69/70] docs: add comment to RequestErrorCode.SSZ_OVER_MAX_SIZE (#6373) --- packages/reqresp/src/request/errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/reqresp/src/request/errors.ts b/packages/reqresp/src/request/errors.ts index 0078ad5d2ecf..ba3904e563ed 100644 --- a/packages/reqresp/src/request/errors.ts +++ b/packages/reqresp/src/request/errors.ts @@ -31,7 +31,7 @@ export enum RequestErrorCode { RESP_TIMEOUT = "REQUEST_ERROR_RESP_TIMEOUT", /** Request rate limited */ REQUEST_RATE_LIMITED = "REQUEST_ERROR_RATE_LIMITED", - /** */ + /** For malformed SSZ (metadata) responses */ SSZ_OVER_MAX_SIZE = "SSZ_SNAPPY_ERROR_OVER_SSZ_MAX_SIZE", } From 5064fab473641bb724425222db79646ac7016ae7 Mon Sep 17 00:00:00 2001 From: scott willeke Date: Tue, 30 Jan 2024 01:30:14 -0800 Subject: [PATCH 70/70] docs: update link to erigon jwt setup (#6375) --- docs/pages/getting-started/starting-a-node.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/getting-started/starting-a-node.md b/docs/pages/getting-started/starting-a-node.md index dd11381bde10..665a39b0df80 100644 --- a/docs/pages/getting-started/starting-a-node.md +++ b/docs/pages/getting-started/starting-a-node.md @@ -47,7 +47,7 @@ Use the `--JsonRpc.JwtSecretFile /data/jwtsecret` flag to configure the secret. Use the `--engine-jwt-secret=` flag to configure the secret. Use their documentation [here](https://besu.hyperledger.org/en/stable/Reference/CLI/CLI-Syntax/#engine-jwt-secret). **For Erigon:** -Use the `--authrpc.jwtsecret` flag to configure the secret. Use their documentation [here](https://github.com/ledgerwatch/erigon#authentication-api). +Use the `--authrpc.jwtsecret` flag to configure the secret. Use their documentation [here](https://github.com/ledgerwatch/erigon?tab=readme-ov-file#beacon-chain-consensus-layer). ## Run a beacon node