use rust types for slots, SubEpochSummary and SubEpochData (#17298)

* use rust types for slots, SubEpochSummary and SubEpochData

* use rust type for EndOfSubSlotBundle

* use rust types for SubEpochChallengeSegment, SubEpochSegments and SubSlotData
This commit is contained in:
Arvid Norberg 2024-01-16 18:04:49 +01:00 committed by GitHub
parent f483328276
commit c6d5f7fa1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 66 additions and 199 deletions

View File

@ -62,8 +62,8 @@ def block_to_block_record(
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,
uint64.construct_optional(block.finished_sub_slots[0].challenge_chain.new_difficulty),
uint64.construct_optional(block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters),
)
if ses.get_hash() != found_ses_hash:
raise ValueError(Err.INVALID_SUB_EPOCH_SUMMARY)

View File

@ -2233,9 +2233,9 @@ class FullNode:
if new_infusions is not None:
self.log.info(
f"⏲️ Finished sub slot, SP {self.constants.NUM_SPS_SUB_SLOT}/{self.constants.NUM_SPS_SUB_SLOT}, "
f"{end_of_slot_bundle.challenge_chain.get_hash()}, "
f"{end_of_slot_bundle.challenge_chain.get_hash().hex()}, "
f"number of sub-slots: {len(self.full_node_store.finished_sub_slots)}, "
f"RC hash: {end_of_slot_bundle.reward_chain.get_hash()}, "
f"RC hash: {end_of_slot_bundle.reward_chain.get_hash().hex()}, "
f"Deficit {end_of_slot_bundle.reward_chain.deficit}"
)
# Reset farmer response timer for sub slot (SP 0)
@ -2448,8 +2448,8 @@ class FullNode:
if field_vdf == CompressibleVDFField.CC_EOS_VDF:
for index, sub_slot in enumerate(block.finished_sub_slots):
if sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf == vdf_info:
new_proofs = dataclasses.replace(sub_slot.proofs, challenge_chain_slot_proof=vdf_proof)
new_subslot = dataclasses.replace(sub_slot, proofs=new_proofs)
new_proofs = sub_slot.proofs.replace(challenge_chain_slot_proof=vdf_proof)
new_subslot = sub_slot.replace(proofs=new_proofs)
new_finished_subslots = block.finished_sub_slots
new_finished_subslots[index] = new_subslot
new_block = dataclasses.replace(block, finished_sub_slots=new_finished_subslots)
@ -2460,8 +2460,8 @@ class FullNode:
sub_slot.infused_challenge_chain is not None
and sub_slot.infused_challenge_chain.infused_challenge_chain_end_of_slot_vdf == vdf_info
):
new_proofs = dataclasses.replace(sub_slot.proofs, infused_challenge_chain_slot_proof=vdf_proof)
new_subslot = dataclasses.replace(sub_slot, proofs=new_proofs)
new_proofs = sub_slot.proofs.replace(infused_challenge_chain_slot_proof=vdf_proof)
new_subslot = sub_slot.replace(proofs=new_proofs)
new_finished_subslots = block.finished_sub_slots
new_finished_subslots[index] = new_subslot
new_block = dataclasses.replace(block, finished_sub_slots=new_finished_subslots)

View File

@ -880,9 +880,9 @@ class FullNodeAPI:
sub_slot_iters = peak.sub_slot_iters
for sub_slot in finished_sub_slots:
if sub_slot.challenge_chain.new_difficulty is not None:
difficulty = sub_slot.challenge_chain.new_difficulty
difficulty = uint64(sub_slot.challenge_chain.new_difficulty)
if sub_slot.challenge_chain.new_sub_slot_iters is not None:
sub_slot_iters = sub_slot.challenge_chain.new_sub_slot_iters
sub_slot_iters = uint64(sub_slot.challenge_chain.new_sub_slot_iters)
required_iters: uint64 = calculate_iterations_quality(
self.full_node.constants.DIFFICULTY_CONSTANT_FACTOR,

View File

@ -707,10 +707,10 @@ def _create_sub_epoch_data(
) -> SubEpochData:
reward_chain_hash: bytes32 = sub_epoch_summary.reward_chain_hash
# Number of subblocks overflow in previous slot
previous_sub_epoch_overflows: uint8 = sub_epoch_summary.num_blocks_overflow # total in sub epoch - expected
previous_sub_epoch_overflows = uint8(sub_epoch_summary.num_blocks_overflow) # total in sub epoch - expected
# New work difficulty and iterations per sub-slot
sub_slot_iters: Optional[uint64] = sub_epoch_summary.new_sub_slot_iters
new_difficulty: Optional[uint64] = sub_epoch_summary.new_difficulty
sub_slot_iters: Optional[int] = sub_epoch_summary.new_sub_slot_iters
new_difficulty: Optional[int] = sub_epoch_summary.new_difficulty
return SubEpochData(reward_chain_hash, previous_sub_epoch_overflows, sub_slot_iters, new_difficulty)
@ -886,7 +886,7 @@ def _map_sub_epoch_summaries(
# if new epoch update diff and iters
if data.new_difficulty is not None:
curr_difficulty = data.new_difficulty
curr_difficulty = uint64(data.new_difficulty)
# add to dict
summaries.append(ses)
@ -998,7 +998,7 @@ def _validate_segment(
return False, uint64(0), uint64(0), uint64(0), []
assert sub_slot_data.signage_point_index is not None
ip_iters = ip_iters + calculate_ip_iters(
constants, curr_ssi, sub_slot_data.signage_point_index, required_iters
constants, curr_ssi, uint8(sub_slot_data.signage_point_index), required_iters
)
vdf_list = _get_challenge_block_vdfs(constants, idx, segment.sub_slots, curr_ssi)
to_validate.extend(vdf_list)
@ -1025,7 +1025,7 @@ def _get_challenge_block_vdfs(
assert sub_slot_data.signage_point_index
sp_input = ClassgroupElement.get_default_element()
if not sub_slot_data.cc_signage_point.normalized_to_identity and sub_slot_idx >= 1:
is_overflow = is_overflow_block(constants, sub_slot_data.signage_point_index)
is_overflow = is_overflow_block(constants, uint8(sub_slot_data.signage_point_index))
prev_ssd = sub_slots[sub_slot_idx - 1]
sp_input = sub_slot_data_vdf_input(
constants, sub_slot_data, sub_slot_idx, sub_slots, is_overflow, prev_ssd.is_end_of_slot(), ssi
@ -1103,7 +1103,7 @@ def _validate_sub_slot_data(
assert sub_slot_data.cc_sp_vdf_info
input = ClassgroupElement.get_default_element()
if not sub_slot_data.cc_signage_point.normalized_to_identity:
is_overflow = is_overflow_block(constants, sub_slot_data.signage_point_index)
is_overflow = is_overflow_block(constants, uint8(sub_slot_data.signage_point_index))
input = sub_slot_data_vdf_input(
constants, sub_slot_data, sub_slot_idx, sub_slots, is_overflow, prev_ssd.is_end_of_slot(), ssi
)
@ -1208,9 +1208,9 @@ def validate_recent_blocks(
last_blocks_to_validate = 100 # todo remove cap after benchmarks
for summary in summaries[:ses_idx]:
if summary.new_sub_slot_iters is not None:
ssi = summary.new_sub_slot_iters
ssi = uint64(summary.new_sub_slot_iters)
if summary.new_difficulty is not None:
diff = summary.new_difficulty
diff = uint64(summary.new_difficulty)
ses_blocks, sub_slots, transaction_blocks = 0, 0, 0
challenge, prev_challenge = recent_chain.recent_chain_data[0].reward_chain_block.pos_ss_cc_challenge_hash, None
@ -1226,15 +1226,15 @@ def validate_recent_blocks(
for sub_slot in block.finished_sub_slots:
prev_challenge = sub_slot.challenge_chain.challenge_chain_end_of_slot_vdf.challenge
challenge = sub_slot.challenge_chain.get_hash()
deficit = sub_slot.reward_chain.deficit
deficit = uint8(sub_slot.reward_chain.deficit)
if sub_slot.challenge_chain.subepoch_summary_hash is not None:
ses = True
assert summaries[ses_idx].get_hash() == sub_slot.challenge_chain.subepoch_summary_hash
ses_idx += 1
if sub_slot.challenge_chain.new_sub_slot_iters is not None:
ssi = sub_slot.challenge_chain.new_sub_slot_iters
ssi = uint64(sub_slot.challenge_chain.new_sub_slot_iters)
if sub_slot.challenge_chain.new_difficulty is not None:
diff = sub_slot.challenge_chain.new_difficulty
diff = uint64(sub_slot.challenge_chain.new_difficulty)
if (challenge is not None) and (prev_challenge is not None):
overflow = is_overflow_block(constants, uint8(block.reward_chain_block.signage_point_index))
@ -1334,7 +1334,7 @@ def __validate_pospace(
sub_slot_data: SubSlotData = segment.sub_slots[idx]
if sub_slot_data.signage_point_index and is_overflow_block(constants, sub_slot_data.signage_point_index):
if sub_slot_data.signage_point_index and is_overflow_block(constants, uint8(sub_slot_data.signage_point_index)):
curr_slot = segment.sub_slots[idx - 1]
assert curr_slot.cc_slot_end_info
challenge = curr_slot.cc_slot_end_info.challenge
@ -1391,14 +1391,14 @@ def __get_rc_sub_slot(
slots_n = 1
assert first
assert first.signage_point_index is not None
if is_overflow_block(constants, first.signage_point_index):
if is_overflow_block(constants, uint8(first.signage_point_index)):
if idx >= 2 and slots[idx - 2].cc_slot_end is None:
slots_n = 2
new_diff = None if ses is None else ses.new_difficulty
new_ssi = None if ses is None else ses.new_sub_slot_iters
ses_hash: Optional[bytes32] = None if ses is None else ses.get_hash()
overflow = is_overflow_block(constants, first.signage_point_index)
overflow = is_overflow_block(constants, uint8(first.signage_point_index))
if overflow:
if idx >= 2 and slots[idx - 2].cc_slot_end is not None and slots[idx - 1].cc_slot_end is not None:
ses_hash = None
@ -1483,9 +1483,9 @@ def _get_curr_diff_ssi(
curr_ssi = constants.SUB_SLOT_ITERS_STARTING
for ses in reversed(summaries[0:idx]):
if ses.new_sub_slot_iters is not None:
curr_ssi = ses.new_sub_slot_iters
curr_ssi = uint64(ses.new_sub_slot_iters)
assert ses.new_difficulty is not None
curr_difficulty = ses.new_difficulty
curr_difficulty = uint64(ses.new_difficulty)
break
return curr_difficulty, curr_ssi
@ -1558,7 +1558,7 @@ def get_sp_total_iters(
assert sub_slot_data.cc_ip_vdf_info is not None
assert sub_slot_data.total_iters is not None
assert sub_slot_data.signage_point_index is not None
sp_iters: uint64 = calculate_sp_iters(constants, ssi, sub_slot_data.signage_point_index)
sp_iters: uint64 = calculate_sp_iters(constants, ssi, uint8(sub_slot_data.signage_point_index))
ip_iters: uint64 = uint64(sub_slot_data.cc_ip_vdf_info.number_of_iterations)
sp_sub_slot_total_iters = uint128(sub_slot_data.total_iters - ip_iters)
if is_overflow:

View File

@ -981,8 +981,8 @@ class BlockTools:
pending_ses = True
ses_hash: Optional[bytes32] = sub_epoch_summary.get_hash()
# if the last block is the last block of the epoch, we set the new sub-slot iters and difficulty
new_sub_slot_iters: Optional[uint64] = sub_epoch_summary.new_sub_slot_iters
new_difficulty: Optional[uint64] = sub_epoch_summary.new_difficulty
new_sub_slot_iters: Optional[uint64] = uint64.construct_optional(sub_epoch_summary.new_sub_slot_iters)
new_difficulty: Optional[uint64] = uint64.construct_optional(sub_epoch_summary.new_difficulty)
self.log.info(f"Sub epoch summary: {sub_epoch_summary} for block {latest_block.height+1}")
else: # the previous block is not the last block of the sub-epoch or epoch
@ -1252,8 +1252,8 @@ class BlockTools:
num_empty_slots_added += 1
if new_sub_slot_iters is not None and new_difficulty is not None: # new epoch
sub_slot_iters = new_sub_slot_iters
difficulty = new_difficulty
sub_slot_iters = uint64(new_sub_slot_iters)
difficulty = uint64(new_difficulty)
def create_genesis_block(
self,
@ -1750,7 +1750,7 @@ def get_icc(
if len(finished_sub_slots) == 0:
prev_deficit = latest_block.deficit
else:
prev_deficit = finished_sub_slots[-1].reward_chain.deficit
prev_deficit = uint8(finished_sub_slots[-1].reward_chain.deficit)
if deficit == prev_deficit == constants.MIN_BLOCKS_PER_CHALLENGE_BLOCK:
# new slot / overflow sb to new slot / overflow sb

View File

@ -87,11 +87,11 @@ class LastState:
self.peak = None
self.subslot_end = state
self.last_ip = uint64(0)
self.deficit = state.reward_chain.deficit
self.deficit = uint8(state.reward_chain.deficit)
if state.challenge_chain.new_difficulty is not None:
assert state.challenge_chain.new_sub_slot_iters is not None
self.difficulty = state.challenge_chain.new_difficulty
self.sub_slot_iters = state.challenge_chain.new_sub_slot_iters
self.difficulty = uint64(state.challenge_chain.new_difficulty)
self.sub_slot_iters = uint64(state.challenge_chain.new_sub_slot_iters)
self.new_epoch = True
else:
self.new_epoch = False

View File

@ -1,54 +1,9 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
import chia_rs
from chia_rs import G2Element
from chia.types.blockchain_format.proof_of_space import ProofOfSpace
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.blockchain_format.vdf import VDFInfo, VDFProof
from chia.util.ints import uint8, uint64
from chia.util.streamable import Streamable, streamable
@streamable
@dataclass(frozen=True)
class ChallengeBlockInfo(Streamable): # The hash of this is used as the challenge_hash for the ICC VDF
proof_of_space: ProofOfSpace
challenge_chain_sp_vdf: Optional[VDFInfo] # Only present if not the first sp
challenge_chain_sp_signature: G2Element
challenge_chain_ip_vdf: VDFInfo
@streamable
@dataclass(frozen=True)
class ChallengeChainSubSlot(Streamable):
challenge_chain_end_of_slot_vdf: VDFInfo
infused_challenge_chain_sub_slot_hash: Optional[bytes32] # Only at the end of a slot
subepoch_summary_hash: Optional[bytes32] # Only once per sub-epoch, and one sub-epoch delayed
new_sub_slot_iters: Optional[uint64] # Only at the end of epoch, sub-epoch, and slot
new_difficulty: Optional[uint64] # Only at the end of epoch, sub-epoch, and slot
@streamable
@dataclass(frozen=True)
class InfusedChallengeChainSubSlot(Streamable):
infused_challenge_chain_end_of_slot_vdf: VDFInfo
@streamable
@dataclass(frozen=True)
class RewardChainSubSlot(Streamable):
end_of_slot_vdf: VDFInfo
challenge_chain_sub_slot_hash: bytes32
infused_challenge_chain_sub_slot_hash: Optional[bytes32]
deficit: uint8 # 16 or less. usually zero
@streamable
@dataclass(frozen=True)
class SubSlotProofs(Streamable):
challenge_chain_slot_proof: VDFProof
infused_challenge_chain_slot_proof: Optional[VDFProof]
reward_chain_slot_proof: VDFProof
ChallengeBlockInfo = chia_rs.ChallengeBlockInfo
ChallengeChainSubSlot = chia_rs.ChallengeChainSubSlot
InfusedChallengeChainSubSlot = chia_rs.InfusedChallengeChainSubSlot
RewardChainSubSlot = chia_rs.RewardChainSubSlot
SubSlotProofs = chia_rs.SubSlotProofs

View File

@ -1,18 +1,5 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
import chia_rs
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.ints import uint8, uint64
from chia.util.streamable import Streamable, streamable
@streamable
@dataclass(frozen=True)
class SubEpochSummary(Streamable):
prev_subepoch_summary_hash: bytes32
reward_chain_hash: bytes32 # hash of reward chain at end of last segment
num_blocks_overflow: uint8 # How many more blocks than 384*(N-1)
new_difficulty: Optional[uint64] # Only once per epoch (diff adjustment)
new_sub_slot_iters: Optional[uint64] # Only once per epoch (diff adjustment)
SubEpochSummary = chia_rs.SubEpochSummary

View File

@ -1,21 +1,5 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import Optional
import chia_rs
from chia.types.blockchain_format.slots import (
ChallengeChainSubSlot,
InfusedChallengeChainSubSlot,
RewardChainSubSlot,
SubSlotProofs,
)
from chia.util.streamable import Streamable, streamable
@streamable
@dataclass(frozen=True)
class EndOfSubSlotBundle(Streamable):
challenge_chain: ChallengeChainSubSlot
infused_challenge_chain: Optional[InfusedChallengeChainSubSlot]
reward_chain: RewardChainSubSlot
proofs: SubSlotProofs
EndOfSubSlotBundle = chia_rs.EndOfSubSlotBundle

View File

@ -1,26 +1,16 @@
from __future__ import annotations
from dataclasses import dataclass
from typing import List, Optional
from typing import List
import chia_rs
from chia.types.blockchain_format.proof_of_space import ProofOfSpace
from chia.types.blockchain_format.reward_chain_block import RewardChainBlock
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.blockchain_format.vdf import VDFInfo, VDFProof
from chia.types.end_of_slot_bundle import EndOfSubSlotBundle
from chia.types.header_block import HeaderBlock
from chia.util.ints import uint8, uint32, uint64, uint128
from chia.util.streamable import Streamable, streamable
@streamable
@dataclass(frozen=True)
class SubEpochData(Streamable):
reward_chain_hash: bytes32
num_blocks_overflow: uint8
new_sub_slot_iters: Optional[uint64]
new_difficulty: Optional[uint64]
SubEpochData = chia_rs.SubEpochData
# number of challenge blocks
# Average iters for challenge blocks
@ -33,53 +23,9 @@ class SubEpochData(Streamable):
# total number of challenge blocks == total number of reward chain blocks
@streamable
@dataclass(frozen=True)
class SubSlotData(Streamable):
# if infused
proof_of_space: Optional[ProofOfSpace]
# 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]
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]
cc_ip_vdf_info: Optional[VDFInfo]
icc_ip_vdf_info: Optional[VDFInfo]
total_iters: Optional[uint128]
def is_challenge(self) -> bool:
if self.proof_of_space is not None:
return True
return False
def is_end_of_slot(self) -> bool:
if self.cc_slot_end_info is not None:
return True
return False
@streamable
@dataclass(frozen=True)
class SubEpochChallengeSegment(Streamable):
sub_epoch_n: uint32
sub_slots: List[SubSlotData]
rc_slot_end_info: Optional[VDFInfo] # in first segment of each sub_epoch
@streamable
@dataclass(frozen=True)
# this is used only for serialization to database
class SubEpochSegments(Streamable):
challenge_segments: List[SubEpochChallengeSegment]
SubEpochChallengeSegment = chia_rs.SubEpochChallengeSegment
SubEpochSegments = chia_rs.SubEpochSegments
SubSlotData = chia_rs.SubSlotData
@streamable

View File

@ -99,8 +99,8 @@ class WalletBlockchain(BlockchainInterface):
and block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters is not None
):
assert block.finished_sub_slots[0].challenge_chain.new_difficulty is not None # They both change together
sub_slot_iters: uint64 = block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters
difficulty: uint64 = block.finished_sub_slots[0].challenge_chain.new_difficulty
sub_slot_iters = uint64(block.finished_sub_slots[0].challenge_chain.new_sub_slot_iters)
difficulty = uint64(block.finished_sub_slots[0].challenge_chain.new_difficulty)
else:
sub_slot_iters = self._sub_slot_iters
difficulty = self._difficulty

View File

@ -657,8 +657,7 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
block.finished_sub_slots[-1],
"challenge_chain",
replace(
block.finished_sub_slots[-1].challenge_chain,
block.finished_sub_slots[-1].challenge_chain.replace(
infused_challenge_chain_sub_slot_hash=bytes([1] * 32),
),
)
@ -668,8 +667,7 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
block.finished_sub_slots[-1],
"challenge_chain",
replace(
block.finished_sub_slots[-1].challenge_chain,
block.finished_sub_slots[-1].challenge_chain.replace(
infused_challenge_chain_sub_slot_hash=block.finished_sub_slots[
-1
].infused_challenge_chain.get_hash(),
@ -695,7 +693,7 @@ class TestBlockHeaderValidation:
new_finished_ss_bad_rc = recursive_replace(
block.finished_sub_slots[-1],
"reward_chain",
replace(block.finished_sub_slots[-1].reward_chain, infused_challenge_chain_sub_slot_hash=None),
block.finished_sub_slots[-1].reward_chain.replace(infused_challenge_chain_sub_slot_hash=None),
)
block_bad = recursive_replace(
block, "finished_sub_slots", block.finished_sub_slots[:-1] + [new_finished_ss_bad_rc]
@ -743,7 +741,7 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
blocks[-1].finished_sub_slots[-1],
"challenge_chain",
replace(blocks[-1].finished_sub_slots[-1].challenge_chain, subepoch_summary_hash=std_hash(b"0")),
blocks[-1].finished_sub_slots[-1].challenge_chain.replace(subepoch_summary_hash=std_hash(b"0")),
)
block_bad = recursive_replace(
blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
@ -791,7 +789,7 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
blocks[-1].finished_sub_slots[-1],
"reward_chain",
replace(blocks[-1].finished_sub_slots[-1].reward_chain, challenge_chain_sub_slot_hash=bytes([3] * 32)),
blocks[-1].finished_sub_slots[-1].reward_chain.replace(challenge_chain_sub_slot_hash=bytes([3] * 32)),
)
block_1_bad = recursive_replace(
blocks[-1], "finished_sub_slots", blocks[-1].finished_sub_slots[:-1] + [new_finished_ss]
@ -1037,8 +1035,8 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
new_finished_ss,
"reward_chain",
replace(
new_finished_ss.reward_chain, challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
new_finished_ss.reward_chain.replace(
challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash()
),
)
block_bad = recursive_replace(block, "finished_sub_slots", [new_finished_ss] + block.finished_sub_slots[1:])
@ -1072,8 +1070,7 @@ class TestBlockHeaderValidation:
new_finished_ss = recursive_replace(
new_finished_ss,
"reward_chain",
replace(
new_finished_ss.reward_chain,
new_finished_ss.reward_chain.replace(
challenge_chain_sub_slot_hash=new_finished_ss.challenge_chain.get_hash(),
),
)

View File

@ -1586,12 +1586,10 @@ class TestFullNodeProtocol:
# Submit the sub slot, but not the last block
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1, force_overflow=True)
for ss in blocks[-1].finished_sub_slots:
challenge_chain = dataclasses.replace(
ss.challenge_chain,
challenge_chain = ss.challenge_chain.replace(
new_difficulty=20,
)
slot2 = dataclasses.replace(
ss,
slot2 = ss.replace(
challenge_chain=challenge_chain,
)
await full_node_1.respond_end_of_sub_slot(fnp.RespondEndOfSubSlot(slot2), peer)

View File

@ -555,7 +555,7 @@ def test_recursive_types() -> None:
def test_ambiguous_deserialization_optionals() -> None:
with pytest.raises(AssertionError):
with pytest.raises(ValueError, match="unexpected end of buffer"):
SubEpochChallengeSegment.from_bytes(b"\x00\x00\x00\x03\xff\xff\xff\xff")
@streamable