def _get_deposit(self, deposit_count: int, deposit_index: int) -> Deposit: """ Return `Deposit` according to `deposit_count` and `deposit_index`. It should include the deposit data at the `deposit_index`, and the merkle proof of the corresponding merkle tree made from deposit data of size `deposit_count`. """ if deposit_index >= deposit_count: raise Eth1MonitorValidationError( "`deposit_index` should be smaller than `deposit_count`: " f"deposit_index={deposit_index}, deposit_count={deposit_count}" ) len_deposit_data = self.total_deposit_count if deposit_count <= 0 or deposit_count > len_deposit_data: raise Eth1MonitorValidationError( f"invalid `deposit_count`: deposit_count={deposit_count}") if deposit_index < 0 or deposit_index >= len_deposit_data: raise Eth1MonitorValidationError( f"invalid `deposit_index`: deposit_index={deposit_index}") deposit_data_in_range = self._db.get_deposit_data_range( 0, deposit_count) tree, root = make_deposit_tree_and_root(deposit_data_in_range) return Deposit( proof=make_deposit_proof(deposit_data_in_range, tree, root, deposit_index), data=self._db.get_deposit_data(deposit_index), )
def _get_eth1_data( self, distance: BlockNumber, eth1_voting_period_start_timestamp: Timestamp) -> Eth1Data: """ Return `Eth1Data` at `distance` relative to the eth1 block earlier and closest to the timestamp `eth1_voting_period_start_timestamp`. Ref: https://github.com/ethereum/eth2.0-specs/blob/61f2a0662ebcfb4c097360cc1835c5f01872705c/specs/validator/0_beacon-chain-validator.md#eth1-data # noqa: E501 First, we find the `eth1_block` whose timestamp is the largest timestamp which is smaller than `eth1_voting_period_start_timestamp`. Then, find the block `target_block` at number `eth1_block.number - distance`. Therefore, we can return `Eth1Data` according to the information of this block. """ eth1_voting_period_start_block_number = self._get_closest_eth1_voting_period_start_block( eth1_voting_period_start_timestamp) target_block_number = BlockNumber( eth1_voting_period_start_block_number - distance) if target_block_number < 0: raise Eth1MonitorValidationError( f"`distance` is larger than `eth1_voting_period_start_block_number`: " f"`distance`={distance}, ", f"eth1_voting_period_start_block_number={eth1_voting_period_start_block_number}", ) try: block = self._eth1_data_provider.get_block(target_block_number) except BlockNotFound: raise Eth1MonitorValidationError( f"Block does not exist for block number={target_block_number}") block_hash = block.block_hash # `Eth1Data.deposit_count`: get the `deposit_count` corresponding to the block. accumulated_deposit_count = self._get_accumulated_deposit_count( target_block_number) if accumulated_deposit_count == 0: raise Eth1MonitorValidationError( f"failed to make `Eth1Data`: `deposit_count = 0` at block #{target_block_number}" ) # Verify that the deposit data in db and the deposit data in contract match deposit_data_in_range = self._db.get_deposit_data_range( 0, accumulated_deposit_count) _, deposit_root = make_deposit_tree_and_root(deposit_data_in_range) contract_deposit_root = self._get_deposit_root_from_contract( target_block_number) if contract_deposit_root != deposit_root: raise DepositDataCorrupted( "deposit root built locally mismatches the one in the contract on chain: " f"contract_deposit_root={contract_deposit_root.hex()}, " f"deposit_root={deposit_root.hex()}") return Eth1Data.create( deposit_root=deposit_root, deposit_count=accumulated_deposit_count, block_hash=block_hash, )
def get_deposit_root(self, block_number: BlockNumber) -> Hash32: # Check and update deposit data when deposit root is requested if self.latest_processed_block_number < block_number: for blk_number in range(self.latest_processed_block_number + 1, block_number + 1): deposit_logs = self.get_logs(BlockNumber(blk_number)) self.deposits += tuple( convert_deposit_log_to_deposit_data(deposit_log) for deposit_log in deposit_logs ) self.latest_processed_block_number = block_number deposit_count_bytes = self.get_deposit_count(block_number) deposit_count = int.from_bytes(deposit_count_bytes, byteorder='little') deposits = self.deposits[:deposit_count] _, deposit_root = make_deposit_tree_and_root(deposits) return deposit_root