def get_origin_relationship(self, rid=None, bulletin_secret=None): for inp in self.inputs: inp = inp.id while 1: txn = BU().get_transaction_by_id(inp, give_block=False, include_fastgraph=True) if txn: if 'rid' in txn and txn[ 'rid'] and 'dh_public_key' in txn and txn[ 'dh_public_key']: if rid and txn['rid'] != rid and txn.get( 'requester_rid') != rid and txn.get( 'requested_rid') != rid: return False return txn else: inp = txn['inputs'][0]['id'] else: txn = self.mongo.db.fastgraph_transactions.find_one( {'id': inp}) if txn and 'inputs' in txn['txn'] and txn['txn'][ 'inputs'] and 'id' in txn['txn']['inputs'][0]: inp = txn['txn']['inputs'][0]['id'] else: return False
async def on_newtransaction(self, sid, data): # TODO: generic test, is the peer known and has rights for this command? Decorator? if self.config.debug: self.app_log.info('WS newtransaction: {} {}'.format( sid, json.dumps(data))) try: incoming_txn = Transaction.from_dict( BU().get_latest_block()['index'], data) if incoming_txn.in_the_future(): # Most important raise ValueError('In the future {}'.format( incoming_txn.transaction_signature)) # print(incoming_txn.transaction_signature) dup_check_count = await get_config( ).mongo.async_db.miner_transactions.count_documents( {'id': incoming_txn.transaction_signature}) if dup_check_count: self.app_log.warning('found duplicate tx {}'.format( incoming_txn.transaction_signature)) raise Exception("duplicate tx {}".format( incoming_txn.transaction_signature)) await get_config().mongo.async_db.miner_transactions.insert_one( incoming_txn.to_dict()) tb = TxnBroadcaster(self.config) await tb.txn_broadcast_job(incoming_txn) except Exception as e: self.app_log.warning("Bad transaction: {}".format(e)) await self.force_close(sid)
async def get(self): """ :return: """ block = BU().get_latest_block() # Note: I'd rather use an extra field "time_human" or time_utc than having different formats for a same field name. block['time_utc'] = ts_to_utc(block['time']) self.render_as_json(block)
async def get(self): rid = self.request.args.get('rid') if rid: transactions = BU().get_transactions_by_rid( rid, self.config.bulletin_secret, rid=True, raw=True) else: transactions = [] self.render_as_json(list(transactions))
def run(cls, config, mongo): used_inputs = [] new_inputs = [] for x in mongo.site_db.faucet.find({'active': True}): balance = BU.get_wallet_balance(config, mongo, x['address']) if balance >= 25: mongo.site_db.faucet.update({'_id': x['_id']}, {'active': False, 'address': x['address']}) continue last_id_in_blockchain = x.get('last_id') if last_id_in_blockchain and not mongo.db.blocks.find({'transactions.id': last_id_in_blockchain}).count(): continue try: transaction = TransactionFactory( block_height=BU.get_latest_block(config, mongo)['index'], fee=0.01, public_key=config.public_key, private_key=config.private_key, outputs=[ Output(to=x['address'], value=5) ] ) except NotEnoughMoneyException as e: print("not enough money yet") return except Exception as e: print(e) try: transaction.transaction.verify() except: mongo.site_db.failed_faucet_transactions.insert(transaction.transaction.to_dict()) print('faucet transaction failed') TU.save(config, mongo, transaction.transaction) x['last_id'] = transaction.transaction.transaction_signature mongo.site_db.faucet.update({'_id': x['_id']}, x) print('saved. sending...', x['address']) for peer in Peers.peers: try: socketIO = SocketIO(peer.host, peer.port, wait_for_connection=False) chat_namespace = socketIO.define(ChatNamespace, '/chat') chat_namespace.emit('newtransaction', transaction.transaction.to_dict()) socketIO.disconnect() except Exception as e: print(e)
async def post(self): self.get_base_graph( ) # TODO: did this to set bulletin_secret, refactor this items = json.loads(self.request.body.decode('utf-8')) if not isinstance(items, list): items = [ items, ] else: items = [item for item in items] transactions = [] for txn in items: transaction = Transaction.from_dict( BU().get_latest_block()['index'], txn) try: transaction.verify() except InvalidTransactionException: await self.config.mongo.async_db.failed_transactions.insert_one( { 'exception': 'InvalidTransactionException', 'txn': txn }) print('InvalidTransactionException') return 'InvalidTransactionException', 400 except InvalidTransactionSignatureException: print('InvalidTransactionSignatureException') await self.config.mongo.async_db.failed_transactions.insert_one( { 'exception': 'InvalidTransactionSignatureException', 'txn': txn }) return 'InvalidTransactionSignatureException', 400 except MissingInputTransactionException: pass except: raise print('uknown error') return 'uknown error', 400 transactions.append(transaction) for x in transactions: await self.config.mongo.async_db.miner_transactions.insert_one( x.to_dict()) try: self.config.push_service.do_push(x.to_dict(), self.bulletin_secret, self.app_log) except Exception as e: print(e) print('do_push failed') txn_b = TxnBroadcaster(self.config) await txn_b.txn_broadcast_job(transaction) return self.render_as_json(items)
async def post(self): """ A peer does notify us of a new block. This is deprecated, since the new code uses events via websocket to notify of a new block. Still, can be used to force notification to important nodes, pools... """ from yadacoin.peers import Peer try: block_data = escape.json_decode(self.request.body) peer_string = block_data.get('peer') if block_data['index'] == 0: return if int(block_data['version']) != BU().get_version_for_height(block_data['index']): print('rejected old version %s from %s' % (block_data['version'], peer_string)) return # Dup code with websocket handler self.app_log.info('Post new block: {} {}'.format(peer_string, json.dumps(block_data))) # TODO: handle a dict here to store the consensus state if not self.peers.syncing: self.app_log.debug("Trying to sync on latest block from {}".format(peer_string)) my_index = self.config.BU.get_latest_block()['index'] # This is mostly to keep in sync with fast moving blocks from whitelisted peers and pools. # ignore if this does not fit. if block_data['index'] == my_index + 1: self.app_log.debug("Next index, trying to merge from {}".format(peer_string)) peer = Peer.from_string(peer_string) if await self.config.consensus.process_next_block(block_data, peer): pass # if ok, block was inserted and event triggered by import block # await self.peers.on_block_insert(data) elif block_data['index'] > my_index + 1: self.app_log.warning("Missing blocks between {} and {} , can't catch up from http route for {}" .format(my_index, block_data['index'], peer_string)) # data = {"start_index": my_index + 1, "end_index": my_index + 1 + CHAIN.MAX_BLOCKS_PER_MESSAGE} # await self.emit('get_blocks', data=data, room=sid) else: # Remove later on self.app_log.debug("Old or same index, ignoring {} from {}".format(block_data['index'], peer_string)) except: print('ERROR: failed to get peers, exiting...')
async def get(self): graph = self.get_base_graph() config = self.config address = self.get_query_argument('address') bulletin_secret = self.get_query_argument('bulletin_secret').replace( ' ', "+") amount_needed = self.get_query_argument('amount_needed', None) if amount_needed: amount_needed = int(amount_needed) rid = TU.generate_rid(config, bulletin_secret) unspent_transactions = [ x for x in BU().get_wallet_unspent_transactions(address) ] spent_txn_ids = [] for x in unspent_transactions: spent_txn_ids.extend([y['id'] for y in x['inputs']]) unspent_fastgraph_transactions = [ x for x in BU().get_wallet_unspent_fastgraph_transactions(address) if x['id'] not in spent_txn_ids ] spent_fastgraph_ids = [] for x in unspent_fastgraph_transactions: spent_fastgraph_ids.extend([y['id'] for y in x['inputs']]) regular_txns = [] txns_for_fastgraph = [] chain_balance = 0 fastgraph_balance = 0 for txn in unspent_transactions + unspent_fastgraph_transactions: if 'signatures' in txn and txn['signatures']: fastgraph = FastGraph.from_dict(0, txn) origin_fasttrack = fastgraph.get_origin_relationship(rid) if origin_fasttrack or (('rid' in txn and txn['rid'] == rid) or txn.get('requester_rid') == rid or txn.get('requested_rid') == rid): txns_for_fastgraph.append(txn) for output in txn['outputs']: if output['to'] == address: fastgraph_balance += int(output['value']) else: regular_txns.append(txn) for output in txn['outputs']: if output['to'] == address: chain_balance += int(output['value']) elif 'dh_public_key' in txn and txn['dh_public_key'] and ( ('rid' in txn and txn['rid'] == rid) or txn.get('requester_rid') == rid or txn.get('requested_rid') == rid): txns_for_fastgraph.append(txn) for output in txn['outputs']: if output['to'] == address: fastgraph_balance += int(output['value']) else: regular_txns.append(txn) for output in txn['outputs']: if output['to'] == address: chain_balance += int(output['value']) wallet = { 'chain_balance': chain_balance, 'fastgraph_balance': fastgraph_balance, 'balance': fastgraph_balance + chain_balance, 'unspent_transactions': regular_txns, 'txns_for_fastgraph': txns_for_fastgraph } self.render_as_json(wallet, indent=4)
async def post(self): config = self.config mongo = self.config.mongo body = json.loads(self.request.body.decode('utf-8')) try: fg = FastGraph.from_dict(0, body.get('txn'), raw=True) fg.verify() except: raise return 'invalid transaction', 400 res = mongo.db.signed_transactions.find_one({'hash': body.get('hash')}) if res: return 'no', 400 try: rid = TU.generate_rid(config, body.get('bulletin_secret')) my_entry_for_relationship = GU().get_transaction_by_rid( rid, config.wif, rid=True, my=True, public_key=config.public_key) their_entry_for_relationship = GU().get_transaction_by_rid( rid, rid=True, raw=True, theirs=True, public_key=config.public_key) verified = verify_signature( base64.b64decode(body.get('bulletin_secret')), my_entry_for_relationship['relationship'] ['their_username'].encode(), bytes.fromhex(their_entry_for_relationship['public_key'])) if not verified: return 'no', 400 verified = verify_signature( base64.b64decode(body.get('id')), body.get('hash').encode('utf-8'), bytes.fromhex(their_entry_for_relationship['public_key'])) address = str( P2PKHBitcoinAddress.from_pubkey( bytes.fromhex(their_entry_for_relationship['public_key']))) found = False for x in BU().get_wallet_unspent_transactions( address, [body.get('input')]): if body.get('input') == x['id']: found = True if not found: for x in BU().get_wallet_unspent_fastgraph_transactions( address): if body.get('input') == x['id']: found = True if found: signature = mongo.db.signed_transactions.find_one({ 'input': body.get('input'), 'txn.public_key': body['txn']['public_key'] }) if signature: already_spent = mongo.db.fastgraph_transactions.find_one({ 'txn.inputs.id': body['input'], 'txn.public_key': body['txn']['public_key'] }) if already_spent: self.set_status(400) self.write('already spent!') self.finish() return True else: signature['txn']['signatures'] = [ signature['signature'] ] fastgraph = FastGraph.from_dict(0, signature['txn']) try: fastgraph.verify() except Exception as e: raise return 'did not verify', 400 result = mongo.db.fastgraph_transactions.find_one( {'txn.hash': fastgraph.hash}) if result: return 'duplicate transaction found', 400 spent_check = mongo.db.fastgraph_transactions.find_one( { 'txn.inputs.id': { '$in': [x.id for x in fastgraph.inputs] } }) if spent_check: return 'already spent input', 400 fastgraph.save() else: return 'no transactions with this input found', 400 if verified: transaction_signature = TU.generate_signature_with_private_key( config.private_key, body.get('hash')) signature = { 'signature': transaction_signature, 'hash': body.get('hash'), 'bulletin_secret': body.get('bulletin_secret'), 'input': body.get('input'), 'id': body.get('id'), 'txn': body.get('txn') } mongo.db.signed_transactions.insert(signature) if '_id' in signature: del signature['_id'] self.render_as_json(signature, indent=4) else: return 'no', 400 except Exception as e: raise self.render_as_json({'status': 'error', 'msg': e})
async def post(self): config = self.config mongo = self.config.mongo kwargs = json.loads(self.request.body.decode('utf-8')) bulletin_secret = kwargs.get('bulletin_secret', '') username = kwargs.get('username', '') to = kwargs.get('to', '') if not bulletin_secret: return 'error: "bulletin_secret" missing', 400 if not username: return 'error: "username" missing', 400 if not to: return 'error: "to" missing', 400 rid = TU.generate_rid(config, bulletin_secret) dup = mongo.db.blocks.find({'transactions.rid': rid}) if dup.count(): found_a = False found_b = False for txn in dup: if txn['public_key'] == config.public_key: found_a = True if txn['public_key'] != config.public_key: found_b = True if found_a and found_b: return json.dumps({ "success": False, "status": "Already added" }) miner_transactions = mongo.db.miner_transactions.find() mtxn_ids = [] for mtxn in miner_transactions: for mtxninput in mtxn['inputs']: mtxn_ids.append(mtxninput['id']) checked_out_txn_ids = mongo.db.checked_out_txn_ids.find() for mtxn in checked_out_txn_ids: mtxn_ids.append(mtxn['id']) a = os.urandom(32).decode('latin1') dh_public_key = scalarmult_base(a).encode('latin1').hex() dh_private_key = a.encode('latin1').hex() transaction = TransactionFactory( block_height=BU().get_latest_block()['index'], bulletin_secret=bulletin_secret, username=username, fee=0.00, public_key=config.public_key, dh_public_key=dh_public_key, private_key=config.private_key, dh_private_key=dh_private_key, outputs=[{ 'to': to, 'value': 0 }]) mongo.db.miner_transactions.insert(transaction.transaction.to_dict()) """ # TODO: integrate new socket/peer framework for transmitting txns job = Process(target=TxnBroadcaster.txn_broadcast_job, args=(transaction.transaction,)) job.start() """ self.render_as_json({"success": True})
async def get(self): term = self.get_argument("term", False) if not term: self.render_as_json({}) return try: res = self.mongo.db.blocks.find({'index': int(term)}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'block_height', 'result': [changetime(x) for x in res] }) except: pass try: res = self.mongo.db.blocks.find({'public_key': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'block_height', 'result': [changetime(x) for x in res] }) except: pass try: res = self.mongo.db.blocks.find({'transactions.public_key': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'block_height', 'result': [changetime(x) for x in res] }) except: pass try: re.search(r'[A-Fa-f0-9]{64}', term).group(0) res = self.mongo.db.blocks.find({'hash': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'block_hash', 'result': [changetime(x) for x in res] }) except: pass try: base64.b64decode(term) res = self.mongo.db.blocks.find({'id': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'block_id', 'result': [changetime(x) for x in res] }) except: pass try: re.search(r'[A-Fa-f0-9]{64}', term).group(0) res = self.mongo.db.blocks.find({'transactions.hash': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'txn_hash', 'result': [changetime(x) for x in res] }) except: pass try: re.search(r'[A-Fa-f0-9]{64}', term).group(0) res = self.mongo.db.blocks.find({'transactions.rid': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'txn_rid', 'result': [changetime(x) for x in res] }) except: pass try: base64.b64decode(term) res = self.mongo.db.blocks.find({'transactions.id': term}, {'_id': 0}) if res.count(): return self.render_as_json({ 'resultType': 'txn_id', 'result': [changetime(x) for x in res] }) except: pass try: re.search(r'[A-Fa-f0-9]+', term).group(0) res = self.mongo.db.blocks.find({'transactions.outputs.to': term}, {'_id': 0}).sort('index', -1).limit(10) if res.count(): balance = BU().get_wallet_balance(term) return self.render_as_json({ 'balance': "{0:.8f}".format(balance), 'resultType': 'txn_outputs_to', 'result': [changetime(x) for x in res] }) except: return self.render_as_json({}) return self.render_as_json({})