def create_multiple_ref_generator(args: MultipleCompressorArg, spend_bundle: SpendBundle) -> BlockGenerator: """ Decompress a transaction by referencing bytes from multiple input generator references """ compressed_cse_list = compressed_coin_solution_entry_list(spend_bundle) program = TEST_MULTIPLE.curry( DECOMPRESS_PUZZLE, DECOMPRESS_CSE_WITH_PREFIX, args.arg[0].start, args.arg[0].end - args.split_offset, args.arg[1].end - args.split_offset, args.arg[1].end, compressed_cse_list, ) # TODO aqk: Improve ergonomics of CompressorArg -> GeneratorArg conversion generator_args = [ GeneratorArg(FAKE_BLOCK_HEIGHT1, args.arg[0].generator), GeneratorArg(FAKE_BLOCK_HEIGHT2, args.arg[1].generator), ] return BlockGenerator(program, generator_args)
def create_block_generator( generator: SerializedProgram, block_heights_list: List[uint32], generator_block_cache: GeneratorBlockCacheInterface ) -> Optional[BlockGenerator]: """`create_block_generator` will returns None if it fails to look up any referenced block""" generator_arg_list: List[GeneratorArg] = [] for i in block_heights_list: previous_generator = generator_block_cache.get_generator_for_block_height( i) if previous_generator is None: log.error( f"Failed to look up generator for block {i}. Ref List: {block_heights_list}" ) return None generator_arg_list.append(GeneratorArg(i, previous_generator)) return BlockGenerator(generator, generator_arg_list)
def create_compressed_generator( original_generator: CompressorArg, compressed_cse_list: List[List[Union[List[uint64], List[Union[bytes, None, Program]]]]], ) -> BlockGenerator: """ Bind the generator block program template to a particular reference block, template bytes offsets, and SpendBundle. """ start = original_generator.start end = original_generator.end program = DECOMPRESS_BLOCK.curry(DECOMPRESS_PUZZLE, DECOMPRESS_CSE_WITH_PREFIX, Program.to(start), Program.to(end), compressed_cse_list) generator_arg = GeneratorArg(original_generator.block_height, original_generator.generator) return BlockGenerator(program, [generator_arg])
def block_generator() -> BlockGenerator: generator_args = [ GeneratorArg(uint32(0), to_sp(FIRST_GENERATOR)), GeneratorArg(uint32(1), to_sp(SECOND_GENERATOR)) ] return BlockGenerator(to_sp(COMPILED_GENERATOR_CODE), generator_args)
async def get_block_generator( self, block: Union[FullBlock, UnfinishedBlock], additional_blocks=None ) -> Optional[BlockGenerator]: if additional_blocks is None: additional_blocks = {} ref_list = block.transactions_generator_ref_list if block.transactions_generator is None: assert len(ref_list) == 0 return None if len(ref_list) == 0: return BlockGenerator(block.transactions_generator, []) result: List[GeneratorArg] = [] previous_block_hash = block.prev_header_hash if ( self.try_block_record(previous_block_hash) and self.height_to_hash(self.block_record(previous_block_hash).height) == previous_block_hash ): # We are not in a reorg, no need to look up alternate header hashes (we can get them from height_to_hash) for ref_height in block.transactions_generator_ref_list: header_hash = self.height_to_hash(ref_height) ref_block = await self.get_full_block(header_hash) assert ref_block is not None if ref_block.transactions_generator is None: raise ValueError(Err.GENERATOR_REF_HAS_NO_GENERATOR) result.append(GeneratorArg(ref_block.height, ref_block.transactions_generator)) else: # First tries to find the blocks in additional_blocks reorg_chain: Dict[uint32, FullBlock] = {} curr: Union[FullBlock, UnfinishedBlock] = block additional_height_dict = {} while curr.prev_header_hash in additional_blocks: prev: FullBlock = additional_blocks[curr.prev_header_hash] additional_height_dict[prev.height] = prev if isinstance(curr, FullBlock): assert curr.height == prev.height + 1 reorg_chain[prev.height] = prev curr = prev peak: Optional[BlockRecord] = self.get_peak() if self.contains_block(curr.prev_header_hash) and peak is not None: # Then we look up blocks up to fork point one at a time, backtracking previous_block_hash = curr.prev_header_hash prev_block_record = await self.block_store.get_block_record(previous_block_hash) prev_block = await self.block_store.get_full_block(previous_block_hash) assert prev_block is not None assert prev_block_record is not None fork = find_fork_point_in_chain(self, peak, prev_block_record) curr_2: Optional[FullBlock] = prev_block assert curr_2 is not None and isinstance(curr_2, FullBlock) reorg_chain[curr_2.height] = curr_2 while curr_2.height > fork and curr_2.height > 0: curr_2 = await self.block_store.get_full_block(curr_2.prev_header_hash) assert curr_2 is not None reorg_chain[curr_2.height] = curr_2 for ref_height in block.transactions_generator_ref_list: if ref_height in reorg_chain: ref_block = reorg_chain[ref_height] assert ref_block is not None if ref_block.transactions_generator is None: raise ValueError(Err.GENERATOR_REF_HAS_NO_GENERATOR) result.append(GeneratorArg(ref_block.height, ref_block.transactions_generator)) else: if ref_height in additional_height_dict: ref_block = additional_height_dict[ref_height] else: header_hash = self.height_to_hash(ref_height) ref_block = await self.get_full_block(header_hash) assert ref_block is not None if ref_block.transactions_generator is None: raise ValueError(Err.GENERATOR_REF_HAS_NO_GENERATOR) result.append(GeneratorArg(ref_block.height, ref_block.transactions_generator)) assert len(result) == len(ref_list) return BlockGenerator(block.transactions_generator, result)