diff --git a/chia/_tests/core/full_node/stores/test_full_node_store.py b/chia/_tests/core/full_node/stores/test_full_node_store.py index 0b245a3fa82b..416eddc5f6c3 100644 --- a/chia/_tests/core/full_node/stores/test_full_node_store.py +++ b/chia/_tests/core/full_node/stores/test_full_node_store.py @@ -24,7 +24,7 @@ from chia.types.blockchain_format.sized_bytes import bytes32 from chia.types.full_block import FullBlock from chia.types.unfinished_block import UnfinishedBlock -from chia.util.block_cache import BlockCache +from chia.util.blockchain_mock import BlockchainMock from chia.util.hash import std_hash from chia.util.ints import uint8, uint16, uint32, uint64, uint128 from chia.util.recursive_replace import recursive_replace @@ -338,7 +338,7 @@ async def test_basic_store( assert ( store.get_finished_sub_slots( - BlockCache({}), + BlockchainMock({}), None, sub_slots[0].challenge_chain.challenge_chain_end_of_slot_vdf.challenge, ) @@ -379,11 +379,12 @@ async def test_basic_store( assert slot_i is not None assert slot_i[0] == sub_slots[i] - assert store.get_finished_sub_slots(BlockCache({}), None, sub_slots[-1].challenge_chain.get_hash()) == sub_slots - assert store.get_finished_sub_slots(BlockCache({}), None, std_hash(b"not a valid hash")) is None + assert store.get_finished_sub_slots(BlockchainMock({}), None, sub_slots[-1].challenge_chain.get_hash()) == sub_slots + assert store.get_finished_sub_slots(BlockchainMock({}), None, std_hash(b"not a valid hash")) is None assert ( - store.get_finished_sub_slots(BlockCache({}), None, sub_slots[-2].challenge_chain.get_hash()) == sub_slots[:-1] + store.get_finished_sub_slots(BlockchainMock({}), None, sub_slots[-2].challenge_chain.get_hash()) + == sub_slots[:-1] ) # Test adding genesis peak @@ -736,7 +737,7 @@ async def test_basic_store( ): sp = get_signage_point( custom_block_tools.constants, - BlockCache({}, {}), + BlockchainMock({}, {}), None, uint128(0), uint8(i), @@ -771,7 +772,7 @@ async def test_basic_store( ): sp = get_signage_point( custom_block_tools.constants, - BlockCache({}, {}), + BlockchainMock({}, {}), None, uint128(slot_offset * peak.sub_slot_iters), uint8(i), diff --git a/chia/_tests/util/blockchain_mock.py b/chia/_tests/util/blockchain_mock.py new file mode 100644 index 000000000000..f32be86f5342 --- /dev/null +++ b/chia/_tests/util/blockchain_mock.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +import logging +from typing import Dict, List, Optional + +from chia.consensus.block_record import BlockRecord +from chia.consensus.blockchain_interface import BlockchainInterface +from chia.types.blockchain_format.sized_bytes import bytes32 +from chia.types.blockchain_format.sub_epoch_summary import SubEpochSummary +from chia.types.header_block import HeaderBlock +from chia.types.weight_proof import SubEpochChallengeSegment, SubEpochSegments +from chia.util.ints import uint32 + + +class BlockchainMock(BlockchainInterface): + def __init__( + self, + blocks: Dict[bytes32, BlockRecord], + headers: Optional[Dict[bytes32, HeaderBlock]] = None, + height_to_hash: Optional[Dict[uint32, bytes32]] = None, + sub_epoch_summaries: Optional[Dict[uint32, SubEpochSummary]] = None, + ): + if sub_epoch_summaries is None: + sub_epoch_summaries = {} + if height_to_hash is None: + height_to_hash = {} + if headers is None: + headers = {} + self._block_records = blocks + self._headers = headers + self._height_to_hash = height_to_hash + self._sub_epoch_summaries = sub_epoch_summaries + self._sub_epoch_segments: Dict[bytes32, SubEpochSegments] = {} + self.log = logging.getLogger(__name__) + + def block_record(self, header_hash: bytes32) -> BlockRecord: + return self._block_records[header_hash] + + def height_to_block_record(self, height: uint32, check_db: bool = False) -> BlockRecord: + # Precondition: height is < peak height + + header_hash: Optional[bytes32] = self.height_to_hash(height) + assert header_hash is not None + + return self.block_record(header_hash) + + def get_ses_heights(self) -> List[uint32]: + return sorted(self._sub_epoch_summaries.keys()) + + def get_ses(self, height: uint32) -> SubEpochSummary: + return self._sub_epoch_summaries[height] + + def height_to_hash(self, height: uint32) -> Optional[bytes32]: + if height not in self._height_to_hash: + self.log.warning(f"could not find height in cache {height}") + return None + return self._height_to_hash[height] + + def contains_block(self, header_hash: bytes32) -> bool: + return header_hash in self._block_records + + async def contains_block_from_db(self, header_hash: bytes32) -> bool: + return header_hash in self._block_records + + def contains_height(self, height: uint32) -> bool: + return height in self._height_to_hash + + async def get_block_records_in_range(self, start: int, stop: int) -> Dict[bytes32, BlockRecord]: + return self._block_records + + async def get_block_records_at(self, heights: List[uint32]) -> List[BlockRecord]: + block_records: List[BlockRecord] = [] + for height in heights: + block_records.append(self.height_to_block_record(height)) + return block_records + + def try_block_record(self, header_hash: bytes32) -> Optional[BlockRecord]: + return self._block_records.get(header_hash) + + async def get_block_record_from_db(self, header_hash: bytes32) -> Optional[BlockRecord]: + return self._block_records[header_hash] + + async def prev_block_hash(self, header_hashes: List[bytes32]) -> List[bytes32]: + ret = [] + for h in header_hashes: + ret.append(self._block_records[h].prev_hash) + return ret + + def remove_block_record(self, header_hash: bytes32) -> None: + del self._block_records[header_hash] + + def add_block_record(self, block: BlockRecord) -> None: + self._block_records[block.header_hash] = block + + async def get_header_blocks_in_range( + self, start: int, stop: int, tx_filter: bool = True + ) -> Dict[bytes32, HeaderBlock]: + return self._headers + + async def persist_sub_epoch_challenge_segments( + self, sub_epoch_summary_hash: bytes32, segments: List[SubEpochChallengeSegment] + ) -> None: + self._sub_epoch_segments[sub_epoch_summary_hash] = SubEpochSegments(segments) + + async def get_sub_epoch_challenge_segments( + self, + sub_epoch_summary_hash: bytes32, + ) -> Optional[List[SubEpochChallengeSegment]]: + segments = self._sub_epoch_segments.get(sub_epoch_summary_hash) + if segments is None: + return None + return segments.challenge_segments diff --git a/chia/_tests/wallet/sync/test_wallet_sync.py b/chia/_tests/wallet/sync/test_wallet_sync.py index f7d9aeae2b3b..eb052c1bd4ed 100644 --- a/chia/_tests/wallet/sync/test_wallet_sync.py +++ b/chia/_tests/wallet/sync/test_wallet_sync.py @@ -39,7 +39,7 @@ from chia.types.full_block import FullBlock from chia.types.peer_info import PeerInfo from chia.util.batches import to_batches -from chia.util.block_cache import BlockCache +from chia.util.blockchain_mock import BlockchainMock from chia.util.hash import std_hash from chia.util.ints import uint32, uint64, uint128 from chia.wallet.nft_wallet.nft_wallet import NFTWallet @@ -646,7 +646,7 @@ async def test_get_wp_fork_point( ) -> None: blocks = default_10000_blocks header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, blockchain_constants) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries)) wp1 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_000)]].header_hash) assert wp1 is not None wp2 = await wpf.get_proof_of_weight(header_cache[height_to_hash[uint32(9_030)]].header_hash) @@ -1410,7 +1410,7 @@ async def test_bad_peak_mismatch( full_node_server = full_node.server blocks = default_1000_blocks header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, blockchain_constants) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries)) await wallet_server.start_client(PeerInfo(self_hostname, full_node_server.get_port()), None) diff --git a/chia/_tests/weight_proof/test_weight_proof.py b/chia/_tests/weight_proof/test_weight_proof.py index bf5403a31886..17b6ea65d1d2 100644 --- a/chia/_tests/weight_proof/test_weight_proof.py +++ b/chia/_tests/weight_proof/test_weight_proof.py @@ -16,7 +16,7 @@ from chia.types.blockchain_format.sub_epoch_summary import SubEpochSummary from chia.types.full_block import FullBlock from chia.types.header_block import HeaderBlock -from chia.util.block_cache import BlockCache +from chia.util.blockchain_mock import BlockchainMock from chia.util.generator_tools import get_block_header from chia.util.ints import uint8, uint32, uint64 @@ -63,7 +63,7 @@ async def load_blocks_dont_validate( sub_block = block_to_block_record( constants, - BlockCache(sub_blocks, height_to_hash=height_to_hash), + BlockchainMock(sub_blocks, height_to_hash=height_to_hash), required_iters, block, None, @@ -93,7 +93,7 @@ async def _test_map_summaries( # next sub block curr = sub_blocks[curr.prev_hash] - wpf = WeightProofHandler(constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler(constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries)) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None @@ -138,7 +138,9 @@ async def test_weight_proof_summaries_1000_blocks( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None summaries_here, sub_epoch_data_weight, _ = _map_sub_epoch_summaries( @@ -158,7 +160,9 @@ async def test_weight_proof_bad_peak_hash( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(bytes32(b"a" * 32)) assert wp is None @@ -171,7 +175,9 @@ async def test_weight_proof_from_genesis( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) @@ -254,10 +260,10 @@ async def test_weight_proof_edge_cases(self, bt: BlockTools, default_400_blocks: blocks = bt.get_consecutive_blocks(300, block_list_input=blocks, seed=b"asdfghjkl", force_overflow=False) header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, bt.constants) - wpf = WeightProofHandler(bt.constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler(bt.constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries)) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(bt.constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler(bt.constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -271,10 +277,12 @@ async def test_weight_proof1000( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -289,10 +297,12 @@ async def test_weight_proof1000_pre_genesis_empty_slots( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -306,10 +316,12 @@ async def test_weight_proof10000__blocks_compact( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -328,10 +340,10 @@ async def test_weight_proof1000_partial_blocks_compact( normalized_to_identity_icc_eos=True, ) header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks, bt.constants) - wpf = WeightProofHandler(bt.constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler(bt.constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries)) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(bt.constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler(bt.constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -345,11 +357,13 @@ async def test_weight_proof10000( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, {}, height_to_hash, {})) + wpf = WeightProofHandler(blockchain_constants, BlockchainMock(sub_blocks, {}, height_to_hash, {})) valid, fork_point = wpf.validate_weight_proof_single_proc(wp) assert valid @@ -363,7 +377,9 @@ async def test_check_num_of_samples( header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate( blocks, blockchain_constants ) - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) wp = await wpf.get_proof_of_weight(blocks[-1].header_hash) assert wp is not None curr = -1 @@ -384,13 +400,13 @@ async def test_weight_proof_extend_no_ses( ) last_ses_height = sorted(summaries.keys())[-1] wpf_synced = WeightProofHandler( - blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries) + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) ) wp = await wpf_synced.get_proof_of_weight(blocks[last_ses_height].header_hash) assert wp is not None # todo for each sampled sub epoch, validate number of segments wpf_not_synced = WeightProofHandler( - blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {}) + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {}) ) valid, fork_point, _ = await wpf_not_synced.validate_weight_proof(wp) assert valid @@ -415,26 +431,28 @@ async def test_weight_proof_extend_new_ses( last_ses = summaries[last_ses_height] del summaries[last_ses_height] wpf_synced = WeightProofHandler( - blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries) + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) ) wp = await wpf_synced.get_proof_of_weight(blocks[last_ses_height - 10].header_hash) assert wp is not None wpf_not_synced = WeightProofHandler( - blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {}) + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {}) ) valid, fork_point, _ = await wpf_not_synced.validate_weight_proof(wp) assert valid assert fork_point == 0 # extend proof with 100 blocks - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) summaries[last_ses_height] = last_ses - wpf_synced.blockchain = BlockCache(sub_blocks, header_cache, height_to_hash, summaries) + wpf_synced.blockchain = BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) new_wp = await wpf_synced._create_proof_of_weight(blocks[-1].header_hash) assert new_wp is not None valid, fork_point, _ = await wpf_not_synced.validate_weight_proof(new_wp) assert valid assert fork_point == 0 - wpf_synced.blockchain = BlockCache(sub_blocks, header_cache, height_to_hash, summaries) + wpf_synced.blockchain = BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) new_wp = await wpf_synced._create_proof_of_weight(blocks[last_ses_height].header_hash) assert new_wp is not None valid, fork_point, _ = await wpf_not_synced.validate_weight_proof(new_wp) @@ -456,8 +474,12 @@ async def test_weight_proof_extend_multiple_ses( last_ses = summaries[last_ses_height] before_last_ses_height = sorted(summaries.keys())[-2] before_last_ses = summaries[before_last_ses_height] - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) - wpf_verify = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {})) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) + wpf_verify = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, {}) + ) for x in range(10, -1, -1): wp = await wpf.get_proof_of_weight(blocks[before_last_ses_height - x].header_hash) assert wp is not None @@ -467,7 +489,9 @@ async def test_weight_proof_extend_multiple_ses( # extend proof with 100 blocks summaries[last_ses_height] = last_ses summaries[before_last_ses_height] = before_last_ses - wpf = WeightProofHandler(blockchain_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries)) + wpf = WeightProofHandler( + blockchain_constants, BlockchainMock(sub_blocks, header_cache, height_to_hash, summaries) + ) new_wp = await wpf._create_proof_of_weight(blocks[-1].header_hash) assert new_wp is not None valid, fork_point, _ = await wpf.validate_weight_proof(new_wp) diff --git a/chia/full_node/weight_proof.py b/chia/full_node/weight_proof.py index e357506765aa..c5fd2b95ad03 100644 --- a/chia/full_node/weight_proof.py +++ b/chia/full_node/weight_proof.py @@ -1249,7 +1249,7 @@ def validate_recent_blocks( prev_block_record = prev_block_record.replace( deficit=uint8(deficit % constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK) ) - sub_blocks.add_block_record(prev_block_record) + sub_blocks.add_block(prev_block_record) adjusted = True deficit = get_deficit(constants, deficit, prev_block_record, overflow, len(block.finished_sub_slots)) if sub_slots > 2 and transaction_blocks > 11 and (tip_height - block.height < last_blocks_to_validate): @@ -1273,7 +1273,7 @@ def validate_recent_blocks( constants, required_iters, block, ssi, overflow, deficit, height, curr_block_ses ) log.debug(f"add block {block_record.height} to tmp sub blocks") - sub_blocks.add_block_record(block_record) + sub_blocks.add_block(block_record) if block.first_in_sub_slot: sub_slots += 1 diff --git a/chia/simulator/block_tools.py b/chia/simulator/block_tools.py index 42dcfcf6ac9c..3714e7d3bd18 100644 --- a/chia/simulator/block_tools.py +++ b/chia/simulator/block_tools.py @@ -949,7 +949,7 @@ def get_consecutive_blocks( if not pending_ses: # if we just created a sub-epoch summary, we can at least skip another sub-slot sub_epoch_summary = next_sub_epoch_summary( constants, - BlockCache(blocks, height_to_hash=height_to_hash), + BlockCache(blocks), latest_block.required_iters, block_list[-1], False, @@ -1247,7 +1247,7 @@ def create_genesis_block( for signage_point_index in range(0, constants.NUM_SPS_SUB_SLOT): signage_point: SignagePoint = get_signage_point( constants, - BlockCache({}, {}), + BlockCache({}), None, sub_slot_total_iters, uint8(signage_point_index), diff --git a/chia/util/block_cache.py b/chia/util/block_cache.py index 7ffba736ee40..cdb6b3ef4ac1 100644 --- a/chia/util/block_cache.py +++ b/chia/util/block_cache.py @@ -1,112 +1,48 @@ from __future__ import annotations -import logging -from typing import Dict, List, Optional +from typing import Dict, Optional from chia.consensus.block_record import BlockRecord from chia.consensus.blockchain_interface import BlockRecordsInterface from chia.types.blockchain_format.sized_bytes import bytes32 -from chia.types.blockchain_format.sub_epoch_summary import SubEpochSummary -from chia.types.header_block import HeaderBlock -from chia.types.weight_proof import SubEpochChallengeSegment, SubEpochSegments from chia.util.ints import uint32 class BlockCache(BlockRecordsInterface): + _block_records: Dict[bytes32, BlockRecord] + _height_to_hash: Dict[uint32, bytes32] + + def add_block(self, block: BlockRecord) -> None: + hh = block.header_hash + self._block_records[hh] = block + self._height_to_hash[block.height] = hh + def __init__( self, blocks: Dict[bytes32, BlockRecord], - headers: Optional[Dict[bytes32, HeaderBlock]] = None, - height_to_hash: Optional[Dict[uint32, bytes32]] = None, - sub_epoch_summaries: Optional[Dict[uint32, SubEpochSummary]] = None, ): - if sub_epoch_summaries is None: - sub_epoch_summaries = {} - if height_to_hash is None: - height_to_hash = {} - if headers is None: - headers = {} self._block_records = blocks - self._headers = headers - self._height_to_hash = height_to_hash - self._sub_epoch_summaries = sub_epoch_summaries - self._sub_epoch_segments: Dict[bytes32, SubEpochSegments] = {} - self.log = logging.getLogger(__name__) + self._height_to_hash = {block.height: hh for hh, block in blocks.items()} def block_record(self, header_hash: bytes32) -> BlockRecord: return self._block_records[header_hash] def height_to_block_record(self, height: uint32, check_db: bool = False) -> BlockRecord: # Precondition: height is < peak height - header_hash: Optional[bytes32] = self.height_to_hash(height) assert header_hash is not None - return self.block_record(header_hash) - def get_ses_heights(self) -> List[uint32]: - return sorted(self._sub_epoch_summaries.keys()) - - def get_ses(self, height: uint32) -> SubEpochSummary: - return self._sub_epoch_summaries[height] - def height_to_hash(self, height: uint32) -> Optional[bytes32]: if height not in self._height_to_hash: - self.log.warning(f"could not find height in cache {height}") return None return self._height_to_hash[height] def contains_block(self, header_hash: bytes32) -> bool: return header_hash in self._block_records - async def contains_block_from_db(self, header_hash: bytes32) -> bool: - return header_hash in self._block_records - def contains_height(self, height: uint32) -> bool: return height in self._height_to_hash - async def get_block_records_in_range(self, start: int, stop: int) -> Dict[bytes32, BlockRecord]: - return self._block_records - - async def get_block_records_at(self, heights: List[uint32]) -> List[BlockRecord]: - block_records: List[BlockRecord] = [] - for height in heights: - block_records.append(self.height_to_block_record(height)) - return block_records - def try_block_record(self, header_hash: bytes32) -> Optional[BlockRecord]: return self._block_records.get(header_hash) - - async def get_block_record_from_db(self, header_hash: bytes32) -> Optional[BlockRecord]: - return self._block_records[header_hash] - - async def prev_block_hash(self, header_hashes: List[bytes32]) -> List[bytes32]: - ret = [] - for h in header_hashes: - ret.append(self._block_records[h].prev_hash) - return ret - - def remove_block_record(self, header_hash: bytes32) -> None: - del self._block_records[header_hash] - - def add_block_record(self, block: BlockRecord) -> None: - self._block_records[block.header_hash] = block - - async def get_header_blocks_in_range( - self, start: int, stop: int, tx_filter: bool = True - ) -> Dict[bytes32, HeaderBlock]: - return self._headers - - async def persist_sub_epoch_challenge_segments( - self, sub_epoch_summary_hash: bytes32, segments: List[SubEpochChallengeSegment] - ) -> None: - self._sub_epoch_segments[sub_epoch_summary_hash] = SubEpochSegments(segments) - - async def get_sub_epoch_challenge_segments( - self, - sub_epoch_summary_hash: bytes32, - ) -> Optional[List[SubEpochChallengeSegment]]: - segments = self._sub_epoch_segments.get(sub_epoch_summary_hash) - if segments is None: - return None - return segments.challenge_segments