Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add proof to validation request #151

Merged
merged 1 commit into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 9 additions & 41 deletions src/validators/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,8 @@
from typing import Set

from eth_typing import BlockNumber, HexStr
from multiproof import StandardMerkleTree
from sw_utils import (
EventProcessor,
compute_deposit_data,
get_eth1_withdrawal_credentials,
is_valid_deposit_data_signature,
)
from multiproof.standart import MultiProof
from sw_utils import EventProcessor, is_valid_deposit_data_signature
from sw_utils.typings import Bytes32
from web3 import Web3
from web3.types import EventData, Wei
Expand All @@ -23,7 +18,7 @@
from src.common.ipfs import fetch_harvest_params
from src.common.metrics import metrics
from src.config.networks import ETH_NETWORKS
from src.config.settings import DEPOSIT_AMOUNT, DEPOSIT_AMOUNT_GWEI, settings
from src.config.settings import DEPOSIT_AMOUNT, settings
from src.validators.database import NetworkValidatorCrud
from src.validators.typings import (
DepositData,
Expand Down Expand Up @@ -222,29 +217,25 @@ async def update_unused_validator_keys_metric(


async def register_single_validator(
tree: StandardMerkleTree,
validator: Validator,
approval: OraclesApproval,
multi_proof: MultiProof,
tx_validators: list[bytes],
update_state_call: HexStr | None,
validators_registry_root: Bytes32,
) -> None:
"""Registers single validator."""
if settings.network not in ETH_NETWORKS:
raise NotImplementedError('networks other than Ethereum not supported')

credentials = get_eth1_withdrawal_credentials(settings.vault)
tx_validator = _encode_tx_validator(credentials, validator)
proof = tree.get_proof([tx_validator, validator.deposit_data_index])

logger.info('Submitting registration transaction')
register_call_args = [
(
validators_registry_root,
tx_validator,
tx_validators[0],
approval.signatures,
approval.ipfs_hash,
),
proof,
multi_proof.proof,
]
if update_state_call is not None:
register_call = vault_contract.encodeABI(
Expand All @@ -259,10 +250,9 @@ async def register_single_validator(
await execution_client.eth.wait_for_transaction_receipt(tx, timeout=300)


# pylint: disable-next=too-many-locals
async def register_multiple_validator(
tree: StandardMerkleTree,
validators: list[Validator],
multi_proof: MultiProof,
tx_validators: list[bytes],
approval: OraclesApproval,
update_state_call: HexStr | None,
validators_registry_root: Bytes32,
Expand All @@ -271,18 +261,8 @@ async def register_multiple_validator(
if settings.network not in ETH_NETWORKS:
raise NotImplementedError('networks other than Ethereum not supported')

credentials = get_eth1_withdrawal_credentials(settings.vault)
tx_validators: list[bytes] = []
leaves: list[tuple[bytes, int]] = []
for validator in validators:
tx_validator = _encode_tx_validator(credentials, validator)
tx_validators.append(tx_validator)
leaves.append((tx_validator, validator.deposit_data_index))

multi_proof = tree.get_multi_proof(leaves)
sorted_tx_validators: list[bytes] = [v[0] for v in multi_proof.leaves]
indexes = [sorted_tx_validators.index(v) for v in tx_validators]

logger.info('Submitting registration transaction')
register_call_args = [
(
Expand All @@ -306,15 +286,3 @@ async def register_multiple_validator(

logger.info('Waiting for transaction %s confirmation', Web3.to_hex(tx))
await execution_client.eth.wait_for_transaction_receipt(tx, timeout=300)


def _encode_tx_validator(withdrawal_credentials: bytes, validator: Validator) -> bytes:
public_key = Web3.to_bytes(hexstr=validator.public_key)
signature = Web3.to_bytes(hexstr=validator.signature)
deposit_root = compute_deposit_data(
public_key=public_key,
withdrawal_credentials=withdrawal_credentials,
amount_gwei=DEPOSIT_AMOUNT_GWEI,
signature=signature,
).hash_tree_root
return public_key + signature + deposit_root
37 changes: 34 additions & 3 deletions src/validators/signing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@
import milagro_bls_binding as bls
from Cryptodome.Random.random import randint
from eth_typing import HexStr
from multiproof import StandardMerkleTree
from multiproof.standart import MultiProof
from py_ecc.optimized_bls12_381.optimized_curve import curve_order
from sw_utils.signing import get_exit_message_signing_root
from sw_utils import get_eth1_withdrawal_credentials
from sw_utils.signing import compute_deposit_data, get_exit_message_signing_root
from sw_utils.typings import ConsensusFork
from web3 import Web3

from src.common.typings import Oracles
from src.config.settings import settings
from src.validators.typings import BLSPrivkey, ExitSignatureShards
from src.config.settings import DEPOSIT_AMOUNT_GWEI, settings
from src.validators.typings import BLSPrivkey, ExitSignatureShards, Validator


def get_polynomial_points(coefficients: list[int], num_points: int) -> list[bytes]:
Expand Down Expand Up @@ -60,3 +63,31 @@ def get_exit_signature_shards(
public_keys=[Web3.to_hex(bls.SkToPk(priv_key)) for priv_key in private_keys],
exit_signatures=exit_signature_shards,
)


def get_validators_proof(
tree: StandardMerkleTree,
validators: list[Validator],
) -> tuple[list[bytes], MultiProof]:
credentials = get_eth1_withdrawal_credentials(settings.vault)
tx_validators: list[bytes] = []
leaves: list[tuple[bytes, int]] = []
for validator in validators:
tx_validator = encode_tx_validator(credentials, validator)
tx_validators.append(tx_validator)
leaves.append((tx_validator, validator.deposit_data_index))

multi_proof = tree.get_multi_proof(leaves)
return tx_validators, multi_proof


def encode_tx_validator(withdrawal_credentials: bytes, validator: Validator) -> bytes:
public_key = Web3.to_bytes(hexstr=validator.public_key)
signature = Web3.to_bytes(hexstr=validator.signature)
deposit_root = compute_deposit_data(
public_key=public_key,
withdrawal_credentials=withdrawal_credentials,
amount_gwei=DEPOSIT_AMOUNT_GWEI,
signature=signature,
).hash_tree_root
return public_key + signature + deposit_root
26 changes: 19 additions & 7 deletions src/validators/tasks.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging

from multiproof.standart import MultiProof
from sw_utils.typings import Bytes32
from web3 import Web3
from web3.types import BlockNumber, Wei
Expand All @@ -20,7 +21,7 @@
register_multiple_validator,
register_single_validator,
)
from src.validators.signing import get_exit_signature_shards
from src.validators.signing import get_exit_signature_shards, get_validators_proof
from src.validators.typings import (
ApprovalRequest,
DepositData,
Expand All @@ -34,6 +35,7 @@
logger = logging.getLogger(__name__)


# pylint: disable-next=too-many-locals
async def register_validators(keystores: Keystores, deposit_data: DepositData) -> None:
"""Registers vault validators."""
vault_balance, update_state_call = await get_withdrawable_assets()
Expand Down Expand Up @@ -71,8 +73,11 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) -
)
return

tx_validators, multi_proof = get_validators_proof(
tree=deposit_data.tree,
validators=validators,
)
registry_root = None

while True:
latest_registry_root = await validators_registry_contract.get_registry_root()

Expand All @@ -85,6 +90,7 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) -
oracles=oracles,
keystores=keystores,
validators=validators,
multi_proof=multi_proof,
)

try:
Expand All @@ -96,19 +102,19 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) -
if len(validators) == 1:
validator = validators[0]
await register_single_validator(
tree=deposit_data.tree,
validator=validator,
approval=oracles_approval,
multi_proof=multi_proof,
tx_validators=tx_validators,
update_state_call=update_state_call,
validators_registry_root=registry_root,
)
logger.info('Successfully registered validator with public key %s', validator.public_key)

if len(validators) > 1:
await register_multiple_validator(
tree=deposit_data.tree,
validators=validators,
approval=oracles_approval,
multi_proof=multi_proof,
tx_validators=tx_validators,
update_state_call=update_state_call,
validators_registry_root=registry_root,
)
Expand All @@ -117,7 +123,11 @@ async def register_validators(keystores: Keystores, deposit_data: DepositData) -


async def create_approval_request(
oracles: Oracles, keystores: Keystores, validators: list[Validator], registry_root: Bytes32
oracles: Oracles,
keystores: Keystores,
validators: list[Validator],
registry_root: Bytes32,
multi_proof: MultiProof,
) -> ApprovalRequest:
"""Generate validator registration request data"""

Expand All @@ -139,6 +149,8 @@ async def create_approval_request(
deposit_signatures=[],
public_key_shards=[],
exit_signature_shards=[],
proof=multi_proof.proof,
proof_flags=multi_proof.proof_flags,
)
for validator in validators:
shards = get_exit_signature_shards(
Expand Down
2 changes: 2 additions & 0 deletions src/validators/typings.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class ApprovalRequest:
deposit_signatures: list[HexStr]
public_key_shards: list[list[HexStr]]
exit_signature_shards: list[list[HexStr]]
proof: list[HexStr]
proof_flags: list[bool]


@dataclass
Expand Down
8 changes: 3 additions & 5 deletions src/validators/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,8 @@
RegistryRootChangedError,
ValidatorIndexChangedError,
)
from src.validators.execution import (
_encode_tx_validator,
get_latest_network_validator_public_keys,
)
from src.validators.execution import get_latest_network_validator_public_keys
from src.validators.signing import encode_tx_validator
from src.validators.typings import (
ApprovalRequest,
BLSPrivkey,
Expand Down Expand Up @@ -202,7 +200,7 @@ def load_deposit_data(vault: HexAddress, deposit_data_file: Path) -> DepositData
public_key=add_0x_prefix(data['pubkey']),
signature=add_0x_prefix(data['signature']),
)
leaves.append((_encode_tx_validator(credentials, validator), i))
leaves.append((encode_tx_validator(credentials, validator), i))
validators.append(validator)

tree = StandardMerkleTree.of(leaves, ['bytes', 'uint256'])
Expand Down