weight proof (#926)

wp validations
wp multi processing
This commit is contained in:
Almog De Paz 2021-02-24 00:39:48 +02:00 committed by GitHub
parent 249a5f3cca
commit 1bb7572d52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1128 additions and 634 deletions

View File

@ -46,6 +46,7 @@ def validate_unfinished_header_block(
expected_sub_slot_iters: uint64,
skip_overflow_last_ss_validation: bool = False,
skip_vdf_is_valid: bool = False,
check_sub_epoch_summary=True,
) -> Tuple[Optional[uint64], Optional[ValidationError]]:
"""
Validates an unfinished header block. This is a block without the infusion VDFs (unfinished)
@ -389,24 +390,25 @@ def validate_unfinished_header_block(
)
# 3c. Check the actual sub-epoch is correct
expected_sub_epoch_summary = make_sub_epoch_summary(
constants,
blocks,
height,
blocks.block_record(prev_b.prev_hash),
expected_difficulty if can_finish_epoch else None,
expected_sub_slot_iters if can_finish_epoch else None,
)
expected_hash = expected_sub_epoch_summary.get_hash()
if expected_hash != ses_hash:
log.error(f"{expected_sub_epoch_summary}")
return (
None,
ValidationError(
Err.INVALID_SUB_EPOCH_SUMMARY,
f"expected ses hash: {expected_hash} got {ses_hash} ",
),
if check_sub_epoch_summary:
expected_sub_epoch_summary = make_sub_epoch_summary(
constants,
blocks,
height,
blocks.block_record(prev_b.prev_hash),
expected_difficulty if can_finish_epoch else None,
expected_sub_slot_iters if can_finish_epoch else None,
)
expected_hash = expected_sub_epoch_summary.get_hash()
if expected_hash != ses_hash:
log.error(f"{expected_sub_epoch_summary}")
return (
None,
ValidationError(
Err.INVALID_SUB_EPOCH_SUMMARY,
f"expected ses hash: {expected_hash} got {ses_hash} ",
),
)
elif new_sub_slot and not genesis_block:
# 3d. Check that we don't have to include a sub-epoch summary
if can_finish_se or can_finish_epoch:
@ -808,6 +810,7 @@ def validate_finished_header_block(
check_filter: bool,
expected_difficulty: uint64,
expected_sub_slot_iters: uint64,
check_sub_epoch_summary=True,
) -> Tuple[Optional[uint64], Optional[ValidationError]]:
"""
Fully validates the header of a block. A header block is the same as a full block, but
@ -831,6 +834,7 @@ def validate_finished_header_block(
expected_difficulty,
expected_sub_slot_iters,
False,
check_sub_epoch_summary=check_sub_epoch_summary,
)
genesis_block = False

View File

@ -12,7 +12,7 @@ from src.types.blockchain_format.slots import ChallengeBlockInfo
from src.types.full_block import FullBlock
from src.consensus.block_record import BlockRecord
from src.types.blockchain_format.sub_epoch_summary import SubEpochSummary
from src.util.ints import uint64, uint32
from src.util.ints import uint64, uint32, uint8
from src.consensus.make_sub_epoch_summary import make_sub_epoch_summary
@ -53,17 +53,73 @@ def block_to_block_record(
overflow,
len(block.finished_sub_slots),
)
prev_transaction_block_hash = (
block.foliage_transaction_block.prev_transaction_block_hash
if block.foliage_transaction_block is not None
else None
found_ses_hash: Optional[bytes32] = None
ses: Optional[SubEpochSummary] = None
if len(block.finished_sub_slots) > 0:
for sub_slot in block.finished_sub_slots:
if sub_slot.challenge_chain.subepoch_summary_hash is not None:
found_ses_hash = sub_slot.challenge_chain.subepoch_summary_hash
if found_ses_hash:
assert prev_b is not None
assert len(block.finished_sub_slots) > 0
ses = make_sub_epoch_summary(
constants,
blocks,
block.height,
blocks.block_record(prev_b.prev_hash),
block.finished_sub_slots[0].challenge_chain.new_difficulty,
block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters,
)
assert ses.get_hash() == found_ses_hash
prev_transaction_block_height = uint32(0)
curr: Optional[BlockRecord] = blocks.try_block_record(block.prev_header_hash)
while curr is not None and not curr.is_transaction_block:
curr = blocks.try_block_record(curr.prev_hash)
if curr is not None and curr.is_transaction_block:
prev_transaction_block_height = curr.height
return header_block_to_sub_block_record(
constants,
required_iters,
block,
sub_slot_iters,
overflow,
deficit,
prev_transaction_block_height,
ses,
)
timestamp = block.foliage_transaction_block.timestamp if block.foliage_transaction_block is not None else None
fees = block.transactions_info.fees if block.transactions_info is not None else None
def header_block_to_sub_block_record(
constants: ConsensusConstants,
required_iters: uint64,
block: Union[FullBlock, HeaderBlock],
sub_slot_iters: uint64,
overflow: bool,
deficit: uint8,
prev_transaction_block_height: uint32,
ses: Optional[SubEpochSummary],
):
reward_claims_incorporated = (
block.transactions_info.reward_claims_incorporated if block.transactions_info is not None else None
)
cbi = ChallengeBlockInfo(
block.reward_chain_block.proof_of_space,
block.reward_chain_block.challenge_chain_sp_vdf,
block.reward_chain_block.challenge_chain_sp_signature,
block.reward_chain_block.challenge_chain_ip_vdf,
)
if block.reward_chain_block.infused_challenge_chain_ip_vdf is not None:
icc_output: Optional[ClassgroupElement] = block.reward_chain_block.infused_challenge_chain_ip_vdf.output
else:
icc_output = None
if len(block.finished_sub_slots) > 0:
finished_challenge_slot_hashes: Optional[List[bytes32]] = [
sub_slot.challenge_chain.get_hash() for sub_slot in block.finished_sub_slots
@ -84,45 +140,13 @@ def block_to_block_record(
finished_challenge_slot_hashes = None
finished_reward_slot_hashes = None
finished_infused_challenge_slot_hashes = None
found_ses_hash: Optional[bytes32] = None
ses: Optional[SubEpochSummary] = None
if len(block.finished_sub_slots) > 0:
for sub_slot in block.finished_sub_slots:
if sub_slot.challenge_chain.subepoch_summary_hash is not None:
found_ses_hash = sub_slot.challenge_chain.subepoch_summary_hash
if found_ses_hash:
assert prev_b is not None
assert len(block.finished_sub_slots) > 0
ses = make_sub_epoch_summary(
constants,
blocks,
block.height,
blocks.block_record(prev_b.prev_hash),
block.finished_sub_slots[0].challenge_chain.new_difficulty,
block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters,
)
assert ses.get_hash() == found_ses_hash
cbi = ChallengeBlockInfo(
block.reward_chain_block.proof_of_space,
block.reward_chain_block.challenge_chain_sp_vdf,
block.reward_chain_block.challenge_chain_sp_signature,
block.reward_chain_block.challenge_chain_ip_vdf,
prev_transaction_block_hash = (
block.foliage_transaction_block.prev_transaction_block_hash
if block.foliage_transaction_block is not None
else None
)
if block.reward_chain_block.infused_challenge_chain_ip_vdf is not None:
icc_output: Optional[ClassgroupElement] = block.reward_chain_block.infused_challenge_chain_ip_vdf.output
else:
icc_output = None
prev_transaction_block_height = uint32(0)
curr: Optional[BlockRecord] = blocks.try_block_record(block.prev_header_hash)
while curr is not None and not curr.is_transaction_block:
curr = blocks.try_block_record(curr.prev_hash)
if curr is not None and curr.is_transaction_block:
prev_transaction_block_height = curr.height
timestamp = block.foliage_transaction_block.timestamp if block.foliage_transaction_block is not None else None
fees = block.transactions_info.fees if block.transactions_info is not None else None
return BlockRecord(
block.header_hash,

View File

@ -564,7 +564,7 @@ class FullNode:
await weight_proof_peer.close()
raise RuntimeError(f"Weight proof had the wrong weight: {weight_proof_peer.peer_host}")
validated, fork_point = self.weight_proof_handler.validate_weight_proof(response.wp)
validated, fork_point = await self.weight_proof_handler.validate_weight_proof(response.wp)
if not validated:
raise ValueError("Weight proof validation failed")

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
from dataclasses import dataclass
from typing import List, Optional
from blspy import G2Element
from src.types.end_of_slot_bundle import EndOfSubSlotBundle
from src.types.blockchain_format.proof_of_space import ProofOfSpace
from src.types.blockchain_format.reward_chain_block import RewardChainBlock
from src.types.blockchain_format.sized_bytes import bytes32
from src.types.blockchain_format.vdf import VDFProof, VDFInfo
from src.util.ints import uint8, uint64, uint32
from src.types.end_of_slot_bundle import EndOfSubSlotBundle
from src.types.header_block import HeaderBlock
from src.util.ints import uint8, uint64, uint32, uint128
from src.util.streamable import Streamable, streamable
@ -37,24 +37,23 @@ class SubEpochData(Streamable):
class SubSlotData(Streamable):
# if infused
proof_of_space: Optional[ProofOfSpace]
# Signature of signage point
cc_sp_sig: Optional[G2Element]
# VDF to signage point
cc_signage_point: Optional[VDFProof]
# VDF from signage to infusion point
cc_infusion_point: Optional[VDFProof]
icc_infusion_point: Optional[VDFProof]
cc_sp_vdf_info: Optional[VDFInfo]
cc_signage_point_index: Optional[uint8]
signage_point_index: Optional[uint8]
# VDF from beginning to end of slot if not infused
# from ip to end if infused
cc_slot_end: Optional[VDFProof]
icc_slot_end: Optional[VDFProof]
# info from finished slots
cc_slot_end_info: Optional[VDFInfo]
icc_slot_end_info: Optional[VDFInfo]
rc_slot_end_info: Optional[VDFInfo]
cc_ip_vdf_info: Optional[VDFInfo]
icc_ip_vdf_info: Optional[VDFInfo]
total_iters: Optional[uint128]
def is_challenge(self):
if self.proof_of_space is not None:
@ -67,6 +66,7 @@ class SubSlotData(Streamable):
class SubEpochChallengeSegment(Streamable):
sub_epoch_n: uint32
sub_slots: List[SubSlotData]
rc_slot_end_info: Optional[VDFInfo] # in first segment of each sub_epoch
@dataclass(frozen=True)
@ -88,4 +88,4 @@ class ProofBlockHeader(Streamable):
class WeightProof(Streamable):
sub_epochs: List[SubEpochData]
sub_epoch_segments: List[SubEpochChallengeSegment] # sampled sub epoch
recent_chain_data: List[ProofBlockHeader] # todo switch HeaderBlock tp class with only needed field
recent_chain_data: List[HeaderBlock]

View File

@ -2,7 +2,7 @@ import logging
from typing import Dict, List, Optional
from src.consensus.block_record import BlockRecord
from src.full_node.weight_proof import BlockchainInterface
from src.consensus.blockchain_interface import BlockchainInterface
from src.types.header_block import HeaderBlock
from src.types.blockchain_format.sized_bytes import bytes32
from src.types.blockchain_format.sub_epoch_summary import SubEpochSummary

View File

@ -441,7 +441,9 @@ class WalletNode:
weight_proof = weight_proof_response.wp
if self.wallet_state_manager is None:
return
valid, fork_point = self.wallet_state_manager.weight_proof_handler.validate_weight_proof(weight_proof)
valid, fork_point = await self.wallet_state_manager.weight_proof_handler.validate_weight_proof(
weight_proof
)
if not valid:
self.log.error(
f"invalid weight proof, num of epochs {len(weight_proof.sub_epochs)}"

View File

@ -1,38 +1,38 @@
# flake8: noqa: F811, F401
import asyncio
import logging
import sys
from typing import Dict, Optional, List, Tuple
import aiosqlite
import pytest
from src.consensus.block_record import BlockRecord
from src.consensus.default_constants import DEFAULT_CONSTANTS
from src.consensus.full_block_to_block_record import block_to_block_record
from src.full_node.block_store import BlockStore
from src.types.blockchain_format.sized_bytes import bytes32
from src.types.blockchain_format.sub_epoch_summary import SubEpochSummary
from src.util.block_cache import BlockCache
from tests.core.fixtures import empty_blockchain # noqa: F401
from tests.core.fixtures import default_1000_blocks # noqa: F401
from tests.core.fixtures import default_400_blocks # noqa: F401
from tests.core.fixtures import default_10000_blocks # noqa: F401
from src.util.block_tools import test_constants
try:
from reprlib import repr
except ImportError:
pass
from src.consensus.pot_iterations import calculate_iterations_quality
from src.full_node.weight_proof import ( # type: ignore
WeightProofHandler,
_map_summaries,
_validate_summaries_weight,
_validate_segment_slots,
)
from src.types.full_block import FullBlock
from src.types.header_block import HeaderBlock
from src.types.blockchain_format.sized_bytes import bytes32
from src.types.blockchain_format.sub_epoch_summary import SubEpochSummary
from src.util.ints import uint32, uint64
from tests.setup_nodes import test_constants
from tests.core.fixtures import default_1000_blocks, default_400_blocks, default_10000_blocks
@pytest.fixture(scope="session")
@ -41,6 +41,33 @@ def event_loop():
yield loop
def count_sub_epochs(blockchain, last_hash) -> int:
curr = blockchain._sub_blocks[last_hash]
count = 0
while True:
if curr.height == 0:
break
# next sub block
curr = blockchain._sub_blocks[curr.prev_hash]
# if end of sub-epoch
if curr.sub_epoch_summary_included is not None:
count += 1
return count
def get_prev_ses_block(sub_blocks, last_hash) -> Tuple[BlockRecord, int]:
curr = sub_blocks[last_hash]
blocks = 1
while curr.height != 0:
# next sub block
curr = sub_blocks[curr.prev_hash]
# if end of sub-epoch
if curr.sub_epoch_summary_included is not None:
return curr, blocks
blocks += 1
assert False
async def load_blocks_dont_validate(
blocks,
) -> Tuple[
@ -48,7 +75,7 @@ async def load_blocks_dont_validate(
]:
header_cache: Dict[bytes32, HeaderBlock] = {}
height_to_hash: Dict[uint32, bytes32] = {}
block_records: Dict[bytes32, BlockRecord] = {}
sub_blocks: Dict[bytes32, BlockRecord] = {}
sub_epoch_summaries: Dict[bytes32, SubEpochSummary] = {}
prev_block = None
difficulty = test_constants.DIFFICULTY_STARTING
@ -79,28 +106,28 @@ async def load_blocks_dont_validate(
cc_sp,
)
block_record = block_to_block_record(
test_constants, BlockCache(block_records, height_to_hash), required_iters, block, None
sub_block = block_to_block_record(
test_constants, BlockCache(sub_blocks, height_to_hash), required_iters, block, None
)
block_records[block.header_hash] = block_record
sub_blocks[block.header_hash] = sub_block
height_to_hash[block.height] = block.header_hash
header_cache[block.header_hash] = block.get_block_header()
if block_record.sub_epoch_summary_included is not None:
sub_epoch_summaries[block.height] = block_record.sub_epoch_summary_included
if sub_block.sub_epoch_summary_included is not None:
sub_epoch_summaries[block.height] = sub_block.sub_epoch_summary_included
prev_block = block
return header_cache, height_to_hash, block_records, sub_epoch_summaries
return header_cache, height_to_hash, sub_blocks, sub_epoch_summaries
async def _test_map_summaries(blocks, header_cache, height_to_hash, block_records, summaries):
curr = block_records[blocks[-1].header_hash]
async def _test_map_summaries(blocks, header_cache, height_to_hash, sub_blocks, summaries):
curr = sub_blocks[blocks[-1].header_hash]
orig_summaries: Dict[int, SubEpochSummary] = {}
while curr.height > 0:
if curr.sub_epoch_summary_included is not None:
orig_summaries[curr.height] = curr.sub_epoch_summary_included
# next sub block
curr = block_records[curr.prev_hash]
curr = sub_blocks[curr.prev_hash]
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
wp = await wpf.get_proof_of_weight(blocks[-1].header_hash)
assert wp is not None
@ -117,19 +144,19 @@ async def _test_map_summaries(blocks, header_cache, height_to_hash, block_record
class TestWeightProof:
@pytest.mark.asyncio
async def test_weight_proof_map_summaries_1(self, default_400_blocks):
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(default_400_blocks)
await _test_map_summaries(default_400_blocks, header_cache, height_to_hash, block_records, summaries)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(default_400_blocks)
await _test_map_summaries(default_400_blocks, header_cache, height_to_hash, sub_blocks, summaries)
@pytest.mark.asyncio
async def test_weight_proof_map_summaries_2(self, default_1000_blocks):
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(default_1000_blocks)
await _test_map_summaries(default_1000_blocks, header_cache, height_to_hash, block_records, summaries)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(default_1000_blocks)
await _test_map_summaries(default_1000_blocks, header_cache, height_to_hash, sub_blocks, summaries)
@pytest.mark.asyncio
async def test_weight_proof_summaries_1000_blocks(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
wp = await wpf.get_proof_of_weight(blocks[-1].header_hash)
summaries, sub_epoch_data_weight = _map_summaries(
wpf.constants.SUB_EPOCH_BLOCKS,
@ -137,15 +164,14 @@ class TestWeightProof:
wp.sub_epochs,
wpf.constants.DIFFICULTY_STARTING,
)
assert wpf._validate_summaries_weight(sub_epoch_data_weight, summaries, wp)
assert _validate_summaries_weight(test_constants, sub_epoch_data_weight, summaries, wp)
# assert res is not None
@pytest.mark.asyncio
async def test_weight_proof_bad_peak_hash(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
wpf.log.setLevel(logging.INFO)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
wp = await wpf.get_proof_of_weight(b"sadgfhjhgdgsfadfgh")
assert wp is None
@ -153,8 +179,8 @@ class TestWeightProof:
@pytest.mark.skip(reason="broken")
async def test_weight_proof_from_genesis(self, default_400_blocks):
blocks = default_400_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(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)
@ -163,15 +189,16 @@ class TestWeightProof:
@pytest.mark.asyncio
async def test_weight_proof_validate_segment(self, default_400_blocks):
blocks = default_400_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
summaries_list: List[SubEpochSummary] = []
for key in sorted(summaries.keys()):
summaries_list.append(summaries[key])
wp = await wpf._create_proof_of_weight(blocks[-1].header_hash)
res, _, _, _, _ = wpf._validate_segment_slots(
res, _, _, _ = _validate_segment_slots(
test_constants,
wp.sub_epoch_segments[0],
test_constants.SUB_SLOT_ITERS_STARTING,
test_constants.DIFFICULTY_STARTING,
@ -183,12 +210,12 @@ class TestWeightProof:
@pytest.mark.asyncio
async def test_weight_proof1000(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(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(test_constants, BlockCache(block_records, header_cache, height_to_hash, {}))
valid, fork_point = wpf.validate_weight_proof(wp)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, {}))
valid, fork_point = wpf.validate_weight_proof_single_proc(wp)
assert valid
assert fork_point == 0
@ -196,13 +223,13 @@ class TestWeightProof:
@pytest.mark.asyncio
async def test_weight_proof10000(self, default_10000_blocks):
blocks = default_10000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
wpf = WeightProofHandler(test_constants, BlockCache(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(test_constants, BlockCache(block_records, {}, height_to_hash, {}))
valid, fork_point = wpf.validate_weight_proof(wp)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, {}, height_to_hash, {}))
valid, fork_point = await wpf.validate_weight_proof(wp)
assert valid
assert fork_point == 0
@ -210,67 +237,67 @@ class TestWeightProof:
@pytest.mark.asyncio
async def test_weight_proof_extend_no_ses(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
last_ses_height = sorted(summaries.keys())[-1]
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
wp = await wpf.get_proof_of_weight(blocks[last_ses_height].header_hash)
wpf_synced = WeightProofHandler(test_constants, BlockCache(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 = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, {}))
valid, fork_point = wpf.validate_weight_proof(wp)
wpf_not_synced = WeightProofHandler(test_constants, BlockCache(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
new_wp = await wpf._extend_proof_of_weight(wp, block_records[blocks[-1].header_hash])
valid, fork_point = wpf.validate_weight_proof(new_wp)
new_wp = await wpf_synced._create_proof_of_weight(blocks[-1].header_hash, wp)
valid, fork_point = await wpf_not_synced.validate_weight_proof(new_wp)
assert valid
assert fork_point == 0
@pytest.mark.asyncio
async def test_weight_proof_extend_new_ses(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
# delete last summary
last_ses_height = sorted(summaries.keys())[-1]
last_ses = summaries[last_ses_height]
del summaries[last_ses_height]
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
wp = await wpf.get_proof_of_weight(blocks[last_ses_height - 10].header_hash)
wpf_synced = WeightProofHandler(test_constants, BlockCache(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 = WeightProofHandler(test_constants, BlockCache(block_records, height_to_hash, header_cache, {}))
valid, fork_point = wpf.validate_weight_proof(wp)
wpf_not_synced = WeightProofHandler(test_constants, BlockCache(sub_blocks, height_to_hash, header_cache, {}))
valid, fork_point = await wpf_not_synced.validate_weight_proof(wp)
assert valid
assert fork_point == 0
# extend proof with 100 blocks
summaries[last_ses_height] = last_ses
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
new_wp = await wpf._extend_proof_of_weight(wp, block_records[blocks[-1].header_hash])
valid, fork_point = wpf.validate_weight_proof(new_wp)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
new_wp = await wpf._create_proof_of_weight(blocks[-1].header_hash, wp)
valid, fork_point = await wpf.validate_weight_proof(new_wp)
assert valid
assert fork_point != 0
@pytest.mark.asyncio
async def test_weight_proof_extend_multiple_ses(self, default_1000_blocks):
blocks = default_1000_blocks
header_cache, height_to_hash, block_records, summaries = await load_blocks_dont_validate(blocks)
header_cache, height_to_hash, sub_blocks, summaries = await load_blocks_dont_validate(blocks)
last_ses_height = sorted(summaries.keys())[-1]
last_ses = summaries[last_ses_height]
before_last_ses_height = sorted(summaries.keys())[-2]
before_last_ses = summaries[before_last_ses_height]
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
wpf_verify = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, {}))
for x in range(50, -1, -1):
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
wpf_verify = WeightProofHandler(test_constants, BlockCache(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
valid, fork_point = wpf_verify.validate_weight_proof(wp)
valid, fork_point = await wpf_verify.validate_weight_proof(wp)
assert valid
assert fork_point == 0
# extend proof with 100 blocks
summaries[last_ses_height] = last_ses
summaries[before_last_ses_height] = before_last_ses
wpf = WeightProofHandler(test_constants, BlockCache(block_records, header_cache, height_to_hash, summaries))
new_wp = await wpf._extend_proof_of_weight(wp, block_records[blocks[-1].header_hash])
valid, fork_point = wpf.validate_weight_proof(new_wp)
wpf = WeightProofHandler(test_constants, BlockCache(sub_blocks, header_cache, height_to_hash, summaries))
new_wp = await wpf._create_proof_of_weight(blocks[-1].header_hash, wp)
valid, fork_point = await wpf.validate_weight_proof(new_wp)
assert valid
assert fork_point != 0
@ -279,37 +306,38 @@ class TestWeightProof:
async def test_weight_proof_from_database(self):
connection = await aiosqlite.connect("path to db")
block_store: BlockStore = await BlockStore.create(connection)
peak = uint32(30000)
block_records = await block_store.get_block_records_in_range(0, peak)
headers = await block_store.get_header_blocks_in_range(0, peak)
height_to_hash = {}
sub_blocks, peak = await block_store.get_block_records()
headers = await block_store.get_header_blocks_in_range(0, 100225)
sub_height_to_hash = {}
sub_epoch_summaries = {}
peak = await block_store.get_full_blocks_at([peak])
if len(block_records) == 0:
peak = await block_store.get_full_blocks_at([100225])
if len(sub_blocks) == 0:
return None, None
assert peak is not None
peak_height = block_records[peak[0].header_hash].height
peak_height = sub_blocks[peak[0].header_hash].height
# Sets the other state variables (peak_height and height_to_hash)
curr: BlockRecord = block_records[peak[0].header_hash]
curr: BlockRecord = sub_blocks[peak[0].header_hash]
while True:
height_to_hash[curr.height] = curr.header_hash
sub_height_to_hash[curr.height] = curr.header_hash
if curr.sub_epoch_summary_included is not None:
sub_epoch_summaries[curr.height] = curr.sub_epoch_summary_included
if curr.height == 0:
break
curr = block_records[curr.prev_hash]
assert len(height_to_hash) == peak_height + 1
block_cache = BlockCache(block_records, headers, height_to_hash, sub_epoch_summaries)
curr = sub_blocks[curr.prev_hash]
assert len(sub_height_to_hash) == peak_height + 1
block_cache = BlockCache(sub_blocks, headers, sub_height_to_hash, sub_epoch_summaries)
wpf = WeightProofHandler(DEFAULT_CONSTANTS, block_cache)
wp = await wpf._create_proof_of_weight(height_to_hash[peak_height - 1])
await wpf._create_proof_of_weight(sub_height_to_hash[peak_height - 1])
wp = await wpf._create_proof_of_weight(sub_height_to_hash[peak_height - 1])
valid, fork_point = wpf.validate_weight_proof(wp)
await connection.close()
assert valid
f = open("wp.txt", "a")
f.write(f"{wp}")
f.close()
def get_size(obj, seen=None):

View File

@ -185,7 +185,7 @@ class TestFullSync:
full_node_protocol.RequestProofOfWeight(blocks_950[-1].height + 1, blocks_950[-1].header_hash)
)
assert res is not None
validated, _ = full_node_1.full_node.weight_proof_handler.validate_weight_proof(
validated, _ = await full_node_1.full_node.weight_proof_handler.validate_weight_proof(
full_node_protocol.RespondProofOfWeight.from_bytes(res.data).wp
)
assert validated