class RoundIter: def __init__(self, dag, block_hash, round_type): block_number = dag.get_block_number(block_hash) epoch_number = Epoch.get_epoch_number(block_number) round_start, round_end = Epoch.get_round_bounds( epoch_number, round_type) self.round_end = round_start self.chain_iter = ChainIter(dag, block_hash) while self.chain_iter.block_number > round_end + 1: self.chain_iter.next() def __iter__(self): return self def __next__(self): block = self.chain_iter.next() block_number = self.chain_iter.block_number if block_number < self.round_end: raise StopIteration() return block def current_block_number(self): return self.chain_iter.block_number def next(self): return self.__next__()
def flatten_with_merge(merger, from_hash, to_hash): flat_chain = [] chain_iter = ChainIter(merger.dag, from_hash) block = chain_iter.next() block_hash = block.get_hash() while block_hash != to_hash: if not block: flat_chain.append(None) else: flat_chain.append(block) if len(block.block.prev_hashes) > 1: merge_chain = merger.merge(block.block.prev_hashes) flat_chain += list(reversed(merge_chain)) chain_iter = ChainIter(merger.dag, merge_chain[0].get_hash()) chain_iter.next( ) # immediately transfer to next block because this one is already in chain block = chain_iter.next() if block: block_hash = block.get_hash() else: block_hash = None flat_chain.append(merger.dag.blocks_by_hash[to_hash]) return MergedChain(list(reversed(flat_chain)))
def get_top_chain_block_hashes(self, from_hash, to_hash): """ Method return list of logical block by block chain from hash to hash IN THE OPPOSITE DIRECTION (from current top to to_hash) :param from_hash: current top hash :param to_hash: any hash from chain :return: list of block hashes in logical sequences WITHOUT SKIPS """ flat_chain = [] chain_iter = ChainIter(self.dag, from_hash) block = chain_iter.next() block_hash = block.get_hash() while block_hash != to_hash: if block: flat_chain.append(block.get_hash()) block = chain_iter.next() if block: block_hash = block.get_hash() else: block_hash = None flat_chain.append(self.dag.blocks_by_hash[to_hash]) return list(reversed(flat_chain))
def test_iterator(self): dag = Dag(0) private = Private.generate() block1 = BlockFactory.create_block_with_timestamp( [dag.genesis_block().get_hash()], BLOCK_TIME) signed_block1 = BlockFactory.sign_block(block1, private) dag.add_signed_block(1, signed_block1) block2 = BlockFactory.create_block_with_timestamp([block1.get_hash()], BLOCK_TIME * 2) signed_block2 = BlockFactory.sign_block(block2, private) dag.add_signed_block(2, signed_block2) block3 = BlockFactory.create_block_with_timestamp([block2.get_hash()], BLOCK_TIME * 3) signed_block3 = BlockFactory.sign_block(block3, private) dag.add_signed_block(3, signed_block3) # alternative chain other_block2 = BlockFactory.create_block_with_timestamp( [block1.get_hash()], BLOCK_TIME * 2 + 1) other_signed_block2 = BlockFactory.sign_block(other_block2, private) dag.add_signed_block(2, other_signed_block2) # intentionally skipped block # alternative chain other_block4 = BlockFactory.create_block_with_timestamp( [other_block2.get_hash()], BLOCK_TIME * 3 + 1) other_signed_block4 = BlockFactory.sign_block(other_block4, private) dag.add_signed_block(4, other_signed_block4) chain_iter = ChainIter(dag, block3.get_hash()) self.assertEqual(chain_iter.next().block.get_hash(), block3.get_hash()) self.assertEqual(chain_iter.next().block.get_hash(), block2.get_hash()) self.assertEqual(chain_iter.next().block.get_hash(), block1.get_hash()) chain_iter = ChainIter(dag, other_block4.get_hash()) self.assertEqual(chain_iter.next().block.get_hash(), other_block4.get_hash()) self.assertEqual(chain_iter.next(), None) # detect intentionally skipped block self.assertEqual(chain_iter.next().block.get_hash(), other_block2.get_hash()) self.assertEqual(chain_iter.next().block.get_hash(), block1.get_hash())