async def add_full_block(self, block: FullBlock, sub_block: SubBlockRecord) -> None: cursor_1 = await self.db.execute( "INSERT OR REPLACE INTO full_blocks VALUES(?, ?, ?, ?, ?)", ( block.header_hash.hex(), sub_block.height, block.sub_block_height, int(block.is_block()), bytes(block), ), ) await cursor_1.close() cursor_2 = await self.db.execute( "INSERT OR REPLACE INTO sub_block_records VALUES(?, ?, ?, ?, ?, ?)", ( block.header_hash.hex(), block.prev_header_hash.hex(), block.sub_block_height, bytes(sub_block), False, block.is_block(), ), ) await cursor_2.close() await self.db.commit()
async def add_full_block(self, block: FullBlock, sub_block: SubBlockRecord) -> None: self.block_cache.put(block.header_hash, block) cursor_1 = await self.db.execute( "INSERT OR REPLACE INTO full_blocks VALUES(?, ?, ?, ?)", ( block.header_hash.hex(), block.height, int(block.is_block()), bytes(block), ), ) await cursor_1.close() cursor_2 = await self.db.execute( "INSERT OR REPLACE INTO block_records VALUES(?, ?, ?, ?,?, ?, ?)", ( block.header_hash.hex(), block.prev_header_hash.hex(), block.height, bytes(sub_block), None if sub_block.sub_epoch_summary_included is None else bytes(sub_block.sub_epoch_summary_included), False, block.is_block(), ), ) await cursor_2.close() await self.db.commit()
def get_future_reward_coins(block: FullBlock) -> Tuple[Coin, Coin]: pool_amount = calculate_pool_reward(block.height) farmer_amount = calculate_base_farmer_reward(block.height) if block.is_block(): assert block.transactions_info is not None farmer_amount = uint64(farmer_amount + block.transactions_info.fees) pool_coin: Coin = create_pool_coin( block.height, block.foliage_sub_block.foliage_sub_block_data.pool_target.puzzle_hash, pool_amount, ) farmer_coin: Coin = create_farmer_coin( block.height, block.foliage_sub_block.foliage_sub_block_data.farmer_reward_puzzle_hash, farmer_amount, ) return pool_coin, farmer_coin
async def new_block(self, block: FullBlock): """ Only called for sub-blocks which are blocks (and thus have rewards and transactions) """ if block.is_block() is False: return assert block.foliage_block is not None removals, additions = block.tx_removals_and_additions() for coin in additions: record: CoinRecord = CoinRecord( coin, block.height, uint32(0), False, False, block.foliage_block.timestamp, ) await self._add_coin_record(record) for coin_name in removals: await self._set_spent(coin_name, block.height) included_reward_coins = block.get_included_reward_coins() if block.height == 0: assert len(included_reward_coins) == 0 else: assert len(included_reward_coins) >= 2 for coin in included_reward_coins: reward_coin_r: CoinRecord = CoinRecord( coin, block.height, uint32(0), False, True, block.foliage_block.timestamp, ) await self._add_coin_record(reward_coin_r)
async def receive_block( self, block: FullBlock, pre_validation_result: Optional[PreValidationResult] = None, ) -> Tuple[ReceiveBlockResult, Optional[Err], Optional[uint32]]: """ This method must be called under the blockchain lock Adds a new block into the blockchain, if it's valid and connected to the current blockchain, regardless of whether it is the child of a head, or another block. Returns a header if block is added to head. Returns an error if the block is invalid. Also returns the fork height, in the case of a new peak. """ genesis: bool = block.sub_block_height == 0 if block.header_hash in self.sub_blocks: return ReceiveBlockResult.ALREADY_HAVE_BLOCK, None, None if block.prev_header_hash not in self.sub_blocks and not genesis: return ( ReceiveBlockResult.DISCONNECTED_BLOCK, Err.INVALID_PREV_BLOCK_HASH, None, ) if pre_validation_result is None: if block.sub_block_height == 0: prev_sb: Optional[SubBlockRecord] = None else: prev_sb = self.sub_blocks[block.prev_header_hash] sub_slot_iters, difficulty = get_sub_slot_iters_and_difficulty( self.constants, block, self.sub_height_to_hash, prev_sb, self.sub_blocks) required_iters, error = validate_finished_header_block( self.constants, self.sub_blocks, block.get_block_header(), False, difficulty, sub_slot_iters, ) if error is not None: return ReceiveBlockResult.INVALID_BLOCK, error.code, None else: required_iters = pre_validation_result.required_iters assert pre_validation_result.error is None assert required_iters is not None error_code = await validate_block_body( self.constants, self.sub_blocks, self.sub_height_to_hash, self.block_store, self.coin_store, self.get_peak(), block, block.sub_block_height, block.height if block.is_block() else None, pre_validation_result.cost_result if pre_validation_result is not None else None, ) if error_code is not None: return ReceiveBlockResult.INVALID_BLOCK, error_code, None sub_block = block_to_sub_block_record( self.constants, self.sub_blocks, self.sub_height_to_hash, required_iters, block, None, ) # Always add the block to the database await self.block_store.add_full_block(block, sub_block) self.sub_blocks[sub_block.header_hash] = sub_block fork_height: Optional[uint32] = await self._reconsider_peak( sub_block, genesis) if fork_height is not None: return ReceiveBlockResult.NEW_PEAK, None, fork_height else: return ReceiveBlockResult.ADDED_AS_ORPHAN, None, None