def _run_generator( constants_dict: bytes, unfinished_block_bytes: bytes, block_generator_bytes: bytes, ) -> Tuple[Optional[Err], Optional[bytes]]: """ Runs the CLVM generator from bytes inputs. This is meant to be called under a ProcessPoolExecutor, in order to validate the heavy parts of a block (clvm program) in a different process. """ try: constants: ConsensusConstants = dataclass_from_dict( ConsensusConstants, constants_dict) unfinished_block: UnfinishedBlock = UnfinishedBlock.from_bytes( unfinished_block_bytes) assert unfinished_block.transactions_info is not None block_generator: BlockGenerator = BlockGenerator.from_bytes( block_generator_bytes) assert block_generator.program == unfinished_block.transactions_generator npc_result: NPCResult = get_name_puzzle_conditions( block_generator, min(constants.MAX_BLOCK_COST_CLVM, unfinished_block.transactions_info.cost), cost_per_byte=constants.COST_PER_BYTE, mempool_mode=False, ) if npc_result.error is not None: return Err(npc_result.error), None except ValidationError as e: return e.code, None except Exception: return Err.UNKNOWN, None return None, bytes(npc_result)
async def test_basic_store(self, empty_blockchain, normalized_to_identity: bool = False): blockchain = empty_blockchain blocks = bt.get_consecutive_blocks( 10, seed=b"1234", normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) store = FullNodeStore(test_constants) unfinished_blocks = [] for block in blocks: unfinished_blocks.append( UnfinishedBlock( block.finished_sub_slots, block.reward_chain_block.get_unfinished(), block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, block.transactions_info, block.transactions_generator, [], )) # Add/get candidate block assert store.get_candidate_block( unfinished_blocks[0].get_hash()) is None for height, unf_block in enumerate(unfinished_blocks): store.add_candidate_block(unf_block.get_hash(), uint32(height), unf_block) candidate = store.get_candidate_block(unfinished_blocks[4].get_hash()) assert candidate is not None assert candidate[1] == 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 # 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) store.clear_seen_unfinished_blocks() assert not store.seen_unfinished_block(h_hash_1) # Add/get unfinished block for height, unf_block in enumerate(unfinished_blocks): assert store.get_unfinished_block(unf_block.partial_hash) is None store.add_unfinished_block( uint32(height), unf_block, PreValidationResult(None, uint64(123532), None, False)) 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 blocks = bt.get_consecutive_blocks( 1, skip_slots=5, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, ) sub_slots = blocks[0].finished_sub_slots assert len(sub_slots) == 5 assert (store.get_finished_sub_slots( BlockCache({}), None, sub_slots[0].challenge_chain.challenge_chain_end_of_slot_vdf. challenge, ) == []) # Test adding non-connecting sub-slots genesis assert store.get_sub_slot(test_constants.GENESIS_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 store.new_finished_sub_slot(sub_slots[1], blockchain, None, None) is None assert store.new_finished_sub_slot(sub_slots[2], blockchain, None, None) is None # Test adding sub-slots after genesis assert store.new_finished_sub_slot(sub_slots[0], blockchain, None, None) is not None sub_slot = store.get_sub_slot(sub_slots[0].challenge_chain.get_hash()) assert sub_slot is not None assert sub_slot[0] == 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], blockchain, None, None) is not None for i in range(len(sub_slots)): assert store.new_finished_sub_slot(sub_slots[i], blockchain, None, None) is not None slot_i = store.get_sub_slot( sub_slots[i].challenge_chain.get_hash()) assert slot_i is not None assert slot_i[0] == sub_slots[i] assert store.get_finished_sub_slots( BlockCache({}), None, sub_slots[-1].challenge_chain.get_hash()) == sub_slots assert store.get_finished_sub_slots(BlockCache( {}), None, std_hash(b"not a valid hash")) is None assert (store.get_finished_sub_slots( BlockCache({}), None, sub_slots[-2].challenge_chain.get_hash()) == sub_slots[:-1]) # Test adding genesis peak await _validate_and_add_block(blockchain, blocks[0]) peak = blockchain.get_peak() peak_full_block = await blockchain.get_full_peak() if peak.overflow: store.new_peak(peak, peak_full_block, sub_slots[-2], sub_slots[-1], None, blockchain) else: store.new_peak(peak, peak_full_block, None, sub_slots[-1], None, blockchain) 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 if peak.overflow: slot_3 = store.get_sub_slot( sub_slots[3].challenge_chain.get_hash()) assert slot_3 is not None assert slot_3[0] == sub_slots[3] else: assert store.get_sub_slot( sub_slots[3].challenge_chain.get_hash()) is None slot_4 = store.get_sub_slot(sub_slots[4].challenge_chain.get_hash()) assert slot_4 is not None assert slot_4[0] == sub_slots[4] assert (store.get_finished_sub_slots( blockchain, peak, sub_slots[-1].challenge_chain.get_hash(), ) == []) # Test adding non genesis peak directly blocks = bt.get_consecutive_blocks( 2, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for block in blocks: await _validate_and_add_block_no_error(blockchain, block) sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, None, blockchain) assert res.added_eos is None # Add reorg blocks blocks_reorg = bt.get_consecutive_blocks( 20, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for block in blocks_reorg: peak = blockchain.get_peak() assert peak is not None await _validate_and_add_block_no_error(blockchain, block) if blockchain.get_peak().header_hash == block.header_hash: sb = blockchain.block_record(block.header_hash) fork = find_fork_point_in_chain( blockchain, peak, blockchain.block_record(sb.header_hash)) if fork > 0: fork_block = blockchain.height_to_block_record(fork) else: fork_block = None sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, fork_block, blockchain) assert res.added_eos is None # Add slots to the end blocks_2 = bt.get_consecutive_blocks( 1, block_list_input=blocks_reorg, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_2[-1].finished_sub_slots: store.new_finished_sub_slot(slot, blockchain, blockchain.get_peak(), await blockchain.get_full_peak()) assert store.get_sub_slot( sub_slots[3].challenge_chain.get_hash()) is None assert store.get_sub_slot( sub_slots[4].challenge_chain.get_hash()) is None # Test adding signage point peak = blockchain.get_peak() ss_start_iters = peak.ip_sub_slot_total_iters(test_constants) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, ss_start_iters, uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) blocks = blocks_reorg while True: blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) await _validate_and_add_block(blockchain, blocks[-1]) if blockchain.get_peak().header_hash == blocks[-1].header_hash: sb = blockchain.block_record(blocks[-1].header_hash) fork = find_fork_point_in_chain( blockchain, peak, blockchain.block_record(sb.header_hash)) if fork > 0: fork_block = blockchain.height_to_block_record(fork) else: fork_block = None sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( blocks[-1].header_hash) res = store.new_peak(sb, blocks[-1], sp_sub_slot, ip_sub_slot, fork_block, blockchain) assert res.added_eos is None if sb.overflow and sp_sub_slot is not None: assert sp_sub_slot != ip_sub_slot break peak = blockchain.get_peak() assert peak.overflow # Overflow peak should result in 2 finished sub slots assert len(store.finished_sub_slots) == 2 # Add slots to the end, except for the last one, which we will use to test invalid SP blocks_2 = bt.get_consecutive_blocks( 1, block_list_input=blocks, skip_slots=3, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_2[-1].finished_sub_slots[:-1]: store.new_finished_sub_slot(slot, blockchain, blockchain.get_peak(), await blockchain.get_full_peak()) finished_sub_slots = blocks_2[-1].finished_sub_slots assert len(store.finished_sub_slots) == 4 # Test adding signage points for overflow blocks (sp_sub_slot) ss_start_iters = peak.sp_sub_slot_total_iters(test_constants) # for i in range(peak.signage_point_index, test_constants.NUM_SPS_SUB_SLOT): # if i < peak.signage_point_index: # continue # latest = peak # while latest.total_iters > peak.sp_total_iters(test_constants): # latest = blockchain.blocks[latest.prev_hash] # sp = get_signage_point( # test_constants, # blockchain.blocks, # latest, # ss_start_iters, # uint8(i), # [], # peak.sub_slot_iters, # ) # assert store.new_signage_point(i, blockchain.blocks, peak, peak.sub_slot_iters, sp) # Test adding signage points for overflow blocks (ip_sub_slot) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants), uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) # Test adding future signage point, a few slots forward (good) saved_sp_hash = None for slot_offset in range(1, len(finished_sub_slots)): for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA, ): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants) + slot_offset * peak.sub_slot_iters, uint8(i), finished_sub_slots[:slot_offset], peak.sub_slot_iters, ) assert sp.cc_vdf is not None saved_sp_hash = sp.cc_vdf.output.get_hash() assert store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) # Test adding future signage point (bad) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants) + len(finished_sub_slots) * peak.sub_slot_iters, uint8(i), finished_sub_slots[:len(finished_sub_slots)], peak.sub_slot_iters, ) assert not store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) # Test adding past signage point sp = SignagePoint( blocks[1].reward_chain_block.challenge_chain_sp_vdf, blocks[1].challenge_chain_sp_proof, blocks[1].reward_chain_block.reward_chain_sp_vdf, blocks[1].reward_chain_sp_proof, ) assert not store.new_signage_point( blocks[1].reward_chain_block.signage_point_index, blockchain, peak, blockchain.block_record( blocks[1].header_hash).sp_sub_slot_total_iters(test_constants), sp, ) # Get signage point by index assert (store.get_signage_point_by_index( finished_sub_slots[0].challenge_chain.get_hash(), uint8(4), finished_sub_slots[0].reward_chain.get_hash(), ) is not None) assert (store.get_signage_point_by_index( finished_sub_slots[0].challenge_chain.get_hash(), uint8(4), std_hash(b"1")) is None) # Get signage point by hash # TODO: address hint error and remove ignore # error: Argument 1 to "get_signage_point" of "FullNodeStore" has incompatible type "Optional[bytes32]"; # expected "bytes32" [arg-type] assert store.get_signage_point( saved_sp_hash) is not None # type: ignore[arg-type] assert store.get_signage_point(std_hash(b"2")) is None # Test adding signage points before genesis store.initialize_genesis_sub_slot() assert len(store.finished_sub_slots) == 1 for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, BlockCache({}, {}), None, uint128(0), uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(uint8(i), blockchain, None, peak.sub_slot_iters, sp) blocks_3 = bt.get_consecutive_blocks( 1, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_3[-1].finished_sub_slots: store.new_finished_sub_slot(slot, blockchain, None, None) assert len(store.finished_sub_slots) == 3 finished_sub_slots = blocks_3[-1].finished_sub_slots for slot_offset in range(1, len(finished_sub_slots) + 1): for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA, ): sp = get_signage_point( test_constants, BlockCache({}, {}), None, slot_offset * peak.sub_slot_iters, uint8(i), finished_sub_slots[:slot_offset], peak.sub_slot_iters, ) assert store.new_signage_point(uint8(i), blockchain, None, peak.sub_slot_iters, sp) # Test adding signage points after genesis blocks_4 = bt.get_consecutive_blocks( 1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) blocks_5 = bt.get_consecutive_blocks( 1, block_list_input=blocks_4, skip_slots=1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) # If this is not the case, fix test to find a block that is assert (blocks_4[-1].reward_chain_block.signage_point_index < test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA) await _validate_and_add_block( blockchain, blocks_4[-1], expected_result=ReceiveBlockResult.ADDED_AS_ORPHAN) sb = blockchain.block_record(blocks_4[-1].header_hash) store.new_peak(sb, blocks_4[-1], None, None, None, blockchain) for i in range( sb.signage_point_index + test_constants.NUM_SP_INTERVALS_EXTRA, test_constants.NUM_SPS_SUB_SLOT, ): if is_overflow_block(test_constants, uint8(i)): finished_sub_slots = blocks_5[-1].finished_sub_slots else: finished_sub_slots = [] sp = get_signage_point( test_constants, blockchain, sb, uint128(0), uint8(i), finished_sub_slots, peak.sub_slot_iters, ) assert store.new_signage_point(uint8(i), empty_blockchain, sb, peak.sub_slot_iters, sp) # Test future EOS cache store.initialize_genesis_sub_slot() blocks = bt.get_consecutive_blocks( 1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) await _validate_and_add_block_no_error(blockchain, blocks[-1]) while True: blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) await _validate_and_add_block_no_error(blockchain, blocks[-1]) sb = blockchain.block_record(blocks[-1].header_hash) if sb.first_in_sub_slot: break assert len(blocks) >= 2 dependant_sub_slots = blocks[-1].finished_sub_slots peak = blockchain.get_peak() peak_full_block = await blockchain.get_full_peak() for block in blocks[:-2]: sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) peak = sb peak_full_block = block res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, None, blockchain) assert res.added_eos is None assert store.new_finished_sub_slot(dependant_sub_slots[0], blockchain, peak, peak_full_block) is None block = blocks[-2] sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, None, blockchain) assert res.added_eos == dependant_sub_slots[0] assert res.new_signage_points == res.new_infusion_points == [] # Test future IP cache store.initialize_genesis_sub_slot() blocks = bt.get_consecutive_blocks( 60, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, ) for block in blocks[:5]: await _validate_and_add_block_no_error(blockchain, block) sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, None, blockchain) assert res.added_eos is None case_0, case_1 = False, False for i in range(5, len(blocks) - 1): prev_block = blocks[i] block = blocks[i + 1] new_ip = NewInfusionPointVDF( block.reward_chain_block.get_unfinished().get_hash(), block.reward_chain_block.challenge_chain_ip_vdf, block.challenge_chain_ip_proof, block.reward_chain_block.reward_chain_ip_vdf, block.reward_chain_ip_proof, block.reward_chain_block.infused_challenge_chain_ip_vdf, block.infused_challenge_chain_ip_proof, ) store.add_to_future_ip(new_ip) await _validate_and_add_block_no_error(blockchain, prev_block) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( prev_block.header_hash) sb = blockchain.block_record(prev_block.header_hash) res = store.new_peak(sb, prev_block, sp_sub_slot, ip_sub_slot, None, blockchain) if len(block.finished_sub_slots) == 0: case_0 = True assert res.new_infusion_points == [new_ip] else: case_1 = True assert res.new_infusion_points == [] found_ips: List[timelord_protocol.NewInfusionPointVDF] = [] for ss in block.finished_sub_slots: ipvdf = store.new_finished_sub_slot( ss, blockchain, sb, prev_block) assert ipvdf is not None found_ips += ipvdf assert found_ips == [new_ip] # If flaky, increase the number of blocks created assert case_0 and case_1 # Try to get two blocks in the same slot, such that we have # SP, B2 SP .... SP B1 # i2 ......... i1 # Then do a reorg up to B2, removing all signage points after B2, but not before log.warning(f"Adding blocks up to {blocks[-1]}") for block in blocks: await _validate_and_add_block_no_error(blockchain, block) log.warning(f"Starting loop") while True: log.warning("Looping") blocks = bt.get_consecutive_blocks(1, block_list_input=blocks, skip_slots=1) await _validate_and_add_block_no_error(blockchain, blocks[-1]) peak = blockchain.get_peak() sub_slots = await blockchain.get_sp_and_ip_sub_slots( peak.header_hash) store.new_peak(peak, blocks[-1], sub_slots[0], sub_slots[1], None, blockchain) blocks = bt.get_consecutive_blocks( 2, block_list_input=blocks, guarantee_transaction_block=True) i3 = blocks[-3].reward_chain_block.signage_point_index i2 = blocks[-2].reward_chain_block.signage_point_index i1 = blocks[-1].reward_chain_block.signage_point_index if (len(blocks[-2].finished_sub_slots) == len( blocks[-1].finished_sub_slots) == 0 and not is_overflow_block(test_constants, signage_point_index=i2) and not is_overflow_block(test_constants, signage_point_index=i1) and i2 > i3 + 3 and i1 > (i2 + 3)): # We hit all the conditions that we want all_sps: List[Optional[SignagePoint]] = [ None ] * test_constants.NUM_SPS_SUB_SLOT def assert_sp_none(sp_index: int, is_none: bool): sp_to_check: Optional[SignagePoint] = all_sps[sp_index] assert sp_to_check is not None assert sp_to_check.cc_vdf is not None fetched = store.get_signage_point( sp_to_check.cc_vdf.output.get_hash()) assert (fetched is None) == is_none if fetched is not None: assert fetched == sp_to_check for i in range(i3 + 1, test_constants.NUM_SPS_SUB_SLOT - 3): finished_sub_slots = [] sp = get_signage_point( test_constants, blockchain, peak, uint128(peak.ip_sub_slot_total_iters(bt.constants)), uint8(i), finished_sub_slots, peak.sub_slot_iters, ) all_sps[i] = sp assert store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) # Adding a new peak clears all SPs after that peak await _validate_and_add_block_no_error(blockchain, blocks[-2]) peak = blockchain.get_peak() sub_slots = await blockchain.get_sp_and_ip_sub_slots( peak.header_hash) store.new_peak(peak, blocks[-2], sub_slots[0], sub_slots[1], None, blockchain) assert_sp_none(i2, False) assert_sp_none(i2 + 1, False) assert_sp_none(i1, True) assert_sp_none(i1 + 1, True) assert_sp_none(i1 + 4, True) for i in range(i2, test_constants.NUM_SPS_SUB_SLOT): if is_overflow_block(test_constants, uint8(i)): blocks_alt = bt.get_consecutive_blocks( 1, block_list_input=blocks[:-1], skip_slots=1) finished_sub_slots = blocks_alt[-1].finished_sub_slots else: finished_sub_slots = [] sp = get_signage_point( test_constants, blockchain, peak, uint128(peak.ip_sub_slot_total_iters(bt.constants)), uint8(i), finished_sub_slots, peak.sub_slot_iters, ) all_sps[i] = sp assert store.new_signage_point(uint8(i), blockchain, peak, peak.sub_slot_iters, sp) assert_sp_none(i2, False) assert_sp_none(i2 + 1, False) assert_sp_none(i1, False) assert_sp_none(i1 + 1, False) assert_sp_none(i1 + 4, False) await _validate_and_add_block_no_error(blockchain, blocks[-1]) peak = blockchain.get_peak() sub_slots = await blockchain.get_sp_and_ip_sub_slots( peak.header_hash) # Do a reorg, which should remove everything after B2 store.new_peak( peak, blocks[-1], sub_slots[0], sub_slots[1], (await blockchain.get_block_records_at([blocks[-2].height]))[0], blockchain, ) assert_sp_none(i2, False) assert_sp_none(i2 + 1, False) assert_sp_none(i1, True) assert_sp_none(i1 + 1, True) assert_sp_none(i1 + 4, True) break else: for block in blocks[-2:]: await _validate_and_add_block_no_error(blockchain, block)
async def test_basic_store(self, empty_blockchain, normalized_to_identity: bool = False): blockchain = empty_blockchain blocks = bt.get_consecutive_blocks( 10, seed=b"1234", normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) store = await FullNodeStore.create(test_constants) unfinished_blocks = [] for block in blocks: unfinished_blocks.append( UnfinishedBlock( block.finished_sub_slots, block.reward_chain_block.get_unfinished(), block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, block.transactions_info, block.transactions_generator, [], )) # Add/get candidate block assert store.get_candidate_block( unfinished_blocks[0].get_hash()) is None for height, unf_block in enumerate(unfinished_blocks): store.add_candidate_block(unf_block.get_hash(), height, unf_block) 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 # 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) store.clear_seen_unfinished_blocks() assert not store.seen_unfinished_block(h_hash_1) # Add/get unfinished block for height, unf_block in enumerate(unfinished_blocks): assert store.get_unfinished_block(unf_block.partial_hash) is None store.add_unfinished_block( height, unf_block, PreValidationResult(None, uint64(123532), None)) 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 blocks = bt.get_consecutive_blocks( 1, skip_slots=5, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, ) sub_slots = blocks[0].finished_sub_slots assert len(sub_slots) == 5 assert (store.get_finished_sub_slots( BlockCache({}), None, sub_slots[0].challenge_chain.challenge_chain_end_of_slot_vdf. challenge, ) == []) # Test adding non-connecting sub-slots genesis assert store.get_sub_slot(test_constants.GENESIS_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 store.new_finished_sub_slot(sub_slots[1], {}, None, None) is None assert store.new_finished_sub_slot(sub_slots[2], {}, None, None) is None # Test adding sub-slots after genesis assert store.new_finished_sub_slot(sub_slots[0], {}, None, None) is not None assert store.get_sub_slot( sub_slots[0].challenge_chain.get_hash())[0] == 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, None) is not None for i in range(len(sub_slots)): assert store.new_finished_sub_slot(sub_slots[i], {}, None, None) is not None assert store.get_sub_slot( sub_slots[i].challenge_chain.get_hash())[0] == sub_slots[i] assert store.get_finished_sub_slots( BlockCache({}), None, sub_slots[-1].challenge_chain.get_hash()) == sub_slots assert store.get_finished_sub_slots(BlockCache( {}), None, std_hash(b"not a valid hash")) is None assert (store.get_finished_sub_slots( BlockCache({}), None, sub_slots[-2].challenge_chain.get_hash()) == sub_slots[:-1]) # Test adding genesis peak await blockchain.receive_block(blocks[0]) peak = blockchain.get_peak() peak_full_block = await blockchain.get_full_peak() if peak.overflow: store.new_peak(peak, peak_full_block, sub_slots[-2], sub_slots[-1], False, {}) else: store.new_peak(peak, peak_full_block, None, sub_slots[-1], 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 if peak.overflow: assert store.get_sub_slot( sub_slots[3].challenge_chain.get_hash())[0] == sub_slots[3] else: assert store.get_sub_slot( sub_slots[3].challenge_chain.get_hash()) is None assert store.get_sub_slot( sub_slots[4].challenge_chain.get_hash())[0] == sub_slots[4] assert (store.get_finished_sub_slots( blockchain, peak, sub_slots[-1].challenge_chain.get_hash(), ) == []) # Test adding non genesis peak directly blocks = bt.get_consecutive_blocks( 2, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) blocks = bt.get_consecutive_blocks( 3, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for block in blocks: await blockchain.receive_block(block) sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, False, blockchain) assert res[0] is None # Add reorg blocks blocks_reorg = bt.get_consecutive_blocks( 20, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for block in blocks_reorg: res, _, _ = await blockchain.receive_block(block) if res == ReceiveBlockResult.NEW_PEAK: sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, True, blockchain) assert res[0] is None # Add slots to the end blocks_2 = bt.get_consecutive_blocks( 1, block_list_input=blocks_reorg, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_2[-1].finished_sub_slots: store.new_finished_sub_slot(slot, blockchain, blockchain.get_peak(), await blockchain.get_full_peak()) assert store.get_sub_slot( sub_slots[3].challenge_chain.get_hash()) is None assert store.get_sub_slot( sub_slots[4].challenge_chain.get_hash()) is None # Test adding signage point peak = blockchain.get_peak() ss_start_iters = peak.ip_sub_slot_total_iters(test_constants) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, ss_start_iters, uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(i, blockchain, peak, peak.sub_slot_iters, sp) blocks = blocks_reorg while True: blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) res, _, _ = await blockchain.receive_block(blocks[-1]) if res == ReceiveBlockResult.NEW_PEAK: sb = blockchain.block_record(blocks[-1].header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( blocks[-1].header_hash) res = store.new_peak(sb, blocks[-1], sp_sub_slot, ip_sub_slot, True, blockchain) assert res[0] is None if sb.overflow and sp_sub_slot is not None: assert sp_sub_slot != ip_sub_slot break peak = blockchain.get_peak() assert peak.overflow # Overflow peak should result in 2 finished sub slots assert len(store.finished_sub_slots) == 2 # Add slots to the end, except for the last one, which we will use to test invalid SP blocks_2 = bt.get_consecutive_blocks( 1, block_list_input=blocks, skip_slots=3, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_2[-1].finished_sub_slots[:-1]: store.new_finished_sub_slot(slot, blockchain, blockchain.get_peak(), await blockchain.get_full_peak()) finished_sub_slots = blocks_2[-1].finished_sub_slots assert len(store.finished_sub_slots) == 4 # Test adding signage points for overflow blocks (sp_sub_slot) ss_start_iters = peak.sp_sub_slot_total_iters(test_constants) # for i in range(peak.signage_point_index, test_constants.NUM_SPS_SUB_SLOT): # if i < peak.signage_point_index: # continue # latest = peak # while latest.total_iters > peak.sp_total_iters(test_constants): # latest = blockchain.blocks[latest.prev_hash] # sp = get_signage_point( # test_constants, # blockchain.blocks, # latest, # ss_start_iters, # uint8(i), # [], # peak.sub_slot_iters, # ) # assert store.new_signage_point(i, blockchain.blocks, peak, peak.sub_slot_iters, sp) # Test adding signage points for overflow blocks (ip_sub_slot) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants), uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(i, blockchain, peak, peak.sub_slot_iters, sp) # Test adding future signage point, a few slots forward (good) saved_sp_hash = None for slot_offset in range(1, len(finished_sub_slots)): for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA, ): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants) + slot_offset * peak.sub_slot_iters, uint8(i), finished_sub_slots[:slot_offset], peak.sub_slot_iters, ) assert sp.cc_vdf is not None saved_sp_hash = sp.cc_vdf.output.get_hash() assert store.new_signage_point(i, blockchain, peak, peak.sub_slot_iters, sp) # Test adding future signage point (bad) for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, blockchain, peak, peak.ip_sub_slot_total_iters(test_constants) + len(finished_sub_slots) * peak.sub_slot_iters, uint8(i), finished_sub_slots[:len(finished_sub_slots)], peak.sub_slot_iters, ) assert not store.new_signage_point(i, blockchain, peak, peak.sub_slot_iters, sp) # Test adding past signage point sp = SignagePoint( blocks[1].reward_chain_block.challenge_chain_sp_vdf, blocks[1].challenge_chain_sp_proof, blocks[1].reward_chain_block.reward_chain_sp_vdf, blocks[1].reward_chain_sp_proof, ) assert not store.new_signage_point( blocks[1].reward_chain_block.signage_point_index, {}, peak, blockchain.block_record( blocks[1].header_hash).sp_sub_slot_total_iters(test_constants), sp, ) # Get signage point by index assert (store.get_signage_point_by_index( finished_sub_slots[0].challenge_chain.get_hash(), 4, finished_sub_slots[0].reward_chain.get_hash(), ) is not None) assert (store.get_signage_point_by_index( finished_sub_slots[0].challenge_chain.get_hash(), 4, std_hash(b"1")) is None) # Get signage point by hash assert store.get_signage_point(saved_sp_hash) is not None assert store.get_signage_point(std_hash(b"2")) is None # Test adding signage points before genesis store.initialize_genesis_sub_slot() assert len(store.finished_sub_slots) == 1 for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA): sp = get_signage_point( test_constants, BlockCache({}, {}), None, uint128(0), uint8(i), [], peak.sub_slot_iters, ) assert store.new_signage_point(i, {}, None, peak.sub_slot_iters, sp) blocks_3 = bt.get_consecutive_blocks( 1, skip_slots=2, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) for slot in blocks_3[-1].finished_sub_slots: store.new_finished_sub_slot(slot, {}, None, None) assert len(store.finished_sub_slots) == 3 finished_sub_slots = blocks_3[-1].finished_sub_slots for slot_offset in range(1, len(finished_sub_slots) + 1): for i in range( 1, test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA, ): sp = get_signage_point( test_constants, BlockCache({}, {}), None, slot_offset * peak.sub_slot_iters, uint8(i), finished_sub_slots[:slot_offset], peak.sub_slot_iters, ) assert store.new_signage_point(i, {}, None, peak.sub_slot_iters, sp) # Test adding signage points after genesis blocks_4 = bt.get_consecutive_blocks( 1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) blocks_5 = bt.get_consecutive_blocks( 1, block_list_input=blocks_4, skip_slots=1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) # If this is not the case, fix test to find a block that is assert (blocks_4[-1].reward_chain_block.signage_point_index < test_constants.NUM_SPS_SUB_SLOT - test_constants.NUM_SP_INTERVALS_EXTRA) await blockchain.receive_block(blocks_4[-1]) sb = blockchain.block_record(blocks_4[-1].header_hash) store.new_peak(sb, blocks_4[-1], None, None, False, blockchain) for i in range( sb.signage_point_index + test_constants.NUM_SP_INTERVALS_EXTRA, test_constants.NUM_SPS_SUB_SLOT, ): if is_overflow_block(test_constants, uint8(i)): finished_sub_slots = blocks_5[-1].finished_sub_slots else: finished_sub_slots = [] sp = get_signage_point( test_constants, blockchain, sb, uint128(0), uint8(i), finished_sub_slots, peak.sub_slot_iters, ) assert store.new_signage_point(i, empty_blockchain, sb, peak.sub_slot_iters, sp) # Test future EOS cache store.initialize_genesis_sub_slot() blocks = bt.get_consecutive_blocks( 1, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) await blockchain.receive_block(blocks[-1]) while True: blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, ) await blockchain.receive_block(blocks[-1]) sb = blockchain.block_record(blocks[-1].header_hash) if sb.first_in_sub_slot: break assert len(blocks) >= 2 dependant_sub_slots = blocks[-1].finished_sub_slots peak = blockchain.get_peak() peak_full_block = await blockchain.get_full_peak() for block in blocks[:-2]: sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) peak = sb peak_full_block = block res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, False, blockchain) assert res[0] is None assert store.new_finished_sub_slot(dependant_sub_slots[0], blockchain, peak, peak_full_block) is None block = blocks[-2] sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, False, blockchain) assert res[0] == dependant_sub_slots[0] assert res[1] == res[2] == [] # Test future IP cache store.initialize_genesis_sub_slot() blocks = bt.get_consecutive_blocks( 60, normalized_to_identity_cc_ip=normalized_to_identity, normalized_to_identity_cc_sp=normalized_to_identity, normalized_to_identity_cc_eos=normalized_to_identity, normalized_to_identity_icc_eos=normalized_to_identity, ) for block in blocks[:5]: await blockchain.receive_block(block) sb = blockchain.block_record(block.header_hash) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( block.header_hash) res = store.new_peak(sb, block, sp_sub_slot, ip_sub_slot, False, blockchain) assert res[0] is None case_0, case_1 = False, False for i in range(5, len(blocks) - 1): prev_block = blocks[i] block = blocks[i + 1] new_ip = NewInfusionPointVDF( block.reward_chain_block.get_unfinished().get_hash(), block.reward_chain_block.challenge_chain_ip_vdf, block.challenge_chain_ip_proof, block.reward_chain_block.reward_chain_ip_vdf, block.reward_chain_ip_proof, block.reward_chain_block.infused_challenge_chain_ip_vdf, block.infused_challenge_chain_ip_proof, ) store.add_to_future_ip(new_ip) await blockchain.receive_block(prev_block) sp_sub_slot, ip_sub_slot = await blockchain.get_sp_and_ip_sub_slots( prev_block.header_hash) sb = blockchain.block_record(prev_block.header_hash) res = store.new_peak(sb, prev_block, sp_sub_slot, ip_sub_slot, False, blockchain) if len(block.finished_sub_slots) == 0: case_0 = True assert res[2] == [new_ip] else: case_1 = True assert res[2] == [] found_ips = [] for ss in block.finished_sub_slots: found_ips += store.new_finished_sub_slot( ss, blockchain, sb, prev_block) assert found_ips == [new_ip] # If flaky, increase the number of blocks created assert case_0 and case_1
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, proof_of_space: ProofOfSpace, slot_cc_challenge: bytes32, farmer_reward_puzzle_hash: bytes32, pool_target: PoolTarget, get_plot_signature: Callable[[bytes32, G1Element], G2Element], get_pool_signature: Callable[[PoolTarget, Optional[G1Element]], Optional[G2Element]], signage_point: SignagePoint, timestamp: uint64, blocks: BlockchainInterface, seed: bytes32 = b"", block_generator: Optional[BlockGenerator] = None, aggregate_sig: G2Element = G2Element(), additions: Optional[List[Coin]] = None, removals: Optional[List[Coin]] = None, prev_block: Optional[BlockRecord] = None, finished_sub_slots_input: List[EndOfSubSlotBundle] = None, ) -> UnfinishedBlock: """ Creates a new unfinished block using all the information available at the signage point. This will have to be modified using information from the infusion point. Args: constants: consensus constants being used for this chain sub_slot_start_total_iters: the starting sub-slot iters at the signage point sub-slot sub_slot_iters: sub-slot-iters at the infusion point epoch signage_point_index: signage point index of the block to create sp_iters: sp_iters of the block to create ip_iters: ip_iters of the block to create proof_of_space: proof of space of the block to create slot_cc_challenge: challenge hash at the sp sub-slot farmer_reward_puzzle_hash: where to pay out farmer rewards pool_target: where to pay out pool rewards get_plot_signature: function that returns signature corresponding to plot public key get_pool_signature: function that returns signature corresponding to pool public key signage_point: signage point information (VDFs) timestamp: timestamp to add to the foliage block, if created seed: seed to randomize chain block_generator: transactions to add to the foliage block, if created aggregate_sig: aggregate of all transctions (or infinity element) additions: Coins added in spend_bundle removals: Coins removed in spend_bundle prev_block: previous block (already in chain) from the signage point blocks: dictionary from header hash to SBR of all included SBR finished_sub_slots_input: finished_sub_slots at the signage point Returns: """ if finished_sub_slots_input is None: finished_sub_slots: List[EndOfSubSlotBundle] = [] else: finished_sub_slots = finished_sub_slots_input.copy() overflow: bool = sp_iters > ip_iters total_iters_sp: uint128 = uint128(sub_slot_start_total_iters + sp_iters) is_genesis: bool = prev_block is None new_sub_slot: bool = len(finished_sub_slots) > 0 cc_sp_hash: Optional[bytes32] = slot_cc_challenge # Only enters this if statement if we are in testing mode (making VDF proofs here) if signage_point.cc_vdf is not None: assert signage_point.rc_vdf is not None cc_sp_hash = signage_point.cc_vdf.output.get_hash() rc_sp_hash = signage_point.rc_vdf.output.get_hash() else: if new_sub_slot: rc_sp_hash = finished_sub_slots[-1].reward_chain.get_hash() else: if is_genesis: rc_sp_hash = constants.GENESIS_CHALLENGE else: assert prev_block is not None assert blocks is not None curr = prev_block while not curr.first_in_sub_slot: curr = blocks.block_record(curr.prev_hash) assert curr.finished_reward_slot_hashes is not None rc_sp_hash = curr.finished_reward_slot_hashes[-1] signage_point = SignagePoint(None, None, None, None) cc_sp_signature: Optional[G2Element] = get_plot_signature(cc_sp_hash, proof_of_space.plot_public_key) rc_sp_signature: Optional[G2Element] = get_plot_signature(rc_sp_hash, proof_of_space.plot_public_key) assert cc_sp_signature is not None 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 + (sub_slot_iters if overflow else 0)) rc_block = RewardChainBlockUnfinished( total_iters, signage_point_index, slot_cc_challenge, proof_of_space, signage_point.cc_vdf, cc_sp_signature, signage_point.rc_vdf, rc_sp_signature, ) if additions is None: additions = [] if removals is None: removals = [] (foliage, foliage_transaction_block, transactions_info,) = create_foliage( constants, rc_block, block_generator, aggregate_sig, additions, removals, prev_block, blocks, total_iters_sp, timestamp, farmer_reward_puzzle_hash, pool_target, get_plot_signature, get_pool_signature, seed, ) return UnfinishedBlock( finished_sub_slots, rc_block, signage_point.cc_proof, signage_point.rc_proof, foliage, foliage_transaction_block, transactions_info, block_generator.program if block_generator else None, block_generator.block_height_list() if block_generator else [], )
async def test1(self, two_nodes): num_blocks = 5 test_rpc_port = uint16(21522) nodes, _ = two_nodes full_node_api_1, full_node_api_2 = nodes server_1 = full_node_api_1.full_node.server server_2 = full_node_api_2.full_node.server def stop_node_cb(): full_node_api_1._close() server_1.close_all() full_node_rpc_api = FullNodeRpcApi(full_node_api_1.full_node) config = bt.config hostname = config["self_hostname"] daemon_port = config["daemon_port"] rpc_cleanup = await start_rpc_server( full_node_rpc_api, hostname, daemon_port, test_rpc_port, stop_node_cb, bt.root_path, config, connect_to_daemon=False, ) try: client = await FullNodeRpcClient.create(self_hostname, test_rpc_port, bt.root_path, config) state = await client.get_blockchain_state() assert state["peak"] is None assert not state["sync"]["sync_mode"] assert state["difficulty"] > 0 assert state["sub_slot_iters"] > 0 blocks = bt.get_consecutive_blocks(num_blocks) blocks = bt.get_consecutive_blocks(num_blocks, block_list_input=blocks, guarantee_transaction_block=True) assert len(await client.get_unfinished_block_headers()) == 0 assert len((await client.get_block_records(0, 100))) == 0 for block in blocks: if is_overflow_block(test_constants, block.reward_chain_block.signage_point_index): finished_ss = block.finished_sub_slots[:-1] else: finished_ss = block.finished_sub_slots unf = UnfinishedBlock( finished_ss, block.reward_chain_block.get_unfinished(), block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, block.transactions_info, block.transactions_generator, [], ) await full_node_api_1.full_node.respond_unfinished_block( full_node_protocol.RespondUnfinishedBlock(unf), None ) await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block), None) assert len(await client.get_unfinished_block_headers()) > 0 assert len(await client.get_all_block(0, 2)) == 2 state = await client.get_blockchain_state() block = await client.get_block(state["peak"].header_hash) assert block == blocks[-1] assert (await client.get_block(bytes([1] * 32))) is None assert (await client.get_block_record_by_height(2)).header_hash == blocks[2].header_hash assert len((await client.get_block_records(0, 100))) == num_blocks * 2 assert (await client.get_block_record_by_height(100)) is None ph = list(blocks[-1].get_included_reward_coins())[0].puzzle_hash coins = await client.get_coin_records_by_puzzle_hash(ph) print(coins) assert len(coins) >= 1 pid = list(blocks[-1].get_included_reward_coins())[0].parent_coin_info pid_2 = list(blocks[-1].get_included_reward_coins())[1].parent_coin_info coins = await client.get_coin_records_by_parent_ids([pid, pid_2]) print(coins) assert len(coins) == 2 additions, removals = await client.get_additions_and_removals(blocks[-1].header_hash) assert len(additions) >= 2 and len(removals) == 0 wallet = WalletTool(full_node_api_1.full_node.constants) wallet_receiver = WalletTool(full_node_api_1.full_node.constants, AugSchemeMPL.key_gen(std_hash(b"123123"))) ph = wallet.get_new_puzzlehash() ph_2 = wallet.get_new_puzzlehash() ph_receiver = wallet_receiver.get_new_puzzlehash() assert len(await client.get_coin_records_by_puzzle_hash(ph)) == 0 assert len(await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 0 blocks = bt.get_consecutive_blocks( 2, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=ph, pool_reward_puzzle_hash=ph, ) for block in blocks[-2:]: await full_node_api_1.full_node.respond_block(full_node_protocol.RespondBlock(block)) assert len(await client.get_coin_records_by_puzzle_hash(ph)) == 2 assert len(await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 0 coin_to_spend = list(blocks[-1].get_included_reward_coins())[0] spend_bundle = wallet.generate_signed_transaction(coin_to_spend.amount, ph_receiver, coin_to_spend) assert len(await client.get_all_mempool_items()) == 0 assert len(await client.get_all_mempool_tx_ids()) == 0 assert (await client.get_mempool_item_by_tx_id(spend_bundle.name())) is None await client.push_tx(spend_bundle) coin = spend_bundle.additions()[0] assert len(await client.get_all_mempool_items()) == 1 assert len(await client.get_all_mempool_tx_ids()) == 1 assert ( SpendBundle.from_json_dict(list((await client.get_all_mempool_items()).values())[0]["spend_bundle"]) == spend_bundle ) assert (await client.get_all_mempool_tx_ids())[0] == spend_bundle.name() assert ( SpendBundle.from_json_dict( (await client.get_mempool_item_by_tx_id(spend_bundle.name()))["spend_bundle"] ) == spend_bundle ) assert (await client.get_coin_record_by_name(coin.name())) is None await full_node_api_1.farm_new_transaction_block(FarmNewBlockProtocol(ph_2)) assert (await client.get_coin_record_by_name(coin.name())).coin == coin assert len(await client.get_coin_records_by_puzzle_hash(ph_receiver)) == 1 assert len(list(filter(lambda cr: not cr.spent, (await client.get_coin_records_by_puzzle_hash(ph))))) == 3 assert len(await client.get_coin_records_by_puzzle_hashes([ph_receiver, ph])) == 5 assert len(await client.get_coin_records_by_puzzle_hash(ph, False)) == 3 assert len(await client.get_coin_records_by_puzzle_hash(ph, True)) == 4 assert len(await client.get_coin_records_by_puzzle_hash(ph, True, 0, 100)) == 4 assert len(await client.get_coin_records_by_puzzle_hash(ph, True, 50, 100)) == 0 assert len(await client.get_coin_records_by_puzzle_hash(ph, True, 0, blocks[-1].height + 1)) == 2 assert len(await client.get_coin_records_by_puzzle_hash(ph, True, 0, 1)) == 0 assert len(await client.get_connections()) == 0 await client.open_connection(self_hostname, server_2._port) async def num_connections(): return len(await client.get_connections()) await time_out_assert(10, num_connections, 1) connections = await client.get_connections() assert NodeType(connections[0]["type"]) == NodeType.FULL_NODE.value assert len(await client.get_connections(NodeType.FULL_NODE)) == 1 assert len(await client.get_connections(NodeType.FARMER)) == 0 await client.close_connection(connections[0]["node_id"]) await time_out_assert(10, num_connections, 0) finally: # Checks that the RPC manages to stop the node client.close() await client.await_closed() await rpc_cleanup()
async def test_full_block_performance(self, wallet_nodes): full_node_1, server_1, wallet_a, wallet_receiver = wallet_nodes blocks = await full_node_1.get_all_full_blocks() full_node_1.full_node.mempool_manager.limit_factor = 1 wallet_ph = wallet_a.get_new_puzzlehash() blocks = bt.get_consecutive_blocks( 10, block_list_input=blocks, guarantee_transaction_block=True, farmer_reward_puzzle_hash=wallet_ph, pool_reward_puzzle_hash=wallet_ph, ) for block in blocks: await full_node_1.full_node.respond_block(fnp.RespondBlock(block)) start_height = (full_node_1.full_node.blockchain.get_peak().height if full_node_1.full_node.blockchain.get_peak() is not None else -1) incoming_queue, node_id = await add_dummy_connection(server_1, 12312) fake_peer = server_1.all_connections[node_id] # Mempool has capacity of 100, make 110 unspents that we can use puzzle_hashes = [] # Makes a bunch of coins for i in range(20): conditions_dict: Dict = {ConditionOpcode.CREATE_COIN: []} # This should fit in one transaction for _ in range(100): receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() puzzle_hashes.append(receiver_puzzlehash) output = ConditionWithArgs( ConditionOpcode.CREATE_COIN, [receiver_puzzlehash, int_to_bytes(100000000)]) conditions_dict[ConditionOpcode.CREATE_COIN].append(output) spend_bundle = wallet_a.generate_signed_transaction( 100, puzzle_hashes[0], get_future_reward_coins(blocks[1 + i])[0], condition_dic=conditions_dict, ) assert spend_bundle is not None respond_transaction_2 = fnp.RespondTransaction(spend_bundle) await full_node_1.respond_transaction(respond_transaction_2, fake_peer) blocks = bt.get_consecutive_blocks( 1, block_list_input=blocks, guarantee_transaction_block=True, transaction_data=spend_bundle, ) await full_node_1.full_node.respond_block( fnp.RespondBlock(blocks[-1]), fake_peer) await time_out_assert(10, node_height_at_least, True, full_node_1, start_height + 20) spend_bundles = [] spend_bundle_ids = [] # Fill mempool for puzzle_hash in puzzle_hashes[1:]: coin_record = (await full_node_1.full_node.coin_store. get_coin_records_by_puzzle_hash(True, puzzle_hash))[0] receiver_puzzlehash = wallet_receiver.get_new_puzzlehash() if puzzle_hash == puzzle_hashes[-1]: fee = 100000000 # 100 million (20 fee per cost) else: fee = random.randint(1, 100000000) spend_bundle = wallet_receiver.generate_signed_transaction( uint64(500), receiver_puzzlehash, coin_record.coin, fee=fee) spend_bundles.append(spend_bundle) spend_bundle_ids.append(spend_bundle.get_hash()) pr = cProfile.Profile() pr.enable() start = time.time() num_tx: int = 0 for spend_bundle, spend_bundle_id in zip(spend_bundles, spend_bundle_ids): num_tx += 1 respond_transaction = fnp.RespondTransaction(spend_bundle) await full_node_1.respond_transaction(respond_transaction, fake_peer) request = fnp.RequestTransaction(spend_bundle_id) req = await full_node_1.request_transaction(request) if req is None: break log.warning(f"Num Tx: {num_tx}") log.warning(f"Time for mempool: {time.time() - start}") pr.create_stats() pr.dump_stats("./mempool-benchmark.pstats") # Create an unfinished block peak = full_node_1.full_node.blockchain.get_peak() assert peak is not None curr: BlockRecord = peak while not curr.is_transaction_block: curr = full_node_1.full_node.blockchain.block_record( curr.prev_hash) mempool_bundle = await full_node_1.full_node.mempool_manager.create_bundle_from_mempool( curr.header_hash) if mempool_bundle is None: spend_bundle = None else: spend_bundle = mempool_bundle[0] current_blocks = await full_node_1.get_all_full_blocks() blocks = bt.get_consecutive_blocks( 1, transaction_data=spend_bundle, block_list_input=current_blocks, guarantee_transaction_block=True, ) block = blocks[-1] unfinished = UnfinishedBlock( block.finished_sub_slots, block.reward_chain_block.get_unfinished(), block.challenge_chain_sp_proof, block.reward_chain_sp_proof, block.foliage, block.foliage_transaction_block, block.transactions_info, block.transactions_generator, [], ) pr = cProfile.Profile() pr.enable() start = time.time() res = await full_node_1.respond_unfinished_block( fnp.RespondUnfinishedBlock(unfinished), fake_peer) log.warning(f"Res: {res}") log.warning(f"Time for unfinished: {time.time() - start}") pr.create_stats() pr.dump_stats("./unfinished-benchmark.pstats") pr = cProfile.Profile() pr.enable() start = time.time() # No transactions generator, the full node already cached it from the unfinished block block_small = dataclasses.replace(block, transactions_generator=None) res = await full_node_1.full_node.respond_block( fnp.RespondBlock(block_small)) log.warning(f"Res: {res}") log.warning(f"Time for full block: {time.time() - start}") pr.create_stats() pr.dump_stats("./full-block-benchmark.pstats")
"229646fb33551966039d9324c0d10166c554d20e9a11e3f30942ec0bb346377e") ), ) request_unfinished_block = full_node_protocol.RequestUnfinishedBlock( bytes32( bytes.fromhex( "8b5e5a59f33bb89e1bfd5aca79409352864e70aa7765c331d641875f83d59d1d") ), ) unfinished_block = UnfinishedBlock( [end_of_subslot_bundle], reward_chain_block.get_unfinished(), vdf_proof, vdf_proof, foliage, foliage_transaction_block, transactions_info, SerializedProgram.from_bytes( bytes.fromhex( "ff01ffff33ffa0f8912302fb33b8188046662785704afc3dd945074e4b45499a7173946e044695ff8203e880ffff33ffa03eaa52e850322dbc281c6b922e9d8819c7b4120ee054c4aa79db50be516a2bcaff8207d08080" )), [uint32(1862532955)], ) respond_unfinished_block = full_node_protocol.RespondUnfinishedBlock( unfinished_block) new_signage_point_or_end_of_subslot = full_node_protocol.NewSignagePointOrEndOfSubSlot( bytes32( bytes.fromhex( "f945510ccea927f832635e56bc20315c92943e108d2b458ac91a290a82e02997") ),