def verify_deposit(deposit_data_dict: Dict[str, Any]) -> bool: ''' Checks whether a deposit is valid based on the eth2 rules. https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#deposits ''' pubkey = BLSPubkey(bytes.fromhex(deposit_data_dict['pubkey'])) withdrawal_credentials = bytes.fromhex(deposit_data_dict['withdrawal_credentials']) amount = deposit_data_dict['amount'] signature = BLSSignature(bytes.fromhex(deposit_data_dict['signature'])) deposit_data_root = bytes.fromhex(deposit_data_dict['signed_deposit_data_root']) # Verify deposit amount if not MIN_DEPOSIT_AMOUNT < amount <= MAX_DEPOSIT_AMOUNT: return False # Verify deposit signature && pubkey deposit_message = DepositMessage(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount) domain = compute_domain(domain_type=DOMAIN_DEPOSIT) signing_root = compute_signing_root(deposit_message, domain) if not bls.Verify(pubkey, signing_root, signature): return False # Verify Deposit Root deposit = Deposit(pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, signature=signature) return deposit.hash_tree_root == deposit_data_root
def deposit_message(self) -> DepositMessage: if not MIN_DEPOSIT_AMOUNT <= self.amount <= MAX_DEPOSIT_AMOUNT: raise ValidationError( f"{self.amount / ETH2GWEI} ETH deposits are not within the bounds of this cli." ) return DepositMessage( pubkey=self.signing_pk, withdrawal_credentials=self.withdrawal_credentials, amount=self.amount, )
def sign_deposit_data(deposit_data: DepositMessage, sk: int) -> Deposit: ''' Given a DepositMessage, it signs its root and returns a Deposit ''' assert bls.PrivToPub(sk) == deposit_data.pubkey domain = compute_domain() signing_root = compute_signing_root(deposit_data, domain) signed_deposit_data = Deposit(**deposit_data.as_dict(), signature=bls.Sign(sk, signing_root)) return signed_deposit_data
def test_compute_signing_root(domain, valid, result): deposit_message = DepositMessage( pubkey=b'\x12' * 48, withdrawal_credentials=b'\x12' * 32, amount=100, ) if valid: assert compute_signing_root(deposit_message, domain) == result else: with pytest.raises(ValueError): compute_signing_root(deposit_message, domain)
def export_deposit_data_json(*, credentials: List[ValidatorCredentials], folder: str): deposit_data: List[dict] = [] for credential in credentials: deposit_datum = DepositMessage( pubkey=credential.signing_pk, withdrawal_credentials=SHA256(credential.withdrawal_pk), amount=credential.amount, ) signed_deposit_datum = sign_deposit_data(deposit_datum, credential.signing_sk) datum_dict = signed_deposit_datum.as_dict() datum_dict.update({'deposit_data_root': deposit_datum.hash_tree_root}) datum_dict.update( {'signed_deposit_data_root': signed_deposit_datum.hash_tree_root}) deposit_data.append(datum_dict) filefolder = os.path.join(folder, 'deposit_data-%i.json' % time.time()) with open(filefolder, 'w') as f: json.dump(deposit_data, f, default=lambda x: x.hex()) return filefolder
def validate_deposit(deposit_data_dict: Dict[str, Any], credential: Credential) -> bool: ''' Checks whether a deposit is valid based on the eth2 rules. https://github.com/ethereum/eth2.0-specs/blob/dev/specs/phase0/beacon-chain.md#deposits ''' pubkey = BLSPubkey(bytes.fromhex(deposit_data_dict['pubkey'])) withdrawal_credentials = bytes.fromhex( deposit_data_dict['withdrawal_credentials']) amount = deposit_data_dict['amount'] signature = BLSSignature(bytes.fromhex(deposit_data_dict['signature'])) deposit_message_root = bytes.fromhex( deposit_data_dict['deposit_data_root']) fork_version = bytes.fromhex(deposit_data_dict['fork_version']) # Verify pubkey if len(pubkey) != 48: return False if pubkey != credential.signing_pk: return False # Verify withdrawal credential if len(withdrawal_credentials) != 32: return False if withdrawal_credentials[: 1] == BLS_WITHDRAWAL_PREFIX == credential.withdrawal_prefix: if withdrawal_credentials[1:] != SHA256(credential.withdrawal_pk)[1:]: return False elif withdrawal_credentials[: 1] == ETH1_ADDRESS_WITHDRAWAL_PREFIX == credential.withdrawal_prefix: if withdrawal_credentials[1:12] != b'\x00' * 11: return False if credential.eth1_withdrawal_address is None: return False if withdrawal_credentials[12:] != credential.eth1_withdrawal_address: return False else: return False # Verify deposit amount if not MIN_DEPOSIT_AMOUNT < amount <= MAX_DEPOSIT_AMOUNT: return False # Verify deposit signature && pubkey deposit_message = DepositMessage( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount) domain = compute_deposit_domain(fork_version) signing_root = compute_signing_root(deposit_message, domain) if not bls.Verify(pubkey, signing_root, signature): return False # Verify Deposit Root signed_deposit = DepositData( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount, signature=signature, ) return signed_deposit.hash_tree_root == deposit_message_root
def deposit_message(self) -> DepositMessage: return DepositMessage( pubkey=self.signing_pk, withdrawal_credentials=self.withdrawal_credentials, amount=self.amount, )