mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-11-13 12:09:25 +03:00
test map_summaries
This commit is contained in:
parent
b27ba1a49b
commit
357ee54886
@ -6,6 +6,7 @@ from src.consensus.constants import ConsensusConstants
|
||||
from src.consensus.pot_iterations import (
|
||||
calculate_iterations_quality,
|
||||
calculate_ip_iters,
|
||||
is_overflow_sub_block,
|
||||
)
|
||||
from src.consensus.sub_block_record import SubBlockRecord
|
||||
from src.types.classgroup import ClassgroupElement
|
||||
@ -44,43 +45,49 @@ class WeightProofFactory:
|
||||
else:
|
||||
self.log = logging.getLogger(__name__)
|
||||
|
||||
def make_weight_proof(self, recent_blocks_n: uint32, total_number_of_blocks: uint32) -> WeightProof:
|
||||
def make_weight_proof(self, recent_blocks_n: uint32, total_number_of_blocks: uint32, tip: bytes32) -> WeightProof:
|
||||
"""
|
||||
Creates a weight proof object
|
||||
"""
|
||||
|
||||
# todo assert recent blocks number
|
||||
tip = self.height_to_hash[uint32(len(self.height_to_hash) - 1)]
|
||||
# todo clean some of the logs after tests pass
|
||||
sub_epoch_data: List[SubEpochData] = []
|
||||
sub_epoch_segments: List[SubEpochChallengeSegment] = []
|
||||
proof_blocks: List[RewardChainSubBlock] = []
|
||||
curr: SubBlockRecord = self.sub_blocks[tip]
|
||||
rng: random.Random = random.Random(tip)
|
||||
# ses_hash from the latest sub epoch summary before this part of the chain
|
||||
self.log.info(
|
||||
f"build weight proofs peak : {self.sub_blocks[tip].header_hash} num of blocks: {total_number_of_blocks}"
|
||||
f"build weight proofs, peak : {self.sub_blocks[tip].height} num of blocks: {total_number_of_blocks}"
|
||||
)
|
||||
assert self.sub_blocks[tip].height > total_number_of_blocks
|
||||
sub_epoch_n = count_sub_epochs_in_range(curr, self.sub_blocks, total_number_of_blocks)
|
||||
sub_epoch_n = count_sub_epochs_in_range(self.sub_blocks[tip], self.sub_blocks, total_number_of_blocks)
|
||||
sub_epoch_reverse_idx: uint32 = uint32(0)
|
||||
|
||||
blocks_left = total_number_of_blocks
|
||||
while blocks_left > 0:
|
||||
curr_height = self.sub_blocks[tip].height - total_number_of_blocks
|
||||
total_overflow_blocks = 0
|
||||
while blocks_left != 0:
|
||||
# next sub block
|
||||
curr = self.sub_blocks[curr.prev_hash]
|
||||
header_block = self.header_cache[curr.header_hash]
|
||||
block = self.height_to_hash[curr_height]
|
||||
sub_block = self.sub_blocks[block]
|
||||
header_block = self.header_cache[block]
|
||||
if is_overflow_sub_block(self.constants, header_block.reward_chain_sub_block.signage_point_index):
|
||||
total_overflow_blocks += 1
|
||||
self.log.info(f"overflow block at height {curr_height} ")
|
||||
# for each sub-epoch
|
||||
if curr.sub_epoch_summary_included is not None:
|
||||
self.log.info(f"sub epoch end in block height {curr.height}")
|
||||
sub_epoch_data.append(make_sub_epoch_data(curr.sub_epoch_summary_included))
|
||||
if sub_block.sub_epoch_summary_included is not None:
|
||||
self.log.info(f"sub epoch end in block height {sub_block.height}")
|
||||
sub_epoch_data.append(make_sub_epoch_data(sub_block.sub_epoch_summary_included))
|
||||
# get sub_epoch_blocks_n in sub_epoch
|
||||
sub_epoch_blocks_n = get_sub_epoch_block_num(curr, self.sub_blocks)
|
||||
sub_epoch_blocks_n = get_sub_epoch_block_num(sub_block, self.sub_blocks)
|
||||
self.log.info(f"sub epoch {sub_epoch_n - sub_epoch_reverse_idx} has {sub_epoch_blocks_n} blocks")
|
||||
# sample sub epoch
|
||||
if choose_sub_epoch(sub_epoch_blocks_n, rng, total_number_of_blocks):
|
||||
self.log.info(f"sub epoch {sub_epoch_n - sub_epoch_reverse_idx} chosen")
|
||||
sub_epoch_segments.extend(
|
||||
self.create_sub_epoch_segments(
|
||||
curr,
|
||||
sub_block,
|
||||
sub_epoch_blocks_n,
|
||||
sub_epoch_n - sub_epoch_reverse_idx,
|
||||
)
|
||||
@ -93,7 +100,8 @@ class WeightProofFactory:
|
||||
recent_blocks_n -= 1
|
||||
|
||||
blocks_left -= 1
|
||||
|
||||
curr_height += 1
|
||||
self.log.info(f"total overflow blocks in proof {total_overflow_blocks}")
|
||||
return WeightProof(sub_epoch_data, sub_epoch_segments, proof_blocks)
|
||||
|
||||
def validate_weight(
|
||||
@ -106,21 +114,21 @@ class WeightProofFactory:
|
||||
) -> bool:
|
||||
# sub epoch summaries validate hashes
|
||||
summaries, sub_epoch_data_weight = map_summaries(
|
||||
self.log,
|
||||
self.constants.SUB_EPOCH_SUB_BLOCKS,
|
||||
prev_ses_hash,
|
||||
weight_proof,
|
||||
weight_proof.sub_epochs,
|
||||
fork_point_difficulty,
|
||||
fork_point_sub_slot_iters,
|
||||
)
|
||||
|
||||
# last ses
|
||||
ses = summaries[uint32(len(summaries) - 1)]
|
||||
|
||||
# validate weight
|
||||
# find first block after last sub epoch end
|
||||
self.log.info(
|
||||
f"diff {fork_point_difficulty}, sub epoch data weight {sub_epoch_data_weight}, start weight {fork_point_weight}"
|
||||
)
|
||||
|
||||
self.log.info(f"")
|
||||
block_idx = get_last_ses_block_idx(
|
||||
weight_proof.recent_reward_chain, uint128(fork_point_difficulty), sub_epoch_data_weight + fork_point_weight
|
||||
)
|
||||
@ -130,10 +138,15 @@ class WeightProofFactory:
|
||||
last_ses_block = weight_proof.recent_reward_chain[block_idx]
|
||||
self.log.error(f"last ses at height {last_ses_block.sub_block_height}")
|
||||
# use block we found by weight to validate last ses_hash
|
||||
cc_vdf = weight_proof.recent_reward_chain[block_idx].challenge_chain_ip_vdf
|
||||
challenge = std_hash(
|
||||
ChallengeChainSubSlot(cc_vdf, None, std_hash(ses), ses.new_sub_slot_iters, ses.new_difficulty)
|
||||
)
|
||||
cc_vdf = weight_proof.recent_reward_chain[block_idx - 1].challenge_chain_ip_vdf
|
||||
|
||||
# last ses
|
||||
ses = summaries[uint32(len(summaries) - 1)]
|
||||
|
||||
challenge = ChallengeChainSubSlot(
|
||||
cc_vdf, None, ses.get_hash(), ses.new_sub_slot_iters, ses.new_difficulty
|
||||
).get_hash()
|
||||
|
||||
expected_challenge = weight_proof.recent_reward_chain[block_idx + 1].challenge_chain_sp_vdf.challenge
|
||||
if challenge != expected_challenge:
|
||||
self.log.error(
|
||||
@ -396,7 +409,7 @@ def get_sub_epoch_block_num(last_block: SubBlockRecord, sub_blocks: Dict[bytes32
|
||||
"""
|
||||
# count from end of sub_epoch
|
||||
if last_block.sub_epoch_summary_included is None:
|
||||
raise Exception("block dose not finish a sub_epoch")
|
||||
raise Exception("block does not finish a sub_epoch")
|
||||
|
||||
curr = sub_blocks[last_block.prev_hash]
|
||||
count: uint32 = uint32(0)
|
||||
@ -407,15 +420,13 @@ def get_sub_epoch_block_num(last_block: SubBlockRecord, sub_blocks: Dict[bytes32
|
||||
|
||||
curr = sub_blocks[curr.prev_hash]
|
||||
count += 1
|
||||
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def choose_sub_epoch(sub_epoch_blocks_n: uint32, rng: random.Random, total_number_of_blocks: uint32) -> bool:
|
||||
print("sub_epoch_blocks_n", sub_epoch_blocks_n, "total ", total_number_of_blocks)
|
||||
prob = sub_epoch_blocks_n / total_number_of_blocks
|
||||
print("try sub_epoch ", "with prob ", prob, " ", sub_epoch_blocks_n, "times")
|
||||
for i in range(sub_epoch_blocks_n):
|
||||
if rng.random() < prob:
|
||||
return True
|
||||
@ -459,15 +470,16 @@ def validate_sub_slot_vdfs(
|
||||
|
||||
|
||||
def map_summaries(
|
||||
log,
|
||||
sub_blocks_for_se: uint32,
|
||||
ses_hash: bytes32,
|
||||
weight_proof: WeightProof,
|
||||
sub_epoch_data: List[SubEpochData],
|
||||
curr_difficulty: uint64,
|
||||
curr_sub_slot_iters: uint64,
|
||||
) -> (Dict[uint32, SubEpochSummary], uint128):
|
||||
sub_epoch_data_weight: uint128 = uint128(0)
|
||||
summaries: Dict[uint32, SubEpochSummary] = {}
|
||||
for idx, sub_epoch_data in enumerate(weight_proof.sub_epochs):
|
||||
for idx, sub_epoch_data in enumerate(sub_epoch_data):
|
||||
ses = SubEpochSummary(
|
||||
ses_hash,
|
||||
sub_epoch_data.reward_chain_hash,
|
||||
@ -481,7 +493,12 @@ def map_summaries(
|
||||
curr_difficulty = sub_epoch_data.new_difficulty
|
||||
curr_sub_slot_iters = sub_epoch_data.new_sub_slot_iters
|
||||
|
||||
print(f"map_summaries curr diff {curr_difficulty} sub_blocks_n {sub_blocks_for_se}")
|
||||
log.info(
|
||||
f"sub_epoch {idx} sub_epoch_weight {sub_epoch_data_weight} "
|
||||
f"sub_epoch_diff {curr_difficulty} "
|
||||
f"num of overflow blocks {sub_epoch_data.num_sub_blocks_overflow} "
|
||||
f"se blocks num {sub_blocks_for_se +sub_epoch_data.num_sub_blocks_overflow}"
|
||||
)
|
||||
sub_epoch_data_weight += curr_difficulty * (sub_blocks_for_se + sub_epoch_data.num_sub_blocks_overflow)
|
||||
|
||||
# add to dict
|
||||
|
@ -5,12 +5,13 @@ from typing import Dict, Optional, List
|
||||
import pytest
|
||||
|
||||
from src.consensus.full_block_to_sub_block_record import full_block_to_sub_block_record
|
||||
from src.consensus.pot_iterations import calculate_iterations_quality
|
||||
from src.consensus.pot_iterations import calculate_iterations_quality, is_overflow_sub_block
|
||||
from src.consensus.sub_block_record import SubBlockRecord
|
||||
from src.full_node.weight_proof import (
|
||||
get_sub_epoch_block_num,
|
||||
WeightProofFactory,
|
||||
get_last_ses_block_idx,
|
||||
map_summaries,
|
||||
)
|
||||
from src.types.full_block import FullBlock
|
||||
from src.types.header_block import HeaderBlock
|
||||
@ -44,15 +45,17 @@ def count_sub_epochs(blockchain, last_hash) -> int:
|
||||
return count
|
||||
|
||||
|
||||
def get_prev_ses_block(sub_blocks, last_hash):
|
||||
def get_prev_ses_block(sub_blocks, last_hash) -> (SubBlockRecord, int):
|
||||
curr = sub_blocks[last_hash]
|
||||
blocks = 0
|
||||
while True:
|
||||
assert 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
|
||||
return curr, blocks
|
||||
blocks += 1
|
||||
|
||||
|
||||
def load_blocks_dont_validate(blocks):
|
||||
@ -99,20 +102,18 @@ class TestWeightProof:
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_sub_epoch_block_num_basic(self, blocks):
|
||||
header_cache, height_to_hash, sub_blocks = load_blocks_dont_validate(blocks)
|
||||
sub_epoch_end = get_prev_ses_block(sub_blocks, blocks[-1].header_hash)
|
||||
sub_epoch_end, _ = get_prev_ses_block(sub_blocks, blocks[-1].header_hash)
|
||||
print("first block of last sub epoch ", sub_epoch_end.height)
|
||||
sub_epoch_blocks_n: uint32 = get_sub_epoch_block_num(sub_epoch_end, sub_blocks)
|
||||
print("sub epoch before last has ", sub_epoch_blocks_n, "blocks")
|
||||
assert (
|
||||
sub_epoch_blocks_n
|
||||
== sub_epoch_end.height - get_prev_ses_block(sub_blocks, sub_epoch_end.header_hash).height
|
||||
)
|
||||
prev_sub_epoch_end, _ = get_prev_ses_block(sub_blocks, sub_epoch_end.header_hash)
|
||||
assert sub_epoch_blocks_n == sub_epoch_end.height - prev_sub_epoch_end.height
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_last_ses_block_idx(self, blocks):
|
||||
async def test_get_last_ses_block_idx_(self, blocks):
|
||||
header_cache, height_to_hash, sub_blocks = load_blocks_dont_validate(blocks)
|
||||
sub_epoch_end = get_prev_ses_block(sub_blocks, blocks[-1].prev_header_hash)
|
||||
print(f"sub_epoch_summary_included, height: {sub_epoch_end.height} {sub_epoch_end.sub_epoch_summary_included }")
|
||||
sub_epoch_end, _ = get_prev_ses_block(sub_blocks, blocks[-1].prev_header_hash)
|
||||
print(f"sub_epoch_summary_included, height: {sub_epoch_end.height} {sub_epoch_end.sub_epoch_summary_included}")
|
||||
reward_blocks: List[RewardChainSubBlock] = []
|
||||
for block in header_cache.values():
|
||||
reward_blocks.append(block.reward_chain_sub_block)
|
||||
@ -124,17 +125,83 @@ class TestWeightProof:
|
||||
idx = get_last_ses_block_idx(reward_blocks, first_after_se.weight - sub_epoch_end.weight, sub_epoch_end.weight)
|
||||
assert idx == first_after_se.height
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_weight_proof_map_summaries(self, blocks):
|
||||
header_cache, height_to_hash, sub_blocks = load_blocks_dont_validate(blocks)
|
||||
sub_epoch_idx = 3
|
||||
|
||||
sub_epoch_end, num_of_blocks = get_prev_ses_block(sub_blocks, blocks[-1].header_hash)
|
||||
print("num of blocks to first ses: ", num_of_blocks)
|
||||
first_sub_epoch_summary = None
|
||||
sub_epochs_left = sub_epoch_idx
|
||||
curr = sub_epoch_end
|
||||
|
||||
while True:
|
||||
if curr.sub_epoch_summary_included is not None:
|
||||
print(
|
||||
f"ses height {curr.height} prev overflows {curr.sub_epoch_summary_included.num_sub_blocks_overflow}"
|
||||
)
|
||||
if sub_epochs_left == 0:
|
||||
break
|
||||
sub_epochs_left -= 1
|
||||
|
||||
first_sub_epoch_summary = curr.sub_epoch_summary_included
|
||||
if curr.is_challenge_sub_block(test_constants):
|
||||
print(f"block height {curr.height} is challenge block hash {curr.header_hash}")
|
||||
if is_overflow_sub_block(test_constants, curr.signage_point_index):
|
||||
print(f"block height {curr.height} is overflow")
|
||||
# next sub block
|
||||
curr = sub_blocks[curr.prev_hash]
|
||||
num_of_blocks += 1
|
||||
|
||||
print(f"fork point is {curr.height}")
|
||||
print(f"num of blocks in proof: {num_of_blocks}")
|
||||
print(f"num of full sub epochs in proof: {sub_epoch_idx}")
|
||||
wpf = WeightProofFactory(test_constants, sub_blocks, header_cache, height_to_hash)
|
||||
wpf.log.setLevel(logging.INFO)
|
||||
initialize_logging("", {"log_stdout": True}, DEFAULT_ROOT_PATH)
|
||||
wp = wpf.make_weight_proof(uint32(len(header_cache)), uint32(num_of_blocks), blocks[-1].header_hash)
|
||||
assert wp is not None
|
||||
first_after_se = sub_blocks[height_to_hash[sub_epoch_end.height + 1]]
|
||||
curr_difficulty = first_after_se.weight - sub_epoch_end.weight
|
||||
fork_point_difficulty = uint64(curr.weight - sub_blocks[curr.prev_hash].weight)
|
||||
print(f"diff {curr_difficulty}, weight {sub_epoch_end.weight}")
|
||||
|
||||
# sub epoch summaries validate hashes
|
||||
summaries, sub_epoch_data_weight = map_summaries(
|
||||
wpf.log,
|
||||
test_constants.SUB_EPOCH_SUB_BLOCKS,
|
||||
first_sub_epoch_summary.prev_subepoch_summary_hash,
|
||||
wp.sub_epochs,
|
||||
fork_point_difficulty,
|
||||
first_after_se.sub_slot_iters,
|
||||
)
|
||||
|
||||
found = False
|
||||
for idx, sub_epoch_data in enumerate(wp.sub_epochs):
|
||||
print(f"sub epoch: {idx} prev num of overflow: {sub_epoch_data.num_sub_blocks_overflow}")
|
||||
|
||||
# validate summary hashes
|
||||
while curr.height > 0:
|
||||
block = header_cache[curr.prev_hash]
|
||||
if block.reward_chain_sub_block.challenge_chain_sp_vdf.challenge == summaries[0].get_hash():
|
||||
found = True
|
||||
break
|
||||
|
||||
assert found
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_weight_proof(self, blocks):
|
||||
header_cache, height_to_hash, sub_blocks = load_blocks_dont_validate(blocks)
|
||||
sub_epoch_idx = 3
|
||||
num_of_blocks = uint32(0)
|
||||
sub_epoch_end = get_prev_ses_block(sub_blocks, blocks[-1].prev_header_hash)
|
||||
sub_epoch_end, _ = get_prev_ses_block(sub_blocks, blocks[-1].prev_header_hash)
|
||||
first_sub_epoch_summary = None
|
||||
print("total blocks: ", len(sub_blocks))
|
||||
sub_epochs_left = sub_epoch_idx
|
||||
sub_epoch_sub_blocks = 0
|
||||
curr = sub_epoch_end
|
||||
curr = sub_blocks[blocks[-1].header_hash]
|
||||
|
||||
while not sub_epochs_left == 0:
|
||||
if curr.sub_epoch_summary_included is not None:
|
||||
print(f"block {curr.height} has ses,ses sub blocks {sub_epoch_sub_blocks}")
|
||||
@ -154,11 +221,10 @@ class TestWeightProof:
|
||||
wpf = WeightProofFactory(test_constants, sub_blocks, header_cache, height_to_hash)
|
||||
wpf.log.setLevel(logging.INFO)
|
||||
initialize_logging("", {"log_stdout": True}, DEFAULT_ROOT_PATH)
|
||||
wp = wpf.make_weight_proof(uint32(len(header_cache)), num_of_blocks)
|
||||
wp = wpf.make_weight_proof(uint32(len(header_cache)), num_of_blocks, blocks[-1].header_hash)
|
||||
|
||||
assert wp is not None
|
||||
assert len(wp.sub_epochs) > 0
|
||||
assert len(wp.sub_epoch_segments) > 0
|
||||
assert len(wp.sub_epochs) == sub_epoch_idx
|
||||
# for each sampled sub epoch, validate number of segments
|
||||
challenges_sub_epoch_n: Dict[int, int] = {}
|
||||
# map challenges per sub_epoch
|
||||
@ -173,13 +239,15 @@ class TestWeightProof:
|
||||
|
||||
first_after_se = sub_blocks[height_to_hash[sub_epoch_end.height + 1]]
|
||||
curr_difficulty = first_after_se.weight - sub_epoch_end.weight
|
||||
fork_point_difficulty = uint64(curr.weight - sub_blocks[curr.prev_hash].weight)
|
||||
print(f"diff {curr_difficulty}, weight {sub_epoch_end.weight}")
|
||||
|
||||
valid = wpf.validate_weight(
|
||||
wp,
|
||||
first_sub_epoch_summary.prev_subepoch_summary_hash,
|
||||
test_constants.DIFFICULTY_STARTING,
|
||||
first_after_se.sub_slot_iters,
|
||||
fork_point_difficulty,
|
||||
curr.sub_slot_iters,
|
||||
curr.weight,
|
||||
)
|
||||
|
||||
assert valid
|
||||
|
Loading…
Reference in New Issue
Block a user