Beispiel #1
0
async def get_outpoints_info(request):
    log = request.app["log"]
    log.info("POST %s" % str(request.rel_url))
    addresses = dict()
    status = 500
    response = {
        "error_code": INTERNAL_SERVER_ERROR,
        "message": "internal server error",
        "details": ""
    }

    try:
        try:
            await request.post()
            data = await request.json()
            outpoints = []
            if len(data) > 100:
                raise APIException(PARAMETER_ERROR,
                                   "only 100 outpoints allowed")
            """
            connector_utxo
            connector_unconfirmed_utxo
            connector_unconfirmed_stxo
            
            """
            for outpoint in data:
                try:
                    o, a = outpoint.split(":")
                    tx_id = s2rh(o)
                    if len(tx_id) != 32:
                        raise Exception()
                    outpoints.append((tx_id, int(a), b"".join(
                        (tx_id, int_to_bytes(int(a))))))
                except:
                    raise APIException(PARAMETER_ERROR,
                                       "invalid outpoint %s" % outpoint)

        except:
            raise APIException(JSON_DECODE_ERROR, "invalid outpoints list")

        response = await outpoints_info(outpoints, request.app)

        status = 200
    except APIException as err:
        status = err.status
        response = {
            "error_code": err.err_code,
            "message": err.message,
            "details": err.details
        }
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status=status)
Beispiel #2
0
async def get_block_transactions_list(request):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))
    status = 500
    response = {"error_code": INTERNAL_SERVER_ERROR,
                "message": "internal server error",
                "details": ""}
    parameters = request.rel_url.query
    try:
        try:
            limit = int(parameters["limit"])
            if not (limit > 0 and limit <= request.app["get_block_tx_page_limit"]):
                raise Exception()
        except:
            limit = request.app["get_block_tx_page_limit"]

        try:
            page = int(parameters["page"])
            if page <= 0:
                raise Exception()
        except:
            page = 1

        try:
            order = "asc" if parameters["order"] == "asc" else "desc"
        except:
            order = "asc"

        pointer = request.match_info['block_pointer']
        if len(pointer) < 12:
            try:
                pointer = int(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
        elif len(pointer) == 64:
            try:
                pointer = s2rh(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
        else:
            raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")

        response = await block_transaction_id_list(pointer, limit, page, order, request.app)

        status = 200
    except APIException as err:
        status = err.status
        response = {"error_code": err.err_code,
                    "message": err.message,
                    "details": err.details}
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status = status)
Beispiel #3
0
async def get_block_headers(request):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))

    status = 500
    response = {
        "error_code": INTERNAL_SERVER_ERROR,
        "message": "internal server error",
        "details": ""
    }
    try:
        pointer = request.match_info['block_pointer']
        if len(pointer) < 12:
            try:
                pointer = int(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER,
                                   "invalid block pointer")
        elif len(pointer) == 64:
            try:
                pointer = s2rh(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER,
                                   "invalid block pointer")
        else:
            raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")

        try:
            count = request.match_info['count']
        except:
            count = 2000
        try:
            count = int(count)
            if count < 1 and count > 2000:
                count = 2000
        except:
            raise APIException(PARAMETER_ERROR, "invalid count parameter")

        response = await block_headers(pointer, count, request.app)
        status = 200
    except APIException as err:
        status = err.status
        response = {
            "error_code": err.err_code,
            "message": err.message,
            "details": err.details
        }
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status=status)
Beispiel #4
0
async def get_transaction_by_pointer(request):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))
    pointer = request.match_info['tx_pointer']

    status = 500
    response = {"error_code": INTERNAL_SERVER_ERROR,
                "message": "internal server error",
                "details": ""}

    option_raw_tx = False
    try:
        if request.rel_url.query['raw_tx'] in ('True','1'):
            option_raw_tx = True
    except:
        pass

    try:
        if len(pointer) == 64:
            try:
                pointer = s2rh(pointer)
            except:
                raise APIException(PARAMETER_ERROR, "invalid transaction hash")
        else:
            try:
                k = pointer.split(":")
                b = int(k[0])
                t = int(k[1])
                if b < 0: raise Exception()
                if t < 0: raise Exception()
                pointer = (b << 39) + (t << 20)
            except:
                raise APIException(PARAMETER_ERROR, "invalid transaction pointer")

        response = await tx_by_pointer_opt_tx(pointer, option_raw_tx, request.app)
        status = 200
    except APIException as err:
        status = err.status
        response = {"error_code": err.err_code,
                    "message": err.message,
                    "details": err.details
                    }
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status = status)
Beispiel #5
0
async def get_block_data_by_pointer(request, pointer=None):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))

    status = 500
    response = {"error_code": INTERNAL_SERVER_ERROR,
                "message": "internal server error",
                "details": ""}

    parameters = request.rel_url.query

    try:
        if parameters["statistics"] in ('1', 'True'):
            stat = True
        else:
            stat = False
    except:
        stat = False

    try:
        if pointer is None:
            pointer = request.match_info['block_pointer']
            if len(pointer) < 12:
                try:
                    pointer = int(pointer)
                except:
                    raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
            elif len(pointer) == 64:
                try:
                    pointer = s2rh(pointer)
                except:
                    raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
            else:
                raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
        response = await block_data_by_pointer(pointer, stat, request.app)
        status = 200
    except APIException as err:
        status = err.status
        response = {"error_code": err.err_code,
                    "message": err.message,
                    "details": err.details}
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status = status)
async def get_block_filters_batch_headers(request):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))

    status = 500
    response = {
        "error_code": INTERNAL_SERVER_ERROR,
        "message": "internal server error",
        "details": ""
    }
    filter_type = int(request.match_info['filter_type'])
    start_height = int(request.match_info['start_height'])
    stop_hash = request.match_info['stop_hash']

    try:
        try:
            stop_hash = s2rh(stop_hash)
            if len(stop_hash) != 32:
                raise Exception()
        except:
            raise APIException(INVALID_BLOCK_POINTER, "invalid stop hash")

        if filter_type < 1:
            raise APIException(PARAMETER_ERROR, "invalid filter_type")

        if start_height < 0:
            raise APIException(PARAMETER_ERROR, "invalid start_height")

        response = await block_filters_batch_headers(filter_type, start_height,
                                                     stop_hash, log,
                                                     request.app)
        status = 200
    except APIException as err:
        status = err.status
        response = {
            "error_code": err.err_code,
            "message": err.message,
            "details": err.details
        }
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status=status)
Beispiel #7
0
    async def _new_block(self, block):
        self.block_dependency_tx = 0
        """
        0 Check if block already exist in db
        1 Check parent block in db:
            If no parent
                get last block height from db
                   if last block height >= recent block height 
                       this is orphan ignore it
                   else:
                       remove top block from db and ask block with
                       hrecent block height -1
                       return
        2 add all transactions from block to db
            ask full block from node
            parse txs and add to db in case not exist
        3 call before add block handler^ if this handler rise 
          exception block adding filed
        4 add block to db and commit
        5 after block add handelr 
        6 ask next block
        """
        if not self.active or not self.active_block.done():
            return
        if block is None:
            self.sync = False
            self.log.debug('Block synchronization completed')
            return
        self.active_block = asyncio.Future()

        binary_block_hash = unhexlify(block["hash"])
        binary_previousblock_hash = \
            unhexlify(block["previousblockhash"]) \
            if "previousblockhash" in block else None
        block_height = int(block["height"])
        next_block_height = block_height + 1
        self.log.info("New block %s %s" % (block_height, block["hash"]))
        bt = q = tm()
        try:
            async with self._db_pool.acquire() as con:
                # blockchain position check
                block_exist = self.block_cache.get(binary_block_hash)
                if block_exist is not None:
                    self.log.info("block already exist in db %s" %
                                  block["hash"])
                    return
                # Get parent from db
                if binary_previousblock_hash is not None:
                    parent_height = self.block_cache.get(
                        binary_previousblock_hash)
                else:
                    parent_height = None
                # self.log.warning("parent height %s" % parent_height)

                if parent_height is None:
                    # have no mount point in local chain
                    # self.log.warning("last local height %s" % self.last_block_height)
                    if self.last_block_height is not None:
                        if self.last_block_height >= block_height:
                            self.log.critical(
                                "bitcoin node out of sync block %s" %
                                block["hash"])
                            return
                        if self.last_block_height + 1 == block_height:
                            if self.orphan_handler:
                                tq = tm()
                                await self.orphan_handler(
                                    self.last_block_height, con)
                                self.log.info("orphan handler  %s [%s]" %
                                              (self.last_block_height, tm(tq)))
                            tq = tm()
                            await remove_orphan(self, con)
                            self.log.info("remove orphan %s [%s]" %
                                          (self.last_block_height + 1, tm(tq)))
                        next_block_height -= 2
                        if next_block_height > self.last_block_height:
                            next_block_height = self.last_block_height + 1
                        if self.sync and next_block_height >= self.sync:
                            if self.sync_requested:
                                next_block_height = self.last_block_height + 1
                        else:
                            self.sync = next_block_height
                        return
                    else:
                        if self.start_block is not None and block[
                                "height"] != self.start_block:
                            self.log.info("Start from block %s" %
                                          self.start_block)
                            next_block_height = self.start_block
                            return
                else:
                    if self.last_block_height + 1 != block_height:
                        if self.orphan_handler:
                            tq = tm()
                            await self.orphan_handler(self.last_block_height,
                                                      con)
                            self.log.info("orphan handler  %s [%s]" %
                                          (self.last_block_height, tm(tq)))
                        await remove_orphan(self, con)
                        next_block_height -= 1
                        self.log.debug("requested %s" % next_block_height)
                        return
                self.log.debug("blockchain position check [%s]" % tm(q))

                # add all block transactions
                q = tm()
                binary_tx_hash_list = [unhexlify(t)[::-1] for t in block["tx"]]
                if block["height"] in (91842, 91880):
                    # BIP30 Fix
                    self.tx_cache.pop(
                        s2rh(
                            "d5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599"
                        ))
                    self.tx_cache.pop(
                        s2rh(
                            "e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb468"
                        ))
                tx_id_list, missed = await get_tx_id_list(
                    self, binary_tx_hash_list, con)
                if len(tx_id_list) + len(missed) != len(block["tx"]):
                    raise Exception("tx count mismatch")
                self.await_tx_id_list = tx_id_list
                if self.before_block_handler:
                    sn = await self.before_block_handler(
                        block, missed, self.sync_tx_lock, self.node_last_block,
                        con)
                    if sn and missed:
                        self.await_tx_id_list = self.await_tx_id_list + [
                            0 for i in range(len(missed))
                        ]
                        missed = []
                cq = tm()
                missed = [rh2s(t) for t in missed]
                self.log.info("Transactions already exist: %s missed %s [%s]" %
                              (len(tx_id_list), len(missed), tm(q)))
                if missed:
                    self.log.debug("Request missed transactions")
                    self.missed_tx_list = list(missed)
                    self.await_tx_list = missed
                    self.await_tx_future = dict()
                    for i in missed:
                        self.await_tx_future[unhexlify(i)
                                             [::-1]] = asyncio.Future()
                    self.block_txs_request = asyncio.Future()
                    if len(missed) == len(block["tx"]):
                        self.loop.create_task(
                            self._get_missed(block["hash"], block["time"],
                                             block["height"]))
                    else:
                        self.loop.create_task(
                            self._get_missed(False, block["time"],
                                             block["height"]))
                    try:
                        await asyncio.wait_for(self.block_txs_request,
                                               timeout=self.block_timeout)
                    except asyncio.CancelledError:
                        # refresh rpc connection session
                        await self.rpc.close()
                        self.rpc = aiojsonrpc.rpc(self.rpc_url,
                                                  self.loop,
                                                  timeout=self.rpc_timeout)
                        raise RuntimeError("block transaction request timeout")
                if len(block["tx"]) != len(self.await_tx_id_list):
                    self.log.error("get block transactions failed")
                    self.log.error(str(self.await_tx_id_list))
                    raise Exception("get block transactions failed")

                tx_count = len(self.await_tx_id_list)
                self.total_received_tx += tx_count
                self.total_received_tx_time += tm(q)
                rate = round(self.total_received_tx /
                             self.total_received_tx_time)
                self.log.info(
                    "Transactions received: %s [%s] rate tx/s ->> %s <<" %
                    (tx_count, tm(cq), rate))
                async with con.transaction():
                    if self.block_received_handler:
                        await self.block_received_handler(block, con)
                    # insert new block
                    await insert_new_block(self, binary_block_hash,
                                           block["height"],
                                           binary_previousblock_hash,
                                           block["time"], con)
                    if not self.external_dublicate_filter:
                        self.loop.create_task(
                            update_block_height(self, block["height"],
                                                list(self.await_tx_id_list)))
                if self.sync == block["height"]:
                    self.sync += 1
                    next_block_height = self.sync
                # after block added handler
                if self.block_handler:
                    await self.block_handler(block, con)
            self.last_block_height = block["height"]
            self.block_cache.set(binary_block_hash, block["height"])
        except Exception as err:
            if self.await_tx_list:
                self.await_tx_list = []
            self.log.error(str(traceback.format_exc()))
            self.log.error("new block error %s" % str(err))
            next_block_height = None
        finally:
            self.active_block.set_result(True)
            self.log.debug("block  processing completed")
            if next_block_height is not None:
                self.sync_requested = True
                self.loop.create_task(
                    self.get_block_by_height(next_block_height))
            self.log.info(
                "%s block [%s tx/ %s size] (dp %s) processing time %s cache [%s/%s]"
                % (block["height"], len(block["tx"]), block["size"] / 1000000,
                   self.block_dependency_tx, tm(bt),
                   len(self.block_hashes_preload._store),
                   len(self.block_preload._store)))
