Exemple #1
0
 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
Exemple #2
0
 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)
Exemple #3
0
 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)
Exemple #4
0
 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))
Exemple #5
0
    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)
Exemple #6
0
    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)
Exemple #7
0
    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...')
Exemple #8
0
    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)
Exemple #9
0
    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})
Exemple #10
0
    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})
Exemple #11
0
    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({})