def receive_mined_block(block_str: str): global global_best_block, global_blockchain try: block: Block = Block.fromJSON(json.loads(block_str)) add_to_blockchain(block) return {'success': True} except Exception as e: return {'error': str(e)}
def sync_with_nodes(): ''' Syncs blocks with node ''' global global_nodes # Init connection for node in global_nodes: try: misocoin_cli('init_connection', [global_host, global_port], **node) except: pass # Checks every 15 seconds while True: # Checks with nodes, syncs with the one with # the longest chain longest_node = None best_height = len(global_blockchain) for node in global_nodes: # If node['host'] is in black list then continue if node['host'] in global_blacklisted_nodes: continue try: node_best_length = misocoin_cli('get_info', [], **node)['height'] if node_best_length > best_height: longest_node = node best_height = node_best_length except: pass # Syncs with that node if longest_node is not None: latest_block_dict: Dict = misocoin_cli('get_block', [best_height], **longest_node) latest_block: Block = Block.fromJSON(latest_block_dict) # Append to latest blockchain add_to_blockchain(latest_block) time.sleep(10)
def add_to_blockchain(block: Block): """ Helper function to update the blockchain. Also updates the utxo cache and tx cache """ global global_best_block, global_txs, global_utxos, global_difficulty # If we don't have the prev block, get it from our nodes if (block.height - 1) not in global_blockchain: for node in global_nodes: try: missing_block_dict: Dict = misocoin_cli( 'get_block', [block.height - 1], **node) missing_block: Block = Block.fromJSON(missing_block_dict) add_to_blockchain(missing_block) break except: pass # Check block hashes if len(global_blockchain) > 0: # Check hashes if block.prev_block_hash != global_blockchain[block.height - 1].block_hash: raise Exception('Block previous hash doesn\'t match') if not block.mined: raise Exception('Block hasn\'t been mined') # Add block to node if block.height not in global_blockchain: global_blockchain[block.height] = block # Add coinbase to cache if block.coinbase.txid not in global_txs: global_txs[block.coinbase.txid] = block.coinbase if block.coinbase.txid not in global_utxos: global_utxos[block.coinbase.txid] = {} global_utxos[block.coinbase.txid][0] = { 'address': block.coinbase.reward_address, 'amount': block.coinbase.reward_amount, 'spent': None } # Add tx for tx in block.transactions: if tx.txid not in global_txs: # Update utxos global_best_block, global_txs, global_utxos = mutils.add_tx_to_block( tx, global_best_block, global_txs, global_utxos) # Only ammend global_best_block if the block.height # is higher if (global_best_block.height < block.height + 1): global_best_block = Block(prev_block_hash=block.block_hash, transactions=[], height=block.height + 1, timestamp=int(time.time()), difficulty=global_difficulty, nonce=0) # Broadcast block for node in global_nodes: try: misocoin_cli('receive_mined_block', [json.dumps(block.toJSON())], **node) except: pass # Auto adjust difficulty ever 10 blocks # Should be around 300 seconds after 10 blocks last_ten_blocks = [] for i in range(max(1, global_best_block.height - 10), global_best_block.height - 1): if i in global_blockchain: last_ten_blocks.append(global_blockchain[i]) if (len(global_blockchain) % 10 == 0): lowest_timestamp = reduce(lambda x, y: min(x, y.timestamp), last_ten_blocks, int(time.time())) highest_timestamp = reduce(lambda x, y: max(x, y.timestamp), last_ten_blocks, genesis_epoch) if (highest_timestamp - lowest_timestamp < 300): global_difficulty = min(global_difficulty + 1, 64) if (highest_timestamp - lowest_timestamp > 300): global_difficulty = max(global_difficulty - 1, 1) print( '[UPDATE] Difficulty adjusted to {}'.format(global_difficulty)) print('[INFO] Received mined block {}'.format(block.height))
# Tx is a dict of all transactions # that ever took place global_txs = {} # blockchain global_blockchain = {} # blacklisted nodes global_blacklisted_nodes = {} # Genesis block genesis_epoch = 1512254915 genesis_block = Block( prev_block_hash= '0000000000000000000000000000000000000000000000000000000000000000', transactions=[], height=1, timestamp=genesis_epoch, difficulty=1, nonce=0) # At init best block will the the genesis_block global_best_block = genesis_block # For now we'll just fix their address and private key account_address = '461ec74a3ce3ea96267c1b7d043b35004a7058f1' account_priv_key = '60c8cb60c21143fffdd682f399ef3baa4b67c56a1f83a274284cfe7c57e007ed' def add_to_blockchain(block: Block): """ Helper function to update the blockchain.