def run(cls, config, mongo, to, value): Peers.init(config, mongo, config.network) try: transaction = TransactionFactory( block_height=config.BU.get_latest_block()['index'], fee=0.01, public_key=config.public_key, private_key=config.private_key, outputs=[ {'to': to, 'value': value} ] ) except NotEnoughMoneyException as e: print("not enough money yet") return except: raise try: transaction.transaction.verify() except: print('transaction failed') TU.save(config, mongo, transaction.transaction) print('Transaction generated successfully. Sending:', value, 'To:', to) for peer in Peers.peers: try: with SocketIO(peer.host, peer.port, ChatNamespace, wait_for_connection=False) as socketIO: chat_namespace = socketIO.define(ChatNamespace, '/chat') chat_namespace.emit('newtransaction', transaction.transaction.to_dict()) socketIO.disconnect() print('Sent to:', peer.host, peer.port) except Exception as e: print(e)
def from_dict(cls, config): from yadacoin.transactionutils import TU cls.seed = config.get('seed', '') cls.xprv = config.get('xprv', '') cls.username = config.get('username', '') cls.use_pnp = config.get('use_pnp', True) cls.ssl = config.get('ssl', True) cls.origin = config.get('origin', True) cls.polling = config.get('polling', -1) cls.network = config.get('network', 'mainnet') cls.public_key = config['public_key'] cls.address = str(P2PKHBitcoinAddress.from_pubkey(bytes.fromhex(cls.public_key))) cls.private_key = config['private_key'] cls.wif = cls.generate_wif(cls.private_key) cls.bulletin_secret = TU.generate_deterministic_signature(config, config['username'], config['private_key']) cls.mongodb_host = config['mongodb_host'] cls.database = config['database'] cls.site_database = config['site_database'] cls.web_server_host = config['web_server_host'] cls.web_server_port = config['web_server_port'] if config['peer_host'] == '0.0.0.0' or config['peer_host'] == 'localhost': raise Exception("cannot use localhost or 0.0.0.0, must specify public ipv4 address") if config['peer_host'] == '[my public ip]': raise Exception("please configure your peer_post to your public ipv4 address") cls.peer_host = config['peer_host'] cls.peer_port = config['peer_port'] cls.serve_host = config['serve_host'] cls.serve_port = config['serve_port'] cls.callbackurl = config['callbackurl'] cls.fcm_key = config['fcm_key']
def get_transaction_by_rid(self, selector, wif=None, bulletin_secret=None, rid=False, raw=False, theirs=False, my=False, public_key=None): # from block import Block # from transaction import Transaction from yadacoin.crypt import Crypt if not rid: ds = bulletin_secret selectors = [ TU.hash(ds + selector), TU.hash(selector + ds) ] else: if not isinstance(selector, list): selectors = [selector, ] else: selectors = selector def txn_gen(): res = self.mongo.db.blocks.find( {"transactions": {"$elemMatch": {"relationship": {"$ne": ""}, "rid": {"$in": selectors}}}}) for x in res: yield x res = self.mongo.db.fastgraph_transactions.find( {"txn": {"$elemMatch": {"relationship": {"$ne": ""}, "rid": {"$in": selectors}}}}) for x in res: yield x for block in txn_gen(): for transaction in block.get('transactions'): if theirs and public_key == transaction['public_key']: continue if my and public_key != transaction['public_key']: continue if not raw: try: cipher = Crypt(wif) decrypted = cipher.decrypt(transaction['relationship']) relationship = json.loads(decrypted.decode('latin1')) transaction['relationship'] = relationship except: continue if 'rid' in transaction and transaction['rid'] in selectors: return transaction
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)
def get_bulletin_secret(cls, private_key=None, username=''): from yadacoin.transactionutils import TU return TU.generate_deterministic_signature(username, private_key)
def inst_get_bulletin_secret(self): from yadacoin.transactionutils import TU return TU.generate_deterministic_signature(self, self.username, self.private_key)
def get_transactions_by_rid(self, selector, bulletin_secret, wif=None, rid=False, raw=False, returnheight=True, lt_block_height=None, requested_rid=False): # selectors is old code before we got an RID by sorting the bulletin secrets # from block import Block # from transaction import Transaction from yadacoin.crypt import Crypt if not rid: ds = bulletin_secret selectors = [ TU.hash(ds + selector), TU.hash(selector + ds) ] else: if not isinstance(selector, list): selectors = [selector, ] else: selectors = selector transactions_by_rid_cache = self.mongo.db.transactions_by_rid_cache.find( { 'raw': raw, 'rid': rid, 'bulletin_secret': bulletin_secret, 'returnheight': returnheight, 'selector': {'$in': selectors}, 'requested_rid': requested_rid } ).sort([('height', -1)]) latest_block = self.config.BU.get_latest_block() transactions = [] if lt_block_height: query = {"transactions.rid": {"$in": selectors}, "transactions": {"$elemMatch": {"relationship": {"$ne": ""}}}, 'index': {'$lte': lt_block_height}} if requested_rid: query["transactions.requested_rid"] = {"$in": selectors} blocks = self.mongo.db.blocks.find(query) else: if transactions_by_rid_cache.count(): transactions_by_rid_cache = transactions_by_rid_cache[0] block_height = transactions_by_rid_cache['height'] else: block_height = 0 query = {"transactions.rid": {"$in": selectors}, "transactions": {"$elemMatch": {"relationship": {"$ne": ""}}}, 'index': {'$gt': block_height}} if requested_rid: query = { "$or": [ { "transactions.rid": { "$in": selectors } }, { "transactions.requested_rid": { "$in": selectors } } ], "transactions": { "$elemMatch": { "relationship": { "$ne": "" } } }, 'index': { '$gt': block_height } } else: query = { "transactions.rid": { "$in": selectors }, "transactions": { "$elemMatch": { "relationship": { "$ne": "" } } }, 'index': { '$gt': block_height } } blocks = self.mongo.db.blocks.find(query) cipher = Crypt(self.config.wif) for block in blocks: for transaction in block.get('transactions'): if 'relationship' in transaction and transaction['relationship']: if returnheight: transaction['height'] = block['index'] if not raw: try: decrypted = cipher.decrypt(transaction['relationship']) relationship = json.loads(decrypted.decode('latin1')) transaction['relationship'] = relationship except: continue for selector in selectors: self.app_log.debug('caching transactions_by_rid at height: {}'.format(block['index'])) self.mongo.db.transactions_by_rid_cache.insert( { 'raw': raw, 'rid': rid, 'bulletin_secret': bulletin_secret, 'returnheight': returnheight, 'selector': selector, 'txn': transaction, 'height': block['index'], 'requested_rid': requested_rid } ) transactions.append(transaction) if not transactions: for selector in selectors: self.mongo.db.transactions_by_rid_cache.insert( { 'raw': raw, 'rid': rid, 'bulletin_secret': bulletin_secret, 'returnheight': returnheight, 'selector': selector, 'height': latest_block['index'], 'requested_rid': requested_rid } ) for ftxn in self.mongo.db.fastgraph_transactions.find({'txn.rid': {'$in': selectors}}): if 'txn' in ftxn: yield ftxn['txn'] last_id = '' for x in self.mongo.db.transactions_by_rid_cache.find({ 'raw': raw, 'rid': rid, 'returnheight': returnheight, 'selector': {'$in': selectors}, 'requested_rid': requested_rid }).sort([('txn.id', 1)]): if 'txn' in x and x['txn']['id'] != last_id: last_id = x['txn']['id'] yield x['txn']
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})
def generate_transaction_signature(self): return TU.generate_signature(self.hash, self.private_key)
def __init__( self, block_height, bulletin_secret='', username='', value=0, fee=0.0, requester_rid='', requested_rid='', public_key='', dh_public_key='', private_key='', dh_private_key='', to='', inputs='', outputs='', coinbase=False, chattext=None, signin=None, no_relationship=False ): self.config = get_config() self.mongo = self.config.mongo self.app_log = getLogger('tornado.application') self.block_height = block_height self.bulletin_secret = bulletin_secret self.username = username self.requester_rid = requester_rid self.requested_rid = requested_rid self.public_key = public_key self.dh_public_key = dh_public_key self.private_key = private_key self.value = value self.fee = float(fee) self.dh_private_key = dh_private_key self.to = to self.time = str(int(time.time())) self.outputs = [] self.no_relationship = no_relationship for x in outputs: self.outputs.append(Output.from_dict(x)) self.inputs = [] for x in inputs: if 'signature' in x and 'public_key' in x and 'address' in x: self.inputs.append(ExternalInput.from_dict(x)) else: self.inputs.append(Input.from_dict(x)) self.coinbase = coinbase self.chattext = chattext self.signin = signin self.do_money() inputs_concat = self.get_input_hashes() outputs_concat = self.get_output_hashes() if bulletin_secret: self.rid = self.generate_rid() if self.chattext: self.relationship = json.dumps({ "chatText": self.chattext }) self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt(self.relationship) elif self.signin: for shared_secret in TU.get_shared_secrets_by_rid(self.rid): self.relationship = SignIn(self.signin) self.cipher = Crypt(shared_secret.hex(), shared=True) self.encrypted_relationship = self.cipher.shared_encrypt(self.relationship.to_json()) break elif self.no_relationship: self.encrypted_relationship = '' else: if not self.dh_public_key or not self.dh_private_key: a = os.urandom(32).decode('latin1') self.dh_public_key = scalarmult_base(a).encode('latin1').hex() self.dh_private_key = a.encode().hex() self.relationship = self.generate_relationship() if not private_key: raise Exception('missing private key') self.cipher = Crypt(self.config.wif) self.encrypted_relationship = self.cipher.encrypt(self.relationship.to_json()) else: self.rid = '' self.encrypted_relationship = '' self.header = ( self.public_key + self.time + self.dh_public_key + self.rid + self.encrypted_relationship + "{0:.8f}".format(self.fee) + self.requester_rid + self.requested_rid + inputs_concat + outputs_concat ) self.hash = hashlib.sha256(self.header.encode('utf-8')).digest().hex() if self.private_key: self.transaction_signature = TU.generate_signature_with_private_key(private_key, self.hash) else: self.transaction_signature = '' self.transaction = self.generate_transaction()