diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1860fc7f..b200ef55 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -82,3 +82,11 @@ repos: files: no-files args: ["lock", "--check"] always_run: true + + - repo: https://github.com/jendrikseipp/vulture + rev: 'v2.13' + hooks: + - id: vulture + args: ["src/"] + files: no-files + always_run: true diff --git a/poetry.lock b/poetry.lock index 40f6f9b0..bca0f8c8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2563,6 +2563,7 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -2570,8 +2571,16 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -2588,6 +2597,7 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -2595,6 +2605,7 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, diff --git a/pyproject.toml b/pyproject.toml index 45f6c646..24d8d27e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -112,7 +112,20 @@ exclude = ''' ''' [tool.coverage.report] -fail_under = 70 +omit = ["*/tests/*"] +fail_under = 66 [tool.pytest.ini_options] asyncio_mode = "auto" + +[tool.vulture] +exclude = ["*/test*", "conftest.py", "networks.py"] +ignore_names = [ + "default_account", # execution client + "_async_session_pool", # credentials.py + "eth_typing_metadata", "ssz_metadata", # pyinstaller + "DATA_DIR", # settings + "contract_event", "get_from_block", "process_events", # event processor + "validators_root", # ApprovalRequest + "previous_version", "current_version", "genesis_validators_root", "fork_info", "voluntary_exit" # remote.py +] diff --git a/src/common/contracts.py b/src/common/contracts.py index ccdaa4e2..435138c8 100644 --- a/src/common/contracts.py +++ b/src/common/contracts.py @@ -245,14 +245,6 @@ async def get_exit_signatures_updated_event( return last_event - async def get_rewards_min_oracles(self) -> int: - """Fetches the last oracles config updated event.""" - return await self.contract.functions.rewardsMinOracles().call() - - async def get_validators_min_oracles(self) -> int: - """Fetches the last oracles config updated event.""" - return await self.contract.functions.validatorsMinOracles().call() - async def can_harvest(self, vault_address: ChecksumAddress) -> bool: return await self.contract.functions.canHarvest(vault_address).call() @@ -261,10 +253,6 @@ class DepositDataRegistryContract(ContractWrapper): abi_path = 'abi/IDepositDataRegistry.json' settings_key = 'DEPOSIT_DATA_REGISTRY_CONTRACT_ADDRESS' - async def get_deposit_data_manager(self) -> ChecksumAddress: - """Fetches the vault deposit data manager address.""" - return await self.contract.functions.getDepositDataManager(settings.vault).call() - async def get_validators_root(self) -> Bytes32: """Fetches vault's validators root.""" return await self.contract.functions.depositDataRoots(settings.vault).call() diff --git a/src/validators/signing/key_shares.py b/src/validators/signing/key_shares.py index 16d2f339..aa4e5160 100644 --- a/src/validators/signing/key_shares.py +++ b/src/validators/signing/key_shares.py @@ -13,38 +13,13 @@ from py_ecc.optimized_bls12_381.optimized_curve import ( G1 as P1, # don't confuse group name (G1) with primitive element name (P1) ) -from py_ecc.optimized_bls12_381.optimized_curve import ( - Z1, - Z2, - add, - curve_order, - multiply, -) +from py_ecc.optimized_bls12_381.optimized_curve import add, curve_order, multiply from py_ecc.typing import Optimized_Field, Optimized_Point3D -from py_ecc.utils import prime_field_inv - -from src.validators.typings import BLSPrivkey # element of G1 or G2 G12: TypeAlias = Optimized_Point3D[Optimized_Field] -def get_polynomial_points(coefficients: list[int], num_points: int) -> list[int]: - """Calculates polynomial points.""" - points = [] - for x in range(1, num_points + 1): - # start with x=1 and calculate the value of y - y = coefficients[0] - # calculate each term and add it to y, using modular math - for i in range(1, len(coefficients)): - exponentiation = (x**i) % curve_order - term = (coefficients[i] * exponentiation) % curve_order - y = (y + term) % curve_order - # add the point to the list of points - points.append(y) - return points - - def get_G12_polynomial_points(coefficients: list, num_points: int) -> list: """Calculates polynomial points in G1 or G2.""" points = [] @@ -62,21 +37,6 @@ def get_G12_polynomial_points(coefficients: list, num_points: int) -> list: return points -def private_key_to_private_key_shares( - private_key: BLSPrivkey, - threshold: int, - total: int, -) -> list[BLSPrivkey]: - coefficients: list[int] = [int.from_bytes(private_key, 'big')] - - for _ in range(threshold - 1): - coefficients.append(secrets.randbelow(curve_order)) - - points = get_polynomial_points(coefficients, total) - - return [BLSPrivkey(p.to_bytes(32, 'big')) for p in points] - - def bls_signature_to_shares( bls_signature: BLSSignature, coefficients_G2: list[G12], @@ -121,31 +81,3 @@ def bls_signature_and_public_key_to_shares( public_key_shards = bls_public_key_to_shares(public_key, coefficients_G1, total) return bls_signature_shards, public_key_shards - - -def reconstruct_shared_bls_signature(signatures: dict[int, BLSSignature]) -> BLSSignature: - """ - Reconstructs shared BLS private key signature. - Copied from https://github.com/dankrad/python-ibft/blob/master/bls_threshold.py - """ - r = Z2 - for i, sig in signatures.items(): - sig_point = signature_to_G2(sig) - coef = 1 - for j in signatures: - if j != i: - coef = -coef * (j + 1) * prime_field_inv(i - j, curve_order) % curve_order - r = add(r, multiply(sig_point, coef)) - return G2_to_signature(r) - - -def get_aggregate_key(keyshares: dict[int, BLSPubkey]) -> BLSPubkey: - r = Z1 - for i, key in keyshares.items(): - key_point = pubkey_to_G1(key) - coef = 1 - for j in keyshares: - if j != i: - coef = -coef * (j + 1) * prime_field_inv(i - j, curve_order) % curve_order - r = add(r, multiply(key_point, coef)) - return G1_to_pubkey(r) diff --git a/src/validators/signing/tests/key_shares.py b/src/validators/signing/tests/key_shares.py new file mode 100644 index 00000000..bc4f5869 --- /dev/null +++ b/src/validators/signing/tests/key_shares.py @@ -0,0 +1,37 @@ +from eth_typing import BLSPubkey, BLSSignature +from py_ecc.bls.g2_primitives import ( + G1_to_pubkey, + G2_to_signature, + pubkey_to_G1, + signature_to_G2, +) +from py_ecc.optimized_bls12_381 import Z1, Z2, add, curve_order, multiply +from py_ecc.utils import prime_field_inv + + +def reconstruct_shared_bls_signature(signatures: dict[int, BLSSignature]) -> BLSSignature: + """ + Reconstructs shared BLS private key signature. + Copied from https://github.com/dankrad/python-ibft/blob/master/bls_threshold.py + """ + r = Z2 + for i, sig in signatures.items(): + sig_point = signature_to_G2(sig) + coef = 1 + for j in signatures: + if j != i: + coef = -coef * (j + 1) * prime_field_inv(i - j, curve_order) % curve_order + r = add(r, multiply(sig_point, coef)) + return G2_to_signature(r) + + +def get_aggregate_key(keyshares: dict[int, BLSPubkey]) -> BLSPubkey: + r = Z1 + for i, key in keyshares.items(): + key_point = pubkey_to_G1(key) + coef = 1 + for j in keyshares: + if j != i: + coef = -coef * (j + 1) * prime_field_inv(i - j, curve_order) % curve_order + r = add(r, multiply(key_point, coef)) + return G1_to_pubkey(r) diff --git a/src/validators/signing/tests/oracle_functions.py b/src/validators/signing/tests/oracle_functions.py index 2d239e07..c679d963 100644 --- a/src/validators/signing/tests/oracle_functions.py +++ b/src/validators/signing/tests/oracle_functions.py @@ -8,7 +8,7 @@ from web3 import Web3 from src.config.settings import settings -from src.validators.signing.key_shares import ( +from src.validators.signing.tests.key_shares import ( get_aggregate_key, reconstruct_shared_bls_signature, ) diff --git a/src/validators/typings.py b/src/validators/typings.py index caa6a439..46952025 100644 --- a/src/validators/typings.py +++ b/src/validators/typings.py @@ -4,7 +4,6 @@ from eth_typing import BlockNumber, BLSSignature, ChecksumAddress, HexStr from multiproof import MultiProof, StandardMerkleTree -from sw_utils.typings import Bytes32 BLSPrivkey = NewType('BLSPrivkey', bytes) @@ -74,14 +73,6 @@ class ApprovalRequest: validators_manager_signature: HexStr | None = None -@dataclass -class KeeperApprovalParams: - validatorsRegistryRoot: HexStr | Bytes32 - validators: HexStr | bytes - signatures: HexStr | bytes - exitSignaturesIpfsHash: str - - class ValidatorsRegistrationMode(Enum): """ AUTO mode: validators are registered automatically when vault assets are enough.