Fix issues with empty slots after epochs
This commit is contained in:
parent
eb1cddbee4
commit
0cf7eb7850
|
@ -197,6 +197,7 @@ def create_foliage(
|
|||
def create_unfinished_block(
|
||||
constants: ConsensusConstants,
|
||||
sub_slot_start_total_iters: uint128,
|
||||
sub_slot_iters: uint64,
|
||||
signage_point_index: uint8,
|
||||
sp_iters: uint64,
|
||||
ip_iters: uint64,
|
||||
|
@ -221,12 +222,10 @@ def create_unfinished_block(
|
|||
if prev_sub_block is not None:
|
||||
curr = prev_sub_block
|
||||
is_block, prev_block = get_prev_block(curr, prev_block, sub_blocks, total_iters_sp)
|
||||
prev_sub_slot_iters: uint64 = prev_sub_block.sub_slot_iters
|
||||
else:
|
||||
# Genesis is a block
|
||||
is_genesis = True
|
||||
is_block = True
|
||||
prev_sub_slot_iters = constants.SUB_SLOT_ITERS_STARTING
|
||||
|
||||
new_sub_slot: bool = len(finished_sub_slots) > 0
|
||||
|
||||
|
@ -255,7 +254,7 @@ def create_unfinished_block(
|
|||
assert rc_sp_signature is not None
|
||||
assert blspy.AugSchemeMPL.verify(proof_of_space.plot_public_key, cc_sp_hash, cc_sp_signature)
|
||||
|
||||
total_iters = uint128(sub_slot_start_total_iters + ip_iters + (prev_sub_slot_iters if overflow else 0))
|
||||
total_iters = uint128(sub_slot_start_total_iters + ip_iters + (sub_slot_iters if overflow else 0))
|
||||
|
||||
rc_sub_block = RewardChainSubBlockUnfinished(
|
||||
total_iters,
|
||||
|
|
|
@ -218,7 +218,7 @@ async def validate_unfinished_header_block(
|
|||
if sub_slot.challenge_chain.subepoch_summary_hash is not None:
|
||||
return None, ValidationError(Err.INVALID_SUB_EPOCH_SUMMARY_HASH)
|
||||
|
||||
if can_finish_epoch:
|
||||
if can_finish_epoch and sub_slot.challenge_chain.subepoch_summary_hash is not None:
|
||||
# 2m. Check new difficulty and ssi
|
||||
if sub_slot.challenge_chain.new_sub_slot_iters != sub_slot_iters:
|
||||
return None, ValidationError(Err.INVALID_NEW_SUB_SLOT_ITERS)
|
||||
|
@ -357,7 +357,7 @@ async def validate_unfinished_header_block(
|
|||
)
|
||||
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:
|
||||
if can_finish_se or can_finish_epoch:
|
||||
return None, ValidationError(
|
||||
Err.INVALID_SUB_EPOCH_SUMMARY, "block finishes sub-epoch but ses-hash is None"
|
||||
)
|
||||
|
|
|
@ -1045,6 +1045,7 @@ class FullNode:
|
|||
unfinished_block: Optional[UnfinishedBlock] = create_unfinished_block(
|
||||
self.constants,
|
||||
total_iters_pos_slot,
|
||||
sub_slot_iters,
|
||||
request.signage_point_index,
|
||||
sp_iters,
|
||||
ip_iters,
|
||||
|
|
|
@ -57,23 +57,6 @@ class FullNodeStore:
|
|||
self.initialize_genesis_sub_slot()
|
||||
return self
|
||||
|
||||
def add_disconnected_block(self, block: FullBlock) -> None:
|
||||
self.disconnected_blocks[block.header_hash] = block
|
||||
|
||||
def get_disconnected_block_by_prev(self, prev_header_hash: bytes32) -> Optional[FullBlock]:
|
||||
for _, block in self.disconnected_blocks.items():
|
||||
if block.prev_header_hash == prev_header_hash:
|
||||
return block
|
||||
return None
|
||||
|
||||
def get_disconnected_block(self, header_hash: bytes32) -> Optional[FullBlock]:
|
||||
return self.disconnected_blocks.get(header_hash, None)
|
||||
|
||||
def clear_disconnected_blocks_below(self, height: uint32) -> None:
|
||||
for key in list(self.disconnected_blocks.keys()):
|
||||
if self.disconnected_blocks[key].height < height:
|
||||
del self.disconnected_blocks[key]
|
||||
|
||||
def add_candidate_block(
|
||||
self,
|
||||
quality_string: bytes32,
|
||||
|
@ -95,12 +78,6 @@ class FullNodeStore:
|
|||
except KeyError:
|
||||
pass
|
||||
|
||||
def add_unfinished_block(self, unfinished_block: UnfinishedBlock) -> None:
|
||||
self.unfinished_blocks[unfinished_block.reward_chain_sub_block.get_hash()] = unfinished_block
|
||||
|
||||
def get_unfinished_block(self, unfinished_reward_hash: bytes32) -> Optional[UnfinishedBlock]:
|
||||
return self.unfinished_blocks.get(unfinished_reward_hash, None)
|
||||
|
||||
def seen_unfinished_block(self, temp_header_hash: bytes32) -> bool:
|
||||
if temp_header_hash in self.seen_unfinished_blocks:
|
||||
return True
|
||||
|
@ -110,6 +87,29 @@ class FullNodeStore:
|
|||
def clear_seen_unfinished_blocks(self) -> None:
|
||||
self.seen_unfinished_blocks.clear()
|
||||
|
||||
def add_disconnected_block(self, block: FullBlock) -> None:
|
||||
self.disconnected_blocks[block.header_hash] = block
|
||||
|
||||
def get_disconnected_block_by_prev(self, prev_header_hash: bytes32) -> Optional[FullBlock]:
|
||||
for _, block in self.disconnected_blocks.items():
|
||||
if block.prev_header_hash == prev_header_hash:
|
||||
return block
|
||||
return None
|
||||
|
||||
def get_disconnected_block(self, header_hash: bytes32) -> Optional[FullBlock]:
|
||||
return self.disconnected_blocks.get(header_hash, None)
|
||||
|
||||
def clear_disconnected_blocks_below(self, height: uint32) -> None:
|
||||
for key in list(self.disconnected_blocks.keys()):
|
||||
if self.disconnected_blocks[key].height < height:
|
||||
del self.disconnected_blocks[key]
|
||||
|
||||
def add_unfinished_block(self, unfinished_block: UnfinishedBlock) -> None:
|
||||
self.unfinished_blocks[unfinished_block.reward_chain_sub_block.get_hash()] = unfinished_block
|
||||
|
||||
def get_unfinished_block(self, unfinished_reward_hash: bytes32) -> Optional[UnfinishedBlock]:
|
||||
return self.unfinished_blocks.get(unfinished_reward_hash, None)
|
||||
|
||||
def get_unfinished_blocks(self) -> Dict[bytes32, UnfinishedBlock]:
|
||||
return self.unfinished_blocks
|
||||
|
||||
|
@ -146,7 +146,7 @@ class FullNodeStore:
|
|||
|
||||
def new_finished_sub_slot(
|
||||
self, eos: EndOfSubSlotBundle, sub_blocks: Dict[bytes32, SubBlockRecord], peak: Optional[SubBlockRecord]
|
||||
):
|
||||
) -> bool:
|
||||
"""
|
||||
Returns true if finished slot successfully added.
|
||||
TODO: do full validation here
|
||||
|
@ -357,9 +357,7 @@ class FullNodeStore:
|
|||
self,
|
||||
peak: SubBlockRecord,
|
||||
peak_sub_slot: Optional[EndOfSubSlotBundle], # None if in first slot
|
||||
total_iters: uint128,
|
||||
prev_sub_slot: Optional[EndOfSubSlotBundle], # None if not overflow, or in first/second slot
|
||||
prev_sub_slot_total_iters: Optional[uint128], # None if not overflow
|
||||
reorg: bool,
|
||||
sub_blocks: Dict[bytes32, SubBlockRecord],
|
||||
) -> Optional[EndOfSubSlotBundle]:
|
||||
|
@ -368,10 +366,11 @@ class FullNodeStore:
|
|||
the prev sub-slot (since we still might get more sub-blocks with an sp in the previous sub-slot)
|
||||
"""
|
||||
new_finished_sub_slots = []
|
||||
total_iters = peak.infusion_sub_slot_total_iters(self.constants)
|
||||
if not reorg:
|
||||
# This is a new peak that adds to the last peak. We can clear data in old sub-slots. (and new ones)
|
||||
for index, (sub_slot, sps, total_iters) in enumerate(self.finished_sub_slots):
|
||||
if prev_sub_slot_total_iters is not None:
|
||||
if peak.overflow and prev_sub_slot is not None:
|
||||
if sub_slot == prev_sub_slot:
|
||||
# In the case of a peak overflow sub-block, the previous sub-slot is added
|
||||
new_finished_sub_slots.append((sub_slot, sps, total_iters))
|
||||
|
@ -384,7 +383,8 @@ class FullNodeStore:
|
|||
# This is either a reorg, which means some sub-blocks are reverted, or this sub slot is not in our current
|
||||
# cache, delete the entire cache and add this sub slot.
|
||||
self.clear_slots()
|
||||
if prev_sub_slot_total_iters is not None:
|
||||
if peak.overflow and prev_sub_slot is not None:
|
||||
prev_sub_slot_total_iters = peak.pos_sub_slot_total_iters(self.constants)
|
||||
self.finished_sub_slots = [(prev_sub_slot, {}, prev_sub_slot_total_iters)]
|
||||
self.finished_sub_slots.append((peak_sub_slot, {}, total_iters))
|
||||
|
||||
|
@ -398,7 +398,7 @@ class FullNodeStore:
|
|||
self,
|
||||
prev_sb: Optional[SubBlockRecord],
|
||||
sub_block_records: Dict[bytes32, SubBlockRecord],
|
||||
pos_challenge_hash: bytes32,
|
||||
pos_ss_challenge_hash: bytes32,
|
||||
extra_sub_slot: bool = False,
|
||||
) -> List[EndOfSubSlotBundle]:
|
||||
"""
|
||||
|
@ -424,13 +424,13 @@ class FullNodeStore:
|
|||
raise ValueError("First sub slot should be None")
|
||||
final_index = 0
|
||||
for index, (sub_slot, sps, total_iters) in enumerate(self.finished_sub_slots):
|
||||
if sub_slot is not None and sub_slot.challenge_chain.get_hash() == pos_challenge_hash:
|
||||
if sub_slot is not None and sub_slot.challenge_chain.get_hash() == pos_ss_challenge_hash:
|
||||
pos_index = index
|
||||
else:
|
||||
for index, (sub_slot, sps, total_iters) in enumerate(self.finished_sub_slots):
|
||||
if sub_slot is None:
|
||||
pass
|
||||
if sub_slot.challenge_chain.get_hash() == pos_challenge_hash:
|
||||
if sub_slot.challenge_chain.get_hash() == pos_ss_challenge_hash:
|
||||
pos_index = index
|
||||
if sub_slot.challenge_chain.get_hash() == final_sub_slot_in_chain:
|
||||
final_index = index
|
||||
|
|
|
@ -26,21 +26,12 @@ class UnfinishedBlock(Streamable):
|
|||
def prev_header_hash(self):
|
||||
return self.foliage_sub_block.prev_sub_block_hash
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
return self.reward_chain_sub_block.sub_block_height
|
||||
def partial_hash(self):
|
||||
return self.reward_chain_sub_block.get_hash()
|
||||
|
||||
@property
|
||||
def weight(self):
|
||||
return self.reward_chain_sub_block.weight
|
||||
def is_block(self):
|
||||
return self.foliage_sub_block.foliage_block_hash is not None
|
||||
|
||||
@property
|
||||
def total_iters(self):
|
||||
return self.reward_chain_sub_block.total_iters
|
||||
|
||||
@property
|
||||
def header_hash(self):
|
||||
return self.foliage_sub_block.get_hash()
|
||||
|
||||
def is_block(self):
|
||||
return self.foliage_sub_block.foliage_block_hash is not None
|
||||
|
|
|
@ -70,7 +70,7 @@ test_constants = DEFAULT_CONSTANTS.replace(
|
|||
"DISCRIMINANT_SIZE_BITS": 16,
|
||||
"SUB_EPOCH_SUB_BLOCKS": 140,
|
||||
"EPOCH_SUB_BLOCKS": 280,
|
||||
"SUB_SLOT_ITERS_STARTING": 2 ** 12, # Must be a multiple of 64
|
||||
"SUB_SLOT_ITERS_STARTING": 2 ** 10, # Must be a multiple of 64
|
||||
"NUMBER_ZERO_BITS_PLOT_FILTER": 1, # H(plot signature of the challenge) must start with these many zeroes
|
||||
"MAX_FUTURE_TIME": 3600
|
||||
* 24
|
||||
|
@ -148,7 +148,7 @@ class BlockTools:
|
|||
mkdir(temp_dir)
|
||||
args = Namespace()
|
||||
# Can't go much lower than 20, since plots start having no solutions and more buggy
|
||||
args.size = 20
|
||||
args.size = 22
|
||||
# Uses many plots for testing, in order to guarantee proofs of space at every height
|
||||
args.num = 20
|
||||
args.buffer = 100
|
||||
|
@ -162,7 +162,7 @@ class BlockTools:
|
|||
args.buckets = 0
|
||||
args.stripe_size = 2000
|
||||
args.num_threads = 0
|
||||
test_private_keys = [AugSchemeMPL.key_gen(std_hash(i.to_bytes(3, "big"))) for i in range(args.num)]
|
||||
test_private_keys = [AugSchemeMPL.key_gen(std_hash(i.to_bytes(2, "big"))) for i in range(args.num)]
|
||||
try:
|
||||
# No datetime in the filename, to get deterministic filenames and not re-plot
|
||||
create_plots(
|
||||
|
@ -209,7 +209,7 @@ class BlockTools:
|
|||
def get_consecutive_blocks(
|
||||
self,
|
||||
num_blocks: uint8,
|
||||
block_list: List[FullBlock] = None,
|
||||
block_list_input: List[FullBlock] = None,
|
||||
farmer_reward_puzzle_hash: Optional[bytes32] = None,
|
||||
pool_reward_puzzle_hash: Optional[bytes32] = None,
|
||||
transaction_data: Optional[SpendBundle] = None,
|
||||
|
@ -218,7 +218,10 @@ class BlockTools:
|
|||
force_overflow: bool = False,
|
||||
skip_slots: uint32 = uint32(0), # Force at least this number of empty slots before the first SB
|
||||
) -> List[FullBlock]:
|
||||
|
||||
if block_list_input is not None:
|
||||
block_list = block_list_input.copy()
|
||||
else:
|
||||
block_list = []
|
||||
constants = self.constants
|
||||
transaction_data_included = False
|
||||
if time_per_sub_block is None:
|
||||
|
@ -230,7 +233,7 @@ class BlockTools:
|
|||
pool_reward_puzzle_hash = self.pool_ph
|
||||
pool_target = PoolTarget(pool_reward_puzzle_hash, uint32(0))
|
||||
|
||||
if block_list is None or len(block_list) == 0:
|
||||
if len(block_list) == 0:
|
||||
initial_block_list_len = 0
|
||||
genesis = self.create_genesis_block(
|
||||
constants,
|
||||
|
@ -272,6 +275,7 @@ class BlockTools:
|
|||
same_slot_as_last = True # Only applies to first slot, to prevent old blocks from being added
|
||||
sub_slot_start_total_iters: uint128 = latest_sub_block.infusion_sub_slot_total_iters(constants)
|
||||
sub_slots_finished = 0
|
||||
pending_ses: bool = False
|
||||
|
||||
# Start at the last block in block list
|
||||
# Get the challenge for that slot
|
||||
|
@ -361,12 +365,10 @@ class BlockTools:
|
|||
latest_sub_block,
|
||||
sub_blocks,
|
||||
)
|
||||
|
||||
if full_block is None:
|
||||
continue
|
||||
if sub_block_record.is_block:
|
||||
transaction_data_included = True
|
||||
|
||||
if pending_ses:
|
||||
pending_ses = False
|
||||
block_list.append(full_block)
|
||||
sub_blocks_added_this_sub_slot += 1
|
||||
|
||||
|
@ -425,14 +427,18 @@ class BlockTools:
|
|||
# in order for light clients to validate.
|
||||
cc_vdf = VDFInfo(cc_vdf.challenge, ClassgroupElement.get_default_element(), sub_slot_iters, cc_vdf.output)
|
||||
|
||||
sub_epoch_summary: Optional[SubEpochSummary] = next_sub_epoch_summary(
|
||||
constants,
|
||||
sub_blocks,
|
||||
height_to_hash,
|
||||
latest_sub_block.signage_point_index,
|
||||
latest_sub_block.required_iters,
|
||||
block_list[-1],
|
||||
)
|
||||
if pending_ses:
|
||||
sub_epoch_summary: Optional[SubEpochSummary] = None
|
||||
else:
|
||||
sub_epoch_summary: Optional[SubEpochSummary] = next_sub_epoch_summary(
|
||||
constants,
|
||||
sub_blocks,
|
||||
height_to_hash,
|
||||
latest_sub_block.signage_point_index,
|
||||
latest_sub_block.required_iters,
|
||||
block_list[-1],
|
||||
)
|
||||
pending_ses = True
|
||||
|
||||
if sub_epoch_summary is not None:
|
||||
ses_hash = sub_epoch_summary.get_hash()
|
||||
|
@ -564,10 +570,10 @@ class BlockTools:
|
|||
overflow_rc_challenge=overflow_rc_challenge,
|
||||
)
|
||||
|
||||
if full_block is None:
|
||||
continue
|
||||
if sub_block_record.is_block:
|
||||
transaction_data_included = True
|
||||
if pending_ses:
|
||||
pending_ses = False
|
||||
|
||||
block_list.append(full_block)
|
||||
sub_blocks_added_this_sub_slot += 1
|
||||
|
@ -655,6 +661,7 @@ class BlockTools:
|
|||
unfinished_block = create_unfinished_block(
|
||||
constants,
|
||||
sub_slot_total_iters,
|
||||
constants.SUB_SLOT_ITERS_STARTING,
|
||||
uint8(signage_point_index),
|
||||
sp_iters,
|
||||
ip_iters,
|
||||
|
@ -1086,10 +1093,10 @@ def get_full_block_and_sub_record(
|
|||
) -> Tuple[FullBlock, SubBlockRecord]:
|
||||
sp_iters = calculate_sp_iters(constants, sub_slot_iters, signage_point_index)
|
||||
ip_iters = calculate_ip_iters(constants, sub_slot_iters, signage_point_index, required_iters)
|
||||
|
||||
unfinished_block = create_unfinished_block(
|
||||
constants,
|
||||
sub_slot_start_total_iters,
|
||||
sub_slot_iters,
|
||||
signage_point_index,
|
||||
sp_iters,
|
||||
ip_iters,
|
||||
|
|
|
@ -41,6 +41,16 @@ async def default_1000_blocks():
|
|||
yield persistent_blocks(1000, "test_blocks_1000.db")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
async def default_10000_blocks():
|
||||
yield persistent_blocks(10000, "test_blocks_10000.db")
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
async def default_20000_blocks():
|
||||
yield persistent_blocks(20000, "test_blocks_20000.db")
|
||||
|
||||
|
||||
def persistent_blocks(num_of_blocks, db_name):
|
||||
# try loading from disc, if not create new blocks.db file
|
||||
if path.exists(db_name):
|
||||
|
|
|
@ -17,7 +17,7 @@ from src.util.ints import uint64, uint8, int512
|
|||
from tests.recursive_replace import recursive_replace
|
||||
from tests.setup_nodes import test_constants, bt
|
||||
from tests.full_node.fixtures import empty_blockchain
|
||||
from tests.full_node.fixtures import default_400_blocks as blocks
|
||||
from tests.full_node.fixtures import default_1000_blocks
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
|
@ -76,8 +76,8 @@ class TestGenesisBlock:
|
|||
|
||||
class TestBlockHeaderValidation:
|
||||
@pytest.mark.asyncio
|
||||
async def test_long_chain(self, empty_blockchain, blocks):
|
||||
# blocks = bt.get_consecutive_blocks(400)
|
||||
async def test_long_chain(self, empty_blockchain, default_1000_blocks):
|
||||
blocks = default_1000_blocks
|
||||
for block in blocks:
|
||||
# if (
|
||||
# len(block.finished_sub_slots) > 0
|
||||
|
@ -165,7 +165,7 @@ class TestBlockHeaderValidation:
|
|||
result, err, _ = await blockchain.receive_block(block)
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(10, skip_slots=2, block_list_input=blocks)
|
||||
for block in blocks[10:]:
|
||||
result, err, _ = await blockchain.receive_block(block)
|
||||
assert err is None
|
||||
|
@ -177,7 +177,7 @@ class TestBlockHeaderValidation:
|
|||
num_blocks = 20
|
||||
blocks = []
|
||||
for i in range(num_blocks):
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=1)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
||||
result, err, _ = await blockchain.receive_block(blocks[-1])
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
assert blockchain.get_peak().height == num_blocks - 1
|
||||
|
@ -188,7 +188,7 @@ class TestBlockHeaderValidation:
|
|||
num_blocks = 20
|
||||
blocks = []
|
||||
for i in range(num_blocks): # Same thing, but 2 sub-slots per sub-block
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=2)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2)
|
||||
result, err, _ = await blockchain.receive_block(blocks[-1])
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
assert blockchain.get_peak().height == num_blocks - 1
|
||||
|
@ -199,7 +199,7 @@ class TestBlockHeaderValidation:
|
|||
num_blocks = 10
|
||||
blocks = []
|
||||
for i in range(num_blocks): # Same thing, but 5 sub-slots per sub-block
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=5)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=5)
|
||||
result, err, _ = await blockchain.receive_block(blocks[-1])
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
assert blockchain.get_peak().height == num_blocks - 1
|
||||
|
@ -220,7 +220,7 @@ class TestBlockHeaderValidation:
|
|||
num_blocks = 10
|
||||
blocks = []
|
||||
for i in range(num_blocks):
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=2, force_overflow=True)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=2, force_overflow=True)
|
||||
result, err, _ = await blockchain.receive_block(blocks[-1])
|
||||
assert err is None
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
|
@ -269,7 +269,7 @@ class TestBlockHeaderValidation:
|
|||
async def test_invalid_sub_slot_challenge_hash_non_genesis(self, empty_blockchain):
|
||||
# 2b
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=1, block_list_input=blocks)
|
||||
print(blocks)
|
||||
new_finished_ss = recursive_replace(
|
||||
blocks[1].finished_sub_slots[0],
|
||||
|
@ -289,7 +289,7 @@ class TestBlockHeaderValidation:
|
|||
async def test_invalid_sub_slot_challenge_hash_empty_ss(self, empty_blockchain):
|
||||
# 2c
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=0)
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, force_overflow=False, skip_slots=2, block_list_input=blocks)
|
||||
new_finished_ss = recursive_replace(
|
||||
blocks[1].finished_sub_slots[-1],
|
||||
"challenge_chain.challenge_chain_end_of_slot_vdf.challenge",
|
||||
|
@ -433,7 +433,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
case_1, case_2 = False, False
|
||||
while not case_1 or not case_2:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=1)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
||||
block = blocks[-1]
|
||||
if len(block.finished_sub_slots) > 0 and block.finished_sub_slots[-1].infused_challenge_chain is not None:
|
||||
if (
|
||||
|
@ -522,7 +522,7 @@ class TestBlockHeaderValidation:
|
|||
blockchain = empty_blockchain
|
||||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=4)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=4)
|
||||
|
||||
new_finished_ss = recursive_replace(
|
||||
blocks[-1].finished_sub_slots[-1],
|
||||
|
@ -535,12 +535,30 @@ class TestBlockHeaderValidation:
|
|||
result, err, _ = await blockchain.receive_block(block_bad)
|
||||
assert err == Err.INVALID_SUB_EPOCH_SUMMARY_HASH
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_empty_sub_slots_epoch(self, empty_blockchain):
|
||||
# 2m
|
||||
# Tests adding an empty sub slot after the sub-epoch / epoch.
|
||||
# Also tests overflow block in epoch
|
||||
blocks_base = bt.get_consecutive_blocks(test_constants.EPOCH_SUB_BLOCKS)
|
||||
blocks_1 = bt.get_consecutive_blocks(1, block_list_input=blocks_base, force_overflow=True)
|
||||
blocks_2 = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks_base, force_overflow=True)
|
||||
blocks_3 = bt.get_consecutive_blocks(1, skip_slots=2, block_list_input=blocks_base, force_overflow=True)
|
||||
blocks_4 = bt.get_consecutive_blocks(1, block_list_input=blocks_base)
|
||||
for block in blocks_base:
|
||||
result, err, _ = await empty_blockchain.receive_block(block)
|
||||
assert err is None
|
||||
assert result == ReceiveBlockResult.NEW_PEAK
|
||||
for block in [blocks_1[-1], blocks_2[-1], blocks_3[-1], blocks_4[-1]]:
|
||||
result, err, _ = await empty_blockchain.receive_block(block)
|
||||
assert err is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_wrong_cc_hash_rc(self, empty_blockchain):
|
||||
# 2o
|
||||
blockchain = empty_blockchain
|
||||
blocks = bt.get_consecutive_blocks(1, skip_slots=1)
|
||||
blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, skip_slots=1, block_list_input=blocks)
|
||||
assert (await blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
new_finished_ss = recursive_replace(
|
||||
|
@ -756,7 +774,7 @@ class TestBlockHeaderValidation:
|
|||
await empty_blockchain.receive_block(blocks[1])
|
||||
case_1, case_2 = False, False
|
||||
while not case_1 or not case_2:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks, skip_slots=1)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1)
|
||||
if len(blocks[-1].finished_sub_slots) > 0:
|
||||
new_finished_ss = recursive_replace(
|
||||
blocks[-1].finished_sub_slots[-1],
|
||||
|
@ -813,7 +831,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if len(blocks[-1].finished_sub_slots) > 0:
|
||||
new_finished_ss: EndOfSubSlotBundle = recursive_replace(
|
||||
blocks[-1].finished_sub_slots[0],
|
||||
|
@ -907,7 +925,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = []
|
||||
case_1, case_2 = False, False
|
||||
while not case_1 or not case_2:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].reward_chain_sub_block.signage_point_index == 0:
|
||||
case_1 = True
|
||||
block_bad = recursive_replace(blocks[-1], "reward_chain_sub_block.signage_point_index", uint8(1))
|
||||
|
@ -942,7 +960,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "reward_chain_sub_block.reward_chain_sp_vdf.challenge", std_hash(b"1")
|
||||
|
@ -992,7 +1010,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].reward_chain_sub_block.signage_point_index != 0:
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "reward_chain_sub_block.challenge_chain_sp_vdf.challenge", std_hash(b"1")
|
||||
|
@ -1057,7 +1075,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "foliage_sub_block.foliage_block_signature", G2Element.generator()
|
||||
|
@ -1114,7 +1132,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
case_1, case_2 = False, False
|
||||
while not case_1 or not case_2:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
case_1 = True
|
||||
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_sub_block.foliage_block_hash", None)
|
||||
|
@ -1134,7 +1152,7 @@ class TestBlockHeaderValidation:
|
|||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
case_1, case_2 = False, False
|
||||
while not case_1 or not case_2:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
block_bad: FullBlock = recursive_replace(
|
||||
blocks[-1], "foliage_sub_block.foliage_block_hash", std_hash(b"2")
|
||||
|
@ -1168,7 +1186,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.prev_block_hash", std_hash(b"2"))
|
||||
block_bad: FullBlock = recursive_replace(
|
||||
|
@ -1189,7 +1207,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
block_bad: FullBlock = recursive_replace(blocks[-1], "foliage_block.filter_hash", std_hash(b"2"))
|
||||
block_bad: FullBlock = recursive_replace(
|
||||
|
@ -1210,7 +1228,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if blocks[-1].foliage_block is not None:
|
||||
block_bad: FullBlock = recursive_replace(
|
||||
blocks[-1], "foliage_block.timestamp", blocks[0].foliage_block.timestamp - 10
|
||||
|
@ -1276,7 +1294,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "reward_chain_sub_block.challenge_chain_ip_vdf.challenge", std_hash(b"1")
|
||||
)
|
||||
|
@ -1312,7 +1330,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "reward_chain_sub_block.reward_chain_ip_vdf.challenge", std_hash(b"1")
|
||||
)
|
||||
|
@ -1348,7 +1366,7 @@ class TestBlockHeaderValidation:
|
|||
blocks = bt.get_consecutive_blocks(1)
|
||||
assert (await empty_blockchain.receive_block(blocks[0]))[0] == ReceiveBlockResult.NEW_PEAK
|
||||
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
block_bad = recursive_replace(
|
||||
blocks[-1], "reward_chain_sub_block.infused_challenge_chain_ip_vdf.challenge", std_hash(b"1")
|
||||
)
|
||||
|
@ -1399,7 +1417,7 @@ class TestBlockHeaderValidation:
|
|||
|
||||
# Test one which should not be a block
|
||||
while True:
|
||||
blocks = bt.get_consecutive_blocks(1, block_list=blocks)
|
||||
blocks = bt.get_consecutive_blocks(1, block_list_input=blocks)
|
||||
if not blocks[-1].is_block():
|
||||
block_bad: FullBlock = recursive_replace(blocks[-1], "reward_chain_sub_block.is_block", True)
|
||||
block_bad: FullBlock = recursive_replace(
|
||||
|
|
|
@ -717,7 +717,7 @@ class TestWalletProtocol:
|
|||
blocks_new = bt.get_consecutive_blocks(
|
||||
test_constants,
|
||||
1,
|
||||
block_list=blocks_list,
|
||||
block_list_input=blocks_list,
|
||||
seed=b"test_request_additions",
|
||||
)
|
||||
async for _ in full_node_1.respond_block(fnp.RespondBlock(blocks_new[-1])):
|
||||
|
@ -879,7 +879,7 @@ class TestWalletProtocol:
|
|||
blocks_new = bt.get_consecutive_blocks(
|
||||
test_constants,
|
||||
10,
|
||||
block_list=blocks_list,
|
||||
block_list_input=blocks_list,
|
||||
)
|
||||
for block in blocks_new:
|
||||
[_ async for _ in full_node_1.respond_block(fnp.RespondBlock(block))]
|
||||
|
@ -913,7 +913,7 @@ class TestWalletProtocol:
|
|||
)
|
||||
}
|
||||
blocks_new = bt.get_consecutive_blocks(
|
||||
test_constants, 5, block_list=blocks_new, transaction_data_at_height=dic_h
|
||||
test_constants, 5, block_list_input=blocks_new, transaction_data_at_height=dic_h
|
||||
)
|
||||
for block in blocks_new:
|
||||
[_ async for _ in full_node_1.respond_block(fnp.RespondBlock(block))]
|
||||
|
@ -1053,7 +1053,7 @@ class TestWalletProtocol:
|
|||
blocks_new = bt.get_consecutive_blocks(
|
||||
test_constants,
|
||||
10,
|
||||
block_list=blocks_list,
|
||||
block_list_input=blocks_list,
|
||||
)
|
||||
for block in blocks_new:
|
||||
[_ async for _ in full_node_1.respond_block(fnp.RespondBlock(block))]
|
||||
|
@ -1088,7 +1088,7 @@ class TestWalletProtocol:
|
|||
)
|
||||
}
|
||||
blocks_new = bt.get_consecutive_blocks(
|
||||
test_constants, 5, block_list=blocks_new, transaction_data_at_height=dic_h
|
||||
test_constants, 5, block_list_input=blocks_new, transaction_data_at_height=dic_h
|
||||
)
|
||||
for block in blocks_new:
|
||||
[_ async for _ in full_node_1.respond_block(fnp.RespondBlock(block))]
|
||||
|
|
|
@ -5,8 +5,11 @@ import sqlite3
|
|||
|
||||
import aiosqlite
|
||||
import pytest
|
||||
from pytest import raises
|
||||
|
||||
from src.full_node.full_node_store import FullNodeStore
|
||||
from src.types.sized_bytes import bytes32
|
||||
from src.types.unfinished_block import UnfinishedBlock
|
||||
from src.util.ints import uint32, uint64
|
||||
from tests.setup_nodes import test_constants, bt
|
||||
|
||||
|
@ -19,97 +22,108 @@ def event_loop():
|
|||
|
||||
class TestFullNodeStore:
|
||||
@pytest.mark.asyncio
|
||||
async def test_basic_store(self):
|
||||
assert sqlite3.threadsafety == 1
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 9, [], 9, b"0")
|
||||
# blocks_alt = bt.get_consecutive_blocks(test_constants, 3, [], 9, b"1")
|
||||
bt.get_consecutive_blocks(test_constants, 3, [], 9, b"1")
|
||||
db_filename = Path("blockchain_test.db")
|
||||
db_filename_2 = Path("blockchain_test_2.db")
|
||||
db_filename_3 = Path("blockchain_test_3.db")
|
||||
async def test_basic_store(self, empty_blockchain):
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 10)
|
||||
|
||||
if db_filename.exists():
|
||||
db_filename.unlink()
|
||||
if db_filename_2.exists():
|
||||
db_filename_2.unlink()
|
||||
if db_filename_3.exists():
|
||||
db_filename_3.unlink()
|
||||
store = await FullNodeStore.create(test_constants)
|
||||
|
||||
connection = await aiosqlite.connect(db_filename)
|
||||
connection_2 = await aiosqlite.connect(db_filename_2)
|
||||
connection_3 = await aiosqlite.connect(db_filename_3)
|
||||
|
||||
db = await FullNodeStore.create(connection)
|
||||
db_2 = await FullNodeStore.create(connection_2)
|
||||
try:
|
||||
# Add/get candidate block
|
||||
assert db.get_candidate_block(0) is None
|
||||
partial = (
|
||||
blocks[5].transactions_generator,
|
||||
blocks[5].transactions_filter,
|
||||
blocks[5].header.data,
|
||||
blocks[5].proof_of_space,
|
||||
unfinished_blocks = []
|
||||
for block in blocks:
|
||||
unfinished_blocks.append(
|
||||
UnfinishedBlock(
|
||||
block.finished_sub_slots,
|
||||
block.reward_chain_sub_block.get_unfinished(),
|
||||
block.challenge_chain_sp_proof,
|
||||
block.reward_chain_sp_proof,
|
||||
block.foliage_sub_block,
|
||||
block.foliage_block,
|
||||
block.transactions_info,
|
||||
block.transactions_generator,
|
||||
)
|
||||
)
|
||||
db.add_candidate_block(blocks[5].header_hash, *partial)
|
||||
assert db.get_candidate_block(blocks[5].header_hash) == partial
|
||||
db.clear_candidate_blocks_below(uint32(8))
|
||||
assert db.get_candidate_block(blocks[5].header_hash) is None
|
||||
|
||||
# Proof of time heights
|
||||
chall_iters = (bytes32(bytes([1] * 32)), uint32(32532535))
|
||||
chall_iters_2 = (bytes32(bytes([3] * 32)), uint32(12522535))
|
||||
assert db.get_proof_of_time_heights(chall_iters) is None
|
||||
db.add_proof_of_time_heights(chall_iters, 5)
|
||||
db.add_proof_of_time_heights(chall_iters_2, 7)
|
||||
db.clear_proof_of_time_heights_below(6)
|
||||
assert db.get_proof_of_time_heights(chall_iters) is None
|
||||
assert db.get_proof_of_time_heights(chall_iters_2) is not None
|
||||
# Add/get candidate block
|
||||
assert store.get_candidate_block(unfinished_blocks[0].get_hash()) is None
|
||||
for unf_block in unfinished_blocks:
|
||||
store.add_candidate_block(unf_block.get_hash(), unf_block)
|
||||
|
||||
# Add/get unfinished block
|
||||
i = 1
|
||||
for block in blocks:
|
||||
key = (block.header_hash, uint64(1000))
|
||||
assert store.get_candidate_block(unfinished_blocks[4].get_hash()) == unfinished_blocks[4]
|
||||
store.clear_candidate_blocks_below(uint32(8))
|
||||
assert store.get_candidate_block(unfinished_blocks[5].get_hash()) is None
|
||||
assert store.get_candidate_block(unfinished_blocks[8].get_hash()) is not None
|
||||
|
||||
# Different database should have different data
|
||||
await db_2.add_unfinished_block(key, block)
|
||||
# Test seen unfinished blocks
|
||||
h_hash_1 = bytes32(token_bytes(32))
|
||||
assert not store.seen_unfinished_block(h_hash_1)
|
||||
assert store.seen_unfinished_block(h_hash_1)
|
||||
await store.clear_seen_unfinished_blocks()
|
||||
assert not store.seen_unfinished_block(h_hash_1)
|
||||
|
||||
assert await db.get_unfinished_block(key) is None
|
||||
await db.add_unfinished_block(key, block)
|
||||
assert await db.get_unfinished_block(key) == block
|
||||
assert len(await db.get_unfinished_blocks()) == i
|
||||
i += 1
|
||||
await db.clear_unfinished_blocks_below(uint32(5))
|
||||
assert len(await db.get_unfinished_blocks()) == 5
|
||||
# Disconnected blocks
|
||||
assert store.get_disconnected_block(blocks[0].prev_header_hash) is None
|
||||
for block in blocks:
|
||||
store.add_disconnected_block(block)
|
||||
assert store.get_disconnected_block_by_prev(block.prev_header_hash) == block
|
||||
assert store.get_disconnected_block(block.header_hash) == block
|
||||
|
||||
assert db.get_disconnected_block(blocks[0].prev_header_hash) is None
|
||||
# Disconnected blocks
|
||||
for block in blocks:
|
||||
db.add_disconnected_block(block)
|
||||
db.get_disconnected_block(block.prev_header_hash) == block
|
||||
# Add/get unfinished block
|
||||
for unf_block in unfinished_blocks:
|
||||
assert store.get_unfinished_block(unf_block.partial_hash) is None
|
||||
store.add_unfinished_block(unf_block)
|
||||
assert store.get_unfinished_block(unf_block.partial_hash) == unf_block
|
||||
store.remove_unfinished_block(unf_block.partial_hash)
|
||||
assert store.get_unfinished_block(unf_block.partial_hash) is None
|
||||
|
||||
db.clear_disconnected_blocks_below(uint32(5))
|
||||
assert db.get_disconnected_block(blocks[4].prev_header_hash) is None
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 1, skip_slots=5)
|
||||
sub_slots = blocks[0].finished_sub_slots
|
||||
assert len(sub_slots) == 5
|
||||
|
||||
h_hash_1 = bytes32(token_bytes(32))
|
||||
assert not db.seen_unfinished_block(h_hash_1)
|
||||
assert db.seen_unfinished_block(h_hash_1)
|
||||
await db.clear_seen_unfinished_blocks()
|
||||
assert not db.seen_unfinished_block(h_hash_1)
|
||||
# Test adding non-connecting sub-slots genesis
|
||||
assert store.get_sub_slot(test_constants.FIRST_CC_CHALLENGE) is None
|
||||
assert store.get_sub_slot(sub_slots[0].challenge_chain.get_hash()) is None
|
||||
assert store.get_sub_slot(sub_slots[1].challenge_chain.get_hash()) is None
|
||||
assert not store.new_finished_sub_slot(sub_slots[1], {}, None)
|
||||
assert not store.new_finished_sub_slot(sub_slots[2], {}, None)
|
||||
|
||||
except Exception:
|
||||
await connection.close()
|
||||
await connection_2.close()
|
||||
await connection_3.close()
|
||||
db_filename.unlink()
|
||||
db_filename_2.unlink()
|
||||
raise
|
||||
# Test adding sub-slots after genesis
|
||||
assert store.new_finished_sub_slot(sub_slots[0], {}, None)
|
||||
assert store.get_sub_slot(sub_slots[0].challenge_chain.get_hash()) == sub_slots[0]
|
||||
assert store.get_sub_slot(sub_slots[1].challenge_chain.get_hash()) is None
|
||||
assert store.new_finished_sub_slot(sub_slots[1], {}, None)
|
||||
for i in range(len(sub_slots)):
|
||||
if i > 0:
|
||||
assert store.new_finished_sub_slot(sub_slots[i], {}, None)
|
||||
assert store.get_sub_slot(sub_slots[i].challenge_chain.get_hash()) == sub_slots[i]
|
||||
|
||||
# Different database should have different data
|
||||
await FullNodeStore.create(connection_3)
|
||||
assert store.get_finished_sub_slots(None, {}, sub_slots[-1].challenge_chain.get_hash(), False) == sub_slots
|
||||
with raises(ValueError):
|
||||
store.get_finished_sub_slots(None, {}, sub_slots[-1].challenge_chain.get_hash(), True)
|
||||
|
||||
await connection.close()
|
||||
await connection_2.close()
|
||||
await connection_3.close()
|
||||
db_filename.unlink()
|
||||
db_filename_2.unlink()
|
||||
db_filename_3.unlink()
|
||||
assert store.get_finished_sub_slots(None, {}, sub_slots[-2].challenge_chain.get_hash(), False) == sub_slots[:-1]
|
||||
|
||||
# Test adding genesis peak
|
||||
await empty_blockchain.receive_block(blocks[0])
|
||||
peak = empty_blockchain.get_peak()
|
||||
if peak.overflow:
|
||||
store.new_peak(peak, sub_slots[-1], sub_slots[-2], False, {})
|
||||
else:
|
||||
store.new_peak(peak, sub_slots[-1], None, False, {})
|
||||
|
||||
assert store.get_sub_slot(sub_slots[0].challenge_chain.get_hash()) is None
|
||||
assert store.get_sub_slot(sub_slots[1].challenge_chain.get_hash()) is None
|
||||
assert store.get_sub_slot(sub_slots[2].challenge_chain.get_hash()) is None
|
||||
assert store.get_sub_slot(sub_slots[3].challenge_chain.get_hash()) == sub_slots[3]
|
||||
assert store.get_sub_slot(sub_slots[4].challenge_chain.get_hash()) == sub_slots[4]
|
||||
|
||||
assert (
|
||||
store.get_finished_sub_slots(
|
||||
peak, empty_blockchain.sub_blocks, sub_slots[-1].challenge_chain.get_hash(), False
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
# Test adding non genesis peak directly
|
||||
blocks = bt.get_consecutive_blocks(test_constants, 2, skip_slots=2)
|
||||
for block in blocks:
|
||||
await empty_blockchain.receive_block(block)
|
||||
sb = empty_blockchain.sub_blocks[block.header_hash]
|
||||
|
|
Loading…
Reference in New Issue