Beispiel #8
0
async def get_block_transactions(request):
    log = request.app["log"]
    log.info("GET %s" % str(request.rel_url))
    status = 500
    response = {"error_code": INTERNAL_SERVER_ERROR,
                "message": "internal server error",
                "details": ""}
    parameters = request.rel_url.query
    try:
        limit = int(parameters["limit"])
        if  not (limit >= 0):
            raise Exception()
    except:
        limit = 50

    try:
        mode = parameters['mode']
    except:
        mode = "brief"

    if mode not in ["brief", "verbose"]:
        mode = "brief"

    try:
        page = int(parameters["page"])
        if page <= 0: raise Exception()
    except:
        page = 1

    if limit == 0 or limit > request.app["get_block_tx_page_limit"]:
        if limit == 0:
            page = 1
        limit = request.app["get_block_tx_page_limit"]

    if limit * page > 2 ** 19 - 1:
        limit = 50
        page = 1

    try:
        order = "asc" if parameters["order"] == "asc" else "desc"
    except:
        order = "asc"

    try:
        pointer = request.match_info['block_pointer']
        if len(pointer) < 12:
            try:
                pointer = int(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
        elif len(pointer) == 64:
            try:
                pointer = s2rh(pointer)
            except:
                raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")
        else:
            raise APIException(INVALID_BLOCK_POINTER, "invalid block pointer")

        option_raw_tx = False
        try:
            if request.rel_url.query['raw_tx'] in ('True', '1'):
                option_raw_tx = True
        except:
            pass

        response = await block_transactions(pointer, option_raw_tx, limit, page, order, mode, request.app)
        status = 200
    except APIException as err:
        status = err.status
        response = {"error_code": err.err_code,
                    "message": err.message,
                    "details": err.details}
    except Exception as err:
        if request.app["debug"]:
            log.error(str(traceback.format_exc()))
        else:
            log.error(str(err))
    finally:
        return web.json_response(response, dumps=json.dumps, status = status)