def random_block_generator(genesis, initial_leaf_number, block_number): """ Randomly generates blocks according to the given parameters. """ max_initial_leaf_number = initial_leaf_number max_block_number = block_number all_blocks = set() all_blocks.add(hash(genesis)) leaves = set() block_counter = 1 yield genesis while block_counter <= max_block_number: if block_counter <= max_initial_leaf_number + 1: parents = {hash(genesis)} else: parents = frozenset( sample(leaves, randint(1, max(1, round(len(leaves) / 5))))) cur_block = Block(block_counter, parents) leaves -= cur_block.get_parents() leaves.add(hash(cur_block)) all_blocks.add(hash(cur_block)) block_counter += 1 yield cur_block
def add(self, block: Block, is_malicious: bool = False): super().add(block) global_id = hash(block) if is_malicious: self._malicious_blocks_to_add_to_honest_dag.append(global_id) if self.did_attack_fail(): self._first_parallel_block_gid = global_id # The malicious attack generates a chain, so the new tip is the current block self._competing_chain_tip_gid = global_id self._competing_chain_tip_antipast -= self._G.node[global_id][self._BLUE_DIFF_PAST_ORDER_KEY].keys() self._competing_chain_tip_antipast -= self._G.node[global_id][self._RED_DIFF_PAST_ORDER_KEY].keys() # Because we are under the assumption that a selfish miner has zero network latency and the # simulation design, the assumption is that no new blocks are mined between the moment a new # selfish block is mined and the moment it is added to the DAG self._virtual_competing_chain_block_parents = \ self._get_competing_chain_tip_parents(global_id, self._competing_chain_tip_antipast, block.get_parents()) else: # Add malicious blocks to the honest DAG as soon as possible if self.did_attack_fail(): self._add_malicious_blocks_to_honest_dag() # This is possible because this is a competing chain attack, # where the honest chain doesn't include any malicious blocks self._honest_dag.add(block) if self.did_attack_succeed(): self._add_malicious_blocks_to_honest_dag() if not self.did_attack_fail(): # need to update the data structure only if in the middle of a (seemingly) successful attack self._competing_chain_tip_antipast.add(global_id) if global_id == self._competing_chain_tip_gid or \ self._is_a_bluer_than_b(self._competing_chain_tip_gid, global_id): self._virtual_competing_chain_block_parents -= block.get_parents() self._virtual_competing_chain_block_parents.add(global_id) elif not self._is_attack_viable(): self._stop_attack()
def add(self, block: Block): global_id = hash(block) parents = block.get_parents() # add the block to the phantom self._G.add_node(global_id) self._G.node[global_id][self._BLOCK_DATA_KEY] = block for parent in parents: self._G.add_edge(global_id, parent) # update the leaves self._leaves -= parents self._leaves.add(global_id) # update the coloring of the graph and everything related (the blue anticones and the topological order too) self._update_coloring_incrementally(global_id) self._update_topological_order_incrementally(global_id)