def build_new_block(self): """Builds a new candidate block and propagate it to the network We input in our model the block size limit, and also extrapolate the probability distribution for the number of transactions per block, based on measurements from the public network (https://www.blockchain.com/charts/n-transactions-per-block?timespan=2years). If the block size limit is 1 MB, as we know in Bitcoin, we take from the probability distribution the number of transactions, but if the user choose to simulate an environment with a 2 MB block, we multiply by two the number of transactions. With this we can see the performance in different block size limits.""" if self.is_mining is False: raise RuntimeError(f'Node {self.location} is not a miner') block_size = self.env.config['bitcoin']['block_size_limit_mb'] transactions_per_block_dist = self.env.config['bitcoin'][ 'number_transactions_per_block'] transactions_per_block = int( get_random_values(transactions_per_block_dist)[0]) pending_txs = [] for i in range(transactions_per_block * block_size): if self.transaction_queue.is_empty(): break pending_tx = self.transaction_queue.get() pending_txs.append(pending_tx) candidate_block = self._build_candidate_block(pending_txs) print( f'{self.address} at {time(self.env)}: New candidate block #{candidate_block.header.number} created {candidate_block.header.hash[:8]} with difficulty {candidate_block.header.difficulty}' ) # Add the candidate block to the chain of the miner node self.chain.add_block(candidate_block) # We need to broadcast the new candidate block across the network self.broadcast_new_blocks([candidate_block])
def verify_block(self, header, block_txs, verificationMode): if verificationMode == "WithMerkle": count = math.log(len(block_txs), 2) else: count = block_txs delay = round( get_random_values(self.env.delays['block_verification'])[0], 4) return count * delay
def start_heartbeat(self): """ The "heartbeat" frequency of any blockchain network based on PoW is time difference between blocks. With this function we simulate the network heartbeat frequency. During all the simulation, between time intervals (corresponding to the time between blocks) its chosen 1 or 2 nodes to broadcast a candidate block. We choose 2 nodes, when we want to simulate an orphan block situation. A fork due to orphan blocks occurs when there are two equally or nearly equally valid candidates for the next block of data in the blockchain. This event can occur when the two blocks are found close in time, and are submitted to the network at different “ends” Each node has a corresponding hashrate. The greater the hashrate, the greater the probability of the node being chosen. """ self._init_lists() while True: time_between_blocks = round( get_random_values( self.env.delays['time_between_blocks_seconds'])[0], 2) yield self.env.timeout(time_between_blocks) orphan_blocks_probability = self.env.config[ self.blockchain]['orphan_blocks_probability'] simulate_orphan_blocks = scipy.random.choice( [True, False], 1, p=[orphan_blocks_probability, 1 - orphan_blocks_probability])[0] if simulate_orphan_blocks: selected_nodes = scipy.random.choice( self._list_nodes, 2, replace=False, p=self._list_probabilities) for selected_node in selected_nodes: self._build_new_block(selected_node) else: selected_node = scipy.random.choice( self._list_nodes, 1, replace=False, p=self._list_probabilities)[0] self._build_new_block(selected_node)
def validate_transaction(self, tx=None): """ Simulates the transaction validation. For now, it only calculates a delay in simulation, corresponding to previous measurements""" delay = round( get_random_values(self.env.delays['tx_validation'])[0], 4) return delay
def validate_block(self, block=None): """ Simulates the block validation. For now, it only applies a delay in simulation, corresponding to previous measurements""" delay = round( get_random_values(self.env.delays['block_validation'])[0], 4) return delay