Skip to content

Commit

Permalink
Validate summaries while syncing (Chia-Network#5284)
Browse files Browse the repository at this point in the history
* block pre process check se matches wp

* test

* test

* test

* lint

* merge

* lint
  • Loading branch information
almogdepaz authored Jun 15, 2021
1 parent 3fd8f68 commit b99ae59
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 4 deletions.
8 changes: 6 additions & 2 deletions chia/consensus/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ async def receive_block(
block: FullBlock,
pre_validation_result: Optional[PreValidationResult] = None,
fork_point_with_peak: Optional[uint32] = None,
summaries_to_check: List[SubEpochSummary] = None, # passed only on long sync
) -> Tuple[ReceiveBlockResult, Optional[Err], Optional[uint32]]:
"""
This method must be called under the blockchain lock
Expand Down Expand Up @@ -545,7 +544,11 @@ async def validate_unfinished_block(
return PreValidationResult(None, required_iters, cost_result)

async def pre_validate_blocks_multiprocessing(
self, blocks: List[FullBlock], npc_results: Dict[uint32, NPCResult], batch_size: int = 4
self,
blocks: List[FullBlock],
npc_results: Dict[uint32, NPCResult],
batch_size: int = 4,
wp_summaries: Optional[List[SubEpochSummary]] = None,
) -> Optional[List[PreValidationResult]]:
return await pre_validate_blocks_multiprocessing(
self.constants,
Expand All @@ -557,6 +560,7 @@ async def pre_validate_blocks_multiprocessing(
npc_results,
self.get_block_generator,
batch_size,
wp_summaries,
)

def contains_block(self, header_hash: bytes32) -> bool:
Expand Down
9 changes: 9 additions & 0 deletions chia/consensus/multiprocess_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from chia.full_node.mempool_check_conditions import get_name_puzzle_conditions
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.blockchain_format.sub_epoch_summary import SubEpochSummary
from chia.types.full_block import FullBlock
from chia.types.generator_types import BlockGenerator
from chia.types.header_block import HeaderBlock
Expand Down Expand Up @@ -132,6 +133,7 @@ async def pre_validate_blocks_multiprocessing(
npc_results: Dict[uint32, NPCResult],
get_block_generator: Optional[Callable],
batch_size: int,
wp_summaries: Optional[List[SubEpochSummary]] = None,
) -> Optional[List[PreValidationResult]]:
"""
This method must be called under the blockchain lock
Expand Down Expand Up @@ -221,6 +223,13 @@ async def pre_validate_blocks_multiprocessing(
block,
None,
)

if block_rec.sub_epoch_summary_included is not None and wp_summaries is not None:
idx = int(block.height / constants.SUB_EPOCH_BLOCKS) - 1
next_ses = wp_summaries[idx]
if not block_rec.sub_epoch_summary_included.get_hash() == next_ses.get_hash():
log.error("sub_epoch_summary does not match wp sub_epoch_summary list")
return None
# Makes sure to not override the valid blocks already in block_records
if not block_records.contains_block(block_rec.header_hash):
block_records.add_block_record(block_rec) # Temporarily add block to dict
Expand Down
4 changes: 2 additions & 2 deletions chia/full_node/full_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -827,7 +827,7 @@ async def receive_block_batch(
pre_validate_start = time.time()
pre_validation_results: Optional[
List[PreValidationResult]
] = await self.blockchain.pre_validate_blocks_multiprocessing(blocks_to_validate, {})
] = await self.blockchain.pre_validate_blocks_multiprocessing(blocks_to_validate, {}, wp_summaries=wp_summaries)
self.log.debug(f"Block pre-validation time: {time.time() - pre_validate_start}")
if pre_validation_results is None:
return False, False, None
Expand All @@ -841,7 +841,7 @@ async def receive_block_batch(
for i, block in enumerate(blocks_to_validate):
assert pre_validation_results[i].required_iters is not None
(result, error, fork_height,) = await self.blockchain.receive_block(
block, pre_validation_results[i], None if advanced_peak else fork_point, wp_summaries
block, pre_validation_results[i], None if advanced_peak else fork_point
)
if result == ReceiveBlockResult.NEW_PEAK:
advanced_peak = True
Expand Down
29 changes: 29 additions & 0 deletions tests/core/full_node/full_sync/test_full_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@

import pytest

from chia.full_node.weight_proof import _validate_sub_epoch_summaries
from chia.protocols import full_node_protocol
from chia.types.blockchain_format.sub_epoch_summary import SubEpochSummary
from chia.types.full_block import FullBlock
from chia.types.peer_info import PeerInfo
from chia.util.hash import std_hash
Expand Down Expand Up @@ -343,3 +345,30 @@ async def test_sync_bad_peak_while_synced(self, three_nodes, default_1000_blocks
await full_node_2.full_node.respond_block(full_node_protocol.RespondBlock(block))

await time_out_assert(180, node_height_exactly, True, full_node_2, 999)

@pytest.mark.asyncio
async def test_block_ses_mismatch(self, three_nodes, default_1000_blocks):
full_node_1, full_node_2, full_node_3 = three_nodes
server_1 = full_node_1.full_node.server
server_2 = full_node_2.full_node.server
blocks = default_1000_blocks

for block in blocks[:501]:
await full_node_1.full_node.respond_block(full_node_protocol.RespondBlock(block))

peak1 = full_node_1.full_node.blockchain.get_peak()
full_node_2.full_node.sync_store.set_long_sync(True)
await server_2.start_client(PeerInfo(self_hostname, uint16(server_1._port)), full_node_2.full_node.on_connect)
wp = await full_node_1.full_node.weight_proof_handler.get_proof_of_weight(peak1.header_hash)
summaries1, _ = _validate_sub_epoch_summaries(full_node_1.full_node.weight_proof_handler.constants, wp)
summaries2 = summaries1
s = summaries1[1]
summaries2[1] = SubEpochSummary(
s.prev_subepoch_summary_hash,
s.reward_chain_hash,
s.num_blocks_overflow,
s.new_difficulty * 2,
s.new_sub_slot_iters * 2,
)
await full_node_2.full_node.sync_from_fork_point(0, 500, peak1.header_hash, summaries2)
await time_out_assert(180, node_height_exactly, True, full_node_2, 320)

0 comments on commit b99ae59

Please sign in to comment.