parent
249a5f3cca
commit
1bb7572d52
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)}"
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue