Skip to content

Commit

Permalink
Add proof to validation request
Browse files Browse the repository at this point in the history
Signed-off-by: cyc60 <[email protected]>
  • Loading branch information
cyc60 committed Aug 24, 2023
1 parent ca2b878 commit afd6b5e
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 56 deletions.
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

0 comments on commit afd6b5e

Please sign in to comment.