From 71431ce0c9365101154188fb2e7d30be87248fb1 Mon Sep 17 00:00:00 2001 From: Dimo99 Date: Wed, 14 Jun 2023 18:47:29 +0300 Subject: [PATCH] feat(plonky2): Validators commitment mapper --- .../circom/scripts/validator_balances/test.ts | 17 +- .../plonky2/Commitment_Mapper.md | 17 + .../get_changed_balances.ts | 86 ++ .../plonky2/circuits/Cargo.lock | 949 ++++++++++++++++++ .../plonky2/circuits/Cargo.toml | 11 + .../plonky2/circuits/src/hash_tree_root.rs | 25 + .../circuits/src/is_valid_merkle_branch.rs | 68 ++ .../plonky2/circuits/src/main.rs | 8 + .../plonky2/circuits/src/utils.rs | 25 + .../circuits/src/validator_hash_tree_root.rs | 37 + beacon-light-client/plonky2/tsconfig.json | 9 + .../src/hash_tree_root.rs | 26 + .../get_changed_validators.ts | 94 ++ 13 files changed, 1369 insertions(+), 3 deletions(-) create mode 100644 beacon-light-client/plonky2/Commitment_Mapper.md create mode 100644 beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts create mode 100644 beacon-light-client/plonky2/circuits/Cargo.lock create mode 100644 beacon-light-client/plonky2/circuits/Cargo.toml create mode 100644 beacon-light-client/plonky2/circuits/src/hash_tree_root.rs create mode 100644 beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs create mode 100644 beacon-light-client/plonky2/circuits/src/main.rs create mode 100644 beacon-light-client/plonky2/circuits/src/utils.rs create mode 100644 beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs create mode 100644 beacon-light-client/plonky2/tsconfig.json create mode 100644 beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs create mode 100644 beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts diff --git a/beacon-light-client/circom/scripts/validator_balances/test.ts b/beacon-light-client/circom/scripts/validator_balances/test.ts index dced09be5..a75502827 100644 --- a/beacon-light-client/circom/scripts/validator_balances/test.ts +++ b/beacon-light-client/circom/scripts/validator_balances/test.ts @@ -12,7 +12,7 @@ import { verifyMerkleProof } from '../../../../libs/typescript/ts-utils/ssz-util ); const beaconStateSZZ = await fetch( - `http://unstable.prater.beacon-api.nimbus.team/eth/v2/debug/beacon/states/5794336`, + `http://testing.mainnet.beacon-api.nimbus.team/eth/v2/debug/beacon/states/6616005`, { headers: { Accept: 'application/octet-stream', @@ -24,8 +24,19 @@ import { verifyMerkleProof } from '../../../../libs/typescript/ts-utils/ssz-util const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); - console.log(beaconState.balances.length); - console.log(beaconState.validators.length); + console.log( + BigInt( + '0x' + + bytesToHex( + ssz.phase0.Validator.hashTreeRoot(beaconState.validators[0]), + ), + ) + .toString(2) + .padStart(256, '0') + .split('') + .map(x => `"${x.toString()}"`) + .join(','), + ); // const beaconStateView = ssz.capella.BeaconState.toViewDU(beaconState); // const beaconStateTree = new Tree(beaconStateView.node); diff --git a/beacon-light-client/plonky2/Commitment_Mapper.md b/beacon-light-client/plonky2/Commitment_Mapper.md new file mode 100644 index 000000000..50626d6c7 --- /dev/null +++ b/beacon-light-client/plonky2/Commitment_Mapper.md @@ -0,0 +1,17 @@ +# Optimizing ZK Proofs for Validator Balances + +## Objective + +Our goal is to confirm the total of a certain collection of validator balances on-chain, aiming to diminish the amount of required on-chain Merkle proofs. Our current strategy utilizes one zk-proof validation on-chain to ensure that a specific validator set exhibits a certain balance total for a designated beacon state root. + +The primary obstacle encountered is the lack of zk-friendliness in the SHA-256 hash function, which is presently employed in our Merkle proofs. The performance deficiency due to the significant computational burden of the SHA-256 makes it unsuitable for our requirements. To illustrate, a single Merkle proof for a validator demands about 43 hashes, whereas the balance tree calls for 39 hashes. + +## Suggested Approach + +### Handling Validators + +We propose to create a commitment mapping from the validators' root (a SHA-256 Merkle tree comprising all validators) to a Poseidon root of validators. This process would involve generating a proof that a given SHA-256 Merkle tree of validators matches a corresponding Poseidon Merkle tree of validators. Given the sheer number of validators, this tree will be formed using recursive proofs. Since only a small fraction of validators changes per epoch, we can economically update and reuse the proofs. The Poseidon hash function, being more zk-friendly, could then be used to validate that a specific validator belongs to the tree in a more cost-effective manner. + +### Dealing with Balances + +The complexity with balances lies in their tendency to alter with each epoch. Consequently, adopting a similar approach as the one for validators would not be feasible. This is due to the need for recalculating the proofs for all balances from the ground up for each epoch. diff --git a/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts b/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts new file mode 100644 index 000000000..15f922588 --- /dev/null +++ b/beacon-light-client/plonky2/balances_commitment_mapper_tree/get_changed_balances.ts @@ -0,0 +1,86 @@ +import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { sleep } from '../../../libs/typescript/ts-utils/common-utils'; + +(async () => { + const { ssz } = await import('@lodestar/types'); + + let prevSlot = 0; + + while (true) { + const beaconStateSZZ = await fetch( + `https://floral-chaotic-sea.discover.quiknode.pro/c1133f4fcc19bbe54fa6e4caf0c05ac79ec7d300/eth/v2/debug/beacon/states/head`, + { + headers: { + Accept: 'application/octet-stream', + }, + }, + ) + .then(response => response.arrayBuffer()) + .then(buffer => new Uint8Array(buffer)); + + const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); + + if (!existsSync('prev_beacon_state.ssz')) { + console.log('prev_beacon_state.ssz does not exist. Creating it.'); + + prevSlot = beaconState.slot; + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + await sleep(12000); + continue; + } + + console.log(beaconState.slot); + + if (prevSlot >= beaconState.slot) { + console.log('Waiting for the next epoch.'); + await sleep(12000); + continue; + } + + const prevBeaconStateSSZ = new Uint8Array( + readFileSync('prev_beacon_state.ssz'), + ); + + const prevBeaconState = + ssz.capella.BeaconState.deserialize(prevBeaconStateSSZ); + + const balances = beaconState.balances; + const prevBalances = prevBeaconState.balances; + + const balancesWithIndices = balances.map((balance, index) => ({ + balance: balance, + index, + })); + + const changedBalances = balancesWithIndices.filter( + ({ balance, index }) => + prevBalances[index] === undefined || balance !== prevBalances[index], + ); + + // TODO: push the changed validators to the tree + + console.log('#changedBalances', changedBalances.length); + + console.log( + 'changed indices', + changedBalances.map(({ index }) => index), + ); + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + prevSlot = beaconState.slot; + + // wait for the next slot + await sleep(12000); + } +})(); diff --git a/beacon-light-client/plonky2/circuits/Cargo.lock b/beacon-light-client/plonky2/circuits/Cargo.lock new file mode 100644 index 000000000..975927032 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/Cargo.lock @@ -0,0 +1,949 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "const-random", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "circuits" +version = "0.1.0" +dependencies = [ + "plonky2", + "plonky2_sha256", + "sha2 0.9.9", +] + +[[package]] +name = "const-random" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e" +dependencies = [ + "const-random-macro", + "proc-macro-hack", +] + +[[package]] +name = "const-random-macro" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb" +dependencies = [ + "getrandom", + "once_cell", + "proc-macro-hack", + "tiny-keccak", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", + "rayon", + "serde", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "keccak-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce2bd4c29270e724d3eaadf7bdc8700af4221fc0ed771b855eadcd1b98d52851" +dependencies = [ + "primitive-types 0.10.1", + "tiny-keccak", +] + +[[package]] +name = "keccak-hash" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b286e6b663fb926e1eeb68528e69cb70ed46c6d65871a21b2215ae8154c6d3c" +dependencies = [ + "primitive-types 0.12.1", + "tiny-keccak", +] + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "log" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" + +[[package]] +name = "maybe_rayon" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "rayon", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "plonky2" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "ahash", + "anyhow", + "hashbrown", + "itertools", + "keccak-hash 0.8.0", + "log", + "maybe_rayon", + "num", + "plonky2_field", + "plonky2_util", + "rand", + "rand_chacha", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "plonky2_field" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "anyhow", + "itertools", + "num", + "plonky2_util", + "rand", + "serde", + "static_assertions", + "unroll", +] + +[[package]] +name = "plonky2_sha256" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2-sha256?branch=main#06d128e78ed8d29b21d58294b069e852c1866f8d" +dependencies = [ + "anyhow", + "env_logger", + "itertools", + "keccak-hash 0.10.0", + "log", + "plonky2", + "plonky2_field", + "plonky2_u32", + "plonky2_util", + "rand", + "sha2 0.10.6", +] + +[[package]] +name = "plonky2_u32" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" +dependencies = [ + "anyhow", + "itertools", + "num", + "plonky2", +] + +[[package]] +name = "plonky2_util" +version = "0.1.0" +source = "git+https://github.com/polymerdao/plonky2?rev=4cb0b48df1d227d5461a4c28ed025aaea64e2e62#4cb0b48df1d227d5461a4c28ed025aaea64e2e62" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05e4722c697a58a99d5d06a08c30821d7c082a4632198de1eaa5a6c22ef42373" +dependencies = [ + "fixed-hash 0.7.0", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", + "uint", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "regex" +version = "1.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "rustix" +version = "0.37.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.164" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.18", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-ident" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" + +[[package]] +name = "unroll" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/beacon-light-client/plonky2/circuits/Cargo.toml b/beacon-light-client/plonky2/circuits/Cargo.toml new file mode 100644 index 000000000..4dcec7a8d --- /dev/null +++ b/beacon-light-client/plonky2/circuits/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "circuits" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +plonky2 = { git = "https://github.com/polymerdao/plonky2", rev = "4cb0b48df1d227d5461a4c28ed025aaea64e2e62" } +plonky2_sha256 = { git = "https://github.com/polymerdao/plonky2-sha256", branch = "main" } +sha2 = "0.9" diff --git a/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs new file mode 100644 index 000000000..3b648ba0b --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/hash_tree_root.rs @@ -0,0 +1,25 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::make_circuits; + +pub fn hash_tree_root, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + leaves: &Vec<[bool; 256]>, +) { + for i in 0..leaves.len() - 1 { + let hasher = make_circuits(builder, 512); + + for j in 0..256 { + pw.set_bool_target(hasher.message[i], leaves[i][j]); + } + + for j in 0..256 { + pw.set_bool_target(hasher.message[i + 256], leaves[i + 1][j]); + } + } +} diff --git a/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs b/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs new file mode 100644 index 000000000..ddb9ecd28 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/is_valid_merkle_branch.rs @@ -0,0 +1,68 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; + +use plonky2_sha256::circuit::{array_to_bits, make_circuits, Sha256Targets}; + +use sha2::{Digest, Sha256}; + +use crate::utils::hash_values; + +pub fn is_valid_merkle_branch, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + root: &[bool; 256], + leaf: &[bool; 256], + branch: &[[bool; 256]], + index: &u64, +) { + let mut leaf = leaf.clone(); + + let mut index = index.clone(); + + for (i, sibling) in branch.iter().enumerate() { + let is_right = index % 2 == 1; + let mut lhs = leaf.clone(); + let mut rhs = sibling.clone(); + + if is_right { + std::mem::swap(&mut lhs, &mut rhs); + } + + let hasher = make_circuits(builder, 512); + + for i in 0..256 { + pw.set_bool_target(hasher.message[i], lhs[i]); + } + + for i in 0..256 { + pw.set_bool_target(hasher.message[i + 256], rhs[i]); + } + + leaf = hash_values(lhs, rhs); + + // constraint the root + if i == branch.len() - 1 { + assert_hasher(root, builder, hasher) + } + + index /= 2; + } +} + +fn assert_hasher, const D: usize>( + result: &[bool; 256], + builder: &mut CircuitBuilder, + hasher: Sha256Targets, +) { + for i in 0..256 { + if result[i] { + builder.assert_one(hasher.digest[i].target); + } else { + builder.assert_zero(hasher.digest[i].target); + } + } +} diff --git a/beacon-light-client/plonky2/circuits/src/main.rs b/beacon-light-client/plonky2/circuits/src/main.rs new file mode 100644 index 000000000..62df128e5 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/main.rs @@ -0,0 +1,8 @@ +mod hash_tree_root; +mod is_valid_merkle_branch; +mod utils; +mod validator_hash_tree_root; + +fn main() { + println!("Hello, world!"); +} diff --git a/beacon-light-client/plonky2/circuits/src/utils.rs b/beacon-light-client/plonky2/circuits/src/utils.rs new file mode 100644 index 000000000..8f89a73c9 --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/utils.rs @@ -0,0 +1,25 @@ +use plonky2_sha256::circuit::array_to_bits; +use sha2::{Sha256, Digest}; + +pub fn hash_values(lhs: [bool; 256], rhs: [bool; 256]) -> [bool; 256] { + let bytes: Vec = [lhs, rhs] + .concat() + .chunks(8) + .map(|chunk| { + let mut byte = 0u8; + for (i, &bit) in chunk.iter().enumerate() { + if bit { + byte |= 1u8 << (7 - i); + } + } + byte + }) + .collect(); + + let mut hasher = Sha256::default(); + hasher.update(&bytes); + + let finalized = hasher.finalize(); + + array_to_bits(finalized.as_slice()).try_into()?; +} diff --git a/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs new file mode 100644 index 000000000..03cabfbda --- /dev/null +++ b/beacon-light-client/plonky2/circuits/src/validator_hash_tree_root.rs @@ -0,0 +1,37 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::{array_to_bits, make_circuits, Sha256Targets}; + +pub struct Validator { + pubkey: [bool; 256], + withdrawal_credentials: [bool; 256], + effective_balance: [bool; 256], + slashed: [bool; 256], + activation_eligibility_epoch: [bool; 256], + activation_epoch: [bool; 256], + exit_epoch: [bool; 256], + withdrawable_epoch: [bool; 256], +} + + +pub fn hash_tree_root_validator_sha256, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + validator: &Validator, +) { + let hasher = make_circuits(builder, 512); + + for i in 0..256 { + pw.set_bool_target(hasher.message[i], validator.pubkey[i]); + } + + for i in 0..256 { + pw.set_bool_target(hasher.message[i + 256], validator.withdrawal_credentials[i]); + } + + +} diff --git a/beacon-light-client/plonky2/tsconfig.json b/beacon-light-client/plonky2/tsconfig.json new file mode 100644 index 000000000..3c326b5ba --- /dev/null +++ b/beacon-light-client/plonky2/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "files": [ + "./hardhat.config.ts" + ], + "compilerOptions": { + "moduleResolution": "nodenext" + } +} diff --git a/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs b/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs new file mode 100644 index 000000000..3cd2d07ff --- /dev/null +++ b/beacon-light-client/plonky2/validator_hash_tree_root/src/hash_tree_root.rs @@ -0,0 +1,26 @@ +use plonky2::{ + field::extension::Extendable, + hash::hash_types::RichField, + iop::witness::{PartialWitness, WitnessWrite}, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_sha256::circuit::make_circuits; + +pub fn hash_tree_root, const D: usize>( + builder: &mut CircuitBuilder, + pw: &mut PartialWitness, + leaves: &Vec<[bool; 256]>, +) { + let + for i in 0..leaves.len() - 1 { + let hasher = make_circuits(builder, 512); + + for j in 0..256 { + pw.set_bool_target(hasher.message[i], leaves[i][j]); + } + + for j in 0..256 { + pw.set_bool_target(hasher.message[i + 256], leaves[i + 1][j]); + } + } +} diff --git a/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts new file mode 100644 index 000000000..175be1885 --- /dev/null +++ b/beacon-light-client/plonky2/validators_commitment_mapper_tree/get_changed_validators.ts @@ -0,0 +1,94 @@ +import { writeFileSync, readFileSync, existsSync } from 'fs'; +import { sleep } from '../../../libs/typescript/ts-utils/common-utils'; + +(async () => { + const { ssz } = await import('@lodestar/types'); + + let prevSlot = 0; + + while (true) { + const beaconStateSZZ = await fetch( + `https://floral-chaotic-sea.discover.quiknode.pro/c1133f4fcc19bbe54fa6e4caf0c05ac79ec7d300/eth/v2/debug/beacon/states/head`, + { + headers: { + Accept: 'application/octet-stream', + }, + }, + ) + .then(response => response.arrayBuffer()) + .then(buffer => new Uint8Array(buffer)); + + const beaconState = ssz.capella.BeaconState.deserialize(beaconStateSZZ); + + if (!existsSync('prev_beacon_state.ssz')) { + console.log('prev_beacon_state.ssz does not exist. Creating it.'); + + prevSlot = beaconState.slot; + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + await sleep(384000); + continue; + } + + console.log(beaconState.slot); + + if (prevSlot >= beaconState.slot) { + console.log('Waiting for the next epoch.'); + await sleep(384000); + continue; + } + + const prevBeaconStateSSZ = new Uint8Array( + readFileSync('prev_beacon_state.ssz'), + ); + + const prevBeaconState = + ssz.capella.BeaconState.deserialize(prevBeaconStateSSZ); + + const validators = beaconState.validators; + const prevValidators = prevBeaconState.validators; + + const validatorsWithIndies = validators.map((validator, index) => ({ + validator, + index, + })); + + const changedValidators = validatorsWithIndies.filter( + ({ validator, index }) => + prevValidators[index] === undefined || + validator.pubkey.some( + (byte, i) => byte !== prevValidators[index].pubkey[i], + ) || + validator.withdrawalCredentials.some( + (byte, i) => byte !== prevValidators[index].withdrawalCredentials[i], + ) || + validator.effectiveBalance !== prevValidators[index].effectiveBalance || + validator.slashed !== prevValidators[index].slashed || + validator.activationEligibilityEpoch !== + prevValidators[index].activationEligibilityEpoch || + validator.activationEpoch !== prevValidators[index].activationEpoch || + validator.exitEpoch !== prevValidators[index].exitEpoch || + validator.withdrawableEpoch !== prevValidators[index].withdrawableEpoch, + ); + + // TODO: push the changed validators to the tree + + console.log('#changedValidators', changedValidators.length); + + writeFileSync( + 'prev_beacon_state.ssz', + Buffer.from(beaconStateSZZ), + 'binary', + ); + + prevSlot = beaconState.slot; + + // wait for the next epoch + await sleep(384000); + } +})();