def get_previous_consensus_block_from_local(self, block, peer): #table cleanup new_block = Mongo.db.consensus.find_one({ 'block.hash': block.prev_hash, 'block.index': (block.index - 1), 'block.version': BU.get_version_for_height((block.index - 1)) }) if new_block: new_block = Block.from_dict(new_block['block']) if int(new_block.version) == BU.get_version_for_height( new_block.index): return new_block else: return None return None
def get_consensus_blocks_by_index(self, index): return Mongo.db.consensus.find( { 'index': index, 'block.prevHash': { '$ne': '' }, 'block.version': BU.get_version_for_height(index) }, {'_id': 0})
def get_previous_consensus_block_from_remote(self, block, peer): try: url = 'http://' + peer.to_string( ) + '/get-block?hash=' + block.prev_hash print 'getting block', url res = requests.get(url, timeout=3) print 'response code: ', res.status_code new_block = Block.from_dict(json.loads(res.content)) if int(new_block.version) == BU.get_version_for_height( new_block.index): return new_block else: return None except: return None
def on_newblock(self, data): #print("new block ", data) config = app.config['yada_config'] mongo = app.config['yada_mongo'] try: peer = Peer.from_string(config, mongo, request.json.get('peer')) block = Block.from_dict(config, mongo, data) if block.index == 0: return if int(block.version) != BU.get_version_for_height(block.index): print 'rejected old version %s from %s' % (block.version, peer) return mongo.db.consensus.update( { 'index': block.to_dict().get('index'), 'id': block.to_dict().get('id'), 'peer': peer.to_string() }, { 'block': block.to_dict(), 'index': block.to_dict().get('index'), 'id': block.to_dict().get('id'), 'peer': peer.to_string() }, upsert=True) except Exception as e: print "block is bad" raise e except BaseException as e: print "block is bad" raise e try: if 'regnet' not in config.network: requests.post('https://yadacoin.io/peers', json.dumps({ 'host': config.peer_host, 'port': config.peer_port }), headers={"Content-Type": "application/json"}) except: print 'ERROR: failed to get peers, exiting...'
def sync(self): #top down syncing self.latest_block = Block.from_dict(BU.get_latest_block()) self.remove_pending_transactions_now_in_chain() latest_consensus = self.get_latest_consensus_block() if latest_consensus: print latest_consensus.index, "latest consensus_block" # check for difference between blockchain and consensus table heights if self.latest_block.index == latest_consensus.index: self.log('up to date, height: ' + str(latest_consensus.index)) return records = Mongo.db.consensus.find({ 'index': latest_consensus.index, 'block.version': BU.get_version_for_height(latest_consensus.index) }) for record in sorted(records, key=lambda x: int(x['block']['target'], 16)): block = Block.from_dict(record['block']) peer = Peer.from_string(record['peer']) print self.latest_block.hash, block.prev_hash, self.latest_block.index, ( block.index - 1) try: self.integrate_block_with_existing_chain( block, peer, self.existing_blockchain) except AboveTargetException as e: pass except ForkException as e: self.retrace(block, peer) except IndexError as e: self.retrace(block, peer) else: self.log('no consensus data... none.') return
def node(nonces=None, config=None): Config.from_dict(json.loads(config)) Peers.init() latest_block_index = Value('i', 0) my_peer = Config.peer_host + ":" + str(Config.peer_port) Config.max_duration = 300000 Config.block_version = 1 #p = Process(target=new_block_checker, args=(latest_block_index,)) status = Array('c', 'asldkjf') #p.start() Mongo.init() # default run state will be to mine some blocks! block = BU.get_latest_block() if block: latest_block_index.value = block.get('index') + 1 else: genesis_block = BlockFactory.get_genesis_block() genesis_block.save() Mongo.db.consensus.insert({ 'block': genesis_block.to_dict(), 'peer': 'me', 'id': genesis_block.signature, 'index': 0 }) block = BU.get_latest_block() latest_block_index.value = block.get('index') dup_test = Mongo.db.consensus.find({ 'peer': 'me', 'index': latest_block_index.value, 'block.version': BU.get_version_for_height(latest_block_index.value + 1) }).sort([('index', -1)]) if dup_test.count(): #print 'returning', latest_block_index.value + 1, BU.get_version_for_height(latest_block_index.value + 1) return transactions = Mongo.db.miner_transactions.find() transaction_objs = [] unspent_indexed = {} for txn in transactions: try: transaction = Transaction.from_dict(txn) transaction.verify() #check double spend address = str( P2PKHBitcoinAddress.from_pubkey( transaction.public_key.decode('hex'))) if address in unspent_indexed: unspent_ids = unspent_indexed[address] else: needed_value = sum( [float(x.value) for x in transaction.outputs]) + float(transaction.fee) res = BU.get_wallet_unspent_transactions( address, needed_value=needed_value) unspent_ids = [x['id'] for x in res] unspent_indexed[address] = unspent_ids failed1 = False failed2 = False used_ids_in_this_txn = [] for x in transaction.inputs: if x.id not in unspent_ids: failed1 = True if x.id in used_ids_in_this_txn: failed2 = True used_ids_in_this_txn.append(x.id) if failed1: Mongo.db.miner_transactions.remove( {'id': transaction.transaction_signature}) print 'transaction removed: input presumably spent already, not in unspent outputs', transaction.transaction_signature Mongo.db.failed_transactions.insert({ 'reason': 'input presumably spent already', 'txn': transaction.to_dict() }) elif failed2: Mongo.db.miner_transactions.remove( {'id': transaction.transaction_signature}) print 'transaction removed: using an input used by another transaction in this block', transaction.transaction_signature Mongo.db.failed_transactions.insert({ 'reason': 'using an input used by another transaction in this block', 'txn': transaction.to_dict() }) else: transaction_objs.append(transaction) except MissingInputTransactionException as e: #print 'missing this input transaction, will try again later' pass except InvalidTransactionSignatureException as e: print 'InvalidTransactionSignatureException: transaction removed' Mongo.db.miner_transactions.remove( {'id': transaction.transaction_signature}) Mongo.db.failed_transactions.insert({ 'reason': 'InvalidTransactionSignatureException', 'txn': transaction.to_dict() }) except InvalidTransactionException as e: print 'InvalidTransactionException: transaction removed' Mongo.db.miner_transactions.remove( {'id': transaction.transaction_signature}) Mongo.db.failed_transactions.insert({ 'reason': 'InvalidTransactionException', 'txn': transaction.to_dict() }) except Exception as e: #print e #print 'rejected transaction', txn['id'] pass except BaseException as e: #print e #print 'rejected transaction', txn['id'] pass try: block = BlockFactory.mine(transaction_objs, Config.public_key, Config.private_key, Config.max_duration, output, latest_block_index, status, nonces) except Exception as e: raise if block: dup_test = Mongo.db.consensus.find_one({ 'peer': 'me', 'index': block.index, 'block.version': BU.get_version_for_height(block.index) }) if not dup_test: print '\r\nCandidate submitted for index:', block.index print '\r\nTransactions:' for x in block.transactions: print x.transaction_signature Mongo.db.consensus.insert({ 'peer': 'me', 'index': block.index, 'id': block.signature, 'block': block.to_dict() }) print '\r\nSent block to:' for peer in Peers.peers: try: block_dict = block.to_dict() block_dict['peer'] = my_peer requests.post('http://{peer}/newblock'.format( peer=peer.host + ":" + str(peer.port)), json=block_dict, timeout=3, headers={'Connection': 'close'}) print peer.host + ":" + str(peer.port) except Exception as e: print e try: print 'reporting bad peer' requests.post('https://yadacoin.io/peers', json={ 'host': peer.host, 'port': str(peer.port), 'failed': True }, timeout=3, headers={'Connection': 'close'}) except: print 'failed to report bad peer' pass
def newblock(data): #print("new block ", data) try: peer = request.json.get('peer') incoming_block = Block.from_dict(data) if incoming_block.index == 0: return if int(incoming_block.version) != BU.get_version_for_height( incoming_block.index): print 'rejected old version %s from %s' % ( incoming_block.version, peer) return except Exception as e: print "block is bad" print e except BaseException as e: print "block is bad" print e try: dup_check = Mongo.db.consensus.find({ 'id': incoming_block.signature, 'peer': peer, 'block.version': BU.get_version_for_height(incoming_block.index) }) if dup_check.count(): return "dup" Mongo.db.consensus.update( { 'block': incoming_block.to_dict(), 'index': incoming_block.to_dict().get('index'), 'id': incoming_block.to_dict().get('id'), 'peer': peer }, { 'block': incoming_block.to_dict(), 'index': incoming_block.to_dict().get('index'), 'id': incoming_block.to_dict().get('id'), 'peer': peer }, upsert=True) # before inserting, we need to check it's chain # search consensus for prevHash of incoming block. #prev_blocks_check = Mongo.db.blocks.find({'hash': incoming_block.prev_hash}) #if prev_blocks_check.count(): # 1. if we have it, then insert it. # Mongo.db.consensus.insert({ # 'block': incoming_block.to_dict(), # 'index': incoming_block.to_dict().get('index'), # 'id': incoming_block.to_dict().get('id'), # 'peer': peer}) #else: # 2 scenarios # 1. the 3 is late to the game # 2. 1 and 2 do not find prev_hash from 3 and # we have a fork # the consensus has the previous block to the incoming block but it's not in the block chain # we need to do the chain compare routine here and decide if we're going with the blockchain # belongs to the incoming block, or stay with our existing one #retrace(incoming_block, db, peer) # return except Exception as e: print e except BaseException as e: print e
def get_latest_consensus_block(self): latests = self.get_latest_consensus_blocks() for latest in latests: if int(latest['block']['version']) == BU.get_version_for_height( latest['block']['index']): return Block.from_dict(latest['block'])
def get_latest_consensus_blocks(self): for x in Mongo.db.consensus.find({}, {'_id': 0}).sort([('index', -1)]): if BU.get_version_for_height(x['block']['index']) == int( x['block']['version']): yield x