Beispiel #1
0
    async def blockchain_scripthash_listunspent(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.listunspent
        Return an ordered list of UTXOs sent to a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        scripthash = query["params"][0]
        if not is_hash256_str(scripthash):
            return JsonRPCError.invalidparams()

        _ec, utxo = await self.bx.fetch_utxo(scripthash)
        if _ec and _ec != 0:
            self.log.debug("Got error: %s", repr(_ec))
            return JsonRPCError.internalerror()

        # TODO: Check mempool
        ret = []
        for i in utxo:
            rec = i["received"]
            ret.append({
                "tx_pos": rec["index"],
                "value": i["value"],
                "tx_hash": hash_to_hex_str(rec["hash"]),
                "height": rec["height"],
            })

        if len(ret) >= 2:
            ret.reverse()
        return {"result": ret}
Beispiel #2
0
    async def blockchain_transaction_get_merkle(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.transaction.get_merkle
        Return the merkle branch to a confirmed transaction given its
        hash and height.
        """
        if "params" not in query or len(query["params"]) != 2:
            return JsonRPCError.invalidparams()

        tx_hash = query["params"][0]
        height = query["params"][1]

        if not is_hash256_str(tx_hash):
            return JsonRPCError.invalidparams()
        if not is_non_negative_integer(height):
            return JsonRPCError.invalidparams()

        _ec, hashes = await self.bx.fetch_block_transaction_hashes(height)
        if _ec and _ec != 0:
            self.log.debug("Got error: %s", repr(_ec))
            return JsonRPCError.internalerror()

        # Decouple from tuples
        hashes = [i[0] for i in hashes]
        tx_pos = hashes.index(unhexlify(tx_hash)[::-1])
        branch = merkle_branch(hashes, tx_pos)

        res = {
            "block_height": int(height),
            "pos": int(tx_pos),
            "merkle": branch,
        }
        return {"result": res}
Beispiel #3
0
    async def blockchain_scripthash_get_history(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.get_history
        Return the confirmed and unconfirmed history of a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        if not is_hash256_str(query["params"][0]):
            return JsonRPCError.invalidparams()

        _ec, data = await self.bx.fetch_history4(query["params"][0])
        if _ec and _ec != 0:
            self.log.debug("Got error: %s", repr(_ec))
            return JsonRPCError.internalerror()

        self.log.debug("hist: %s", data)
        ret = []
        # TODO: mempool
        for i in data:
            if "received" in i:
                ret.append({
                    "height": i["received"]["height"],
                    "tx_hash": hash_to_hex_str(i["received"]["hash"]),
                })
            if "spent" in i:
                ret.append({
                    "height": i["spent"]["height"],
                    "tx_hash": hash_to_hex_str(i["spent"]["hash"]),
                })

        return {"result": ret}
Beispiel #4
0
    async def scripthash_subscribe(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.subscribe
        Subscribe to a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        scripthash = query["params"][0]
        if not is_hash256_str(scripthash):
            return JsonRPCError.invalidparams()

        _ec, history = await self.bx.fetch_history4(scripthash)
        if _ec and _ec != ZMQError.success:
            self.log.error("bx.fetch_history4: %s", _ec.name)
            return JsonRPCError.internalerror()

        # TODO: Check how history4 acts for mempool/unconfirmed
        status = ElectrumProtocol.__scripthash_status_from_history(history)
        self.peers[self._get_peer(writer)]["sh"][scripthash] = {
            "status": status
        }

        task = asyncio.create_task(self.scripthash_notifier(
            writer, scripthash))
        self.peers[self._get_peer(writer)]["sh"][scripthash]["task"] = task

        if len(history) < 1:
            return {"result": None}
        return {"result": ElectrumProtocol.__scripthash_status_encode(status)}
Beispiel #5
0
    async def scripthash_listunspent(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.listunspent
        Return an ordered list of UTXOs sent to a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        scripthash = query["params"][0]
        if not is_hash256_str(scripthash):
            return JsonRPCError.invalidparams()

        _ec, utxo = await self.bx.fetch_utxo(scripthash)
        if _ec and _ec != ZMQError.success:
            self.log.error("bx.fetch_utxo: %s", _ec.name)
            return JsonRPCError.internalerror()

        ret = []
        for i in utxo:
            rec = i["received"]
            ret.append({
                "tx_pos":
                rec["index"],
                "value":
                i["value"],
                "tx_hash":
                hash_to_hex_str(rec["hash"]),
                "height":
                rec["height"] if rec["height"] != 4294967295 else 0,
            })

        return {"result": ret}
Beispiel #6
0
    async def scripthash_get_balance(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.get_balance
        Return the confirmed and unconfirmed balances of a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        if not is_hash256_str(query["params"][0]):
            return JsonRPCError.invalidparams()

        _ec, data = await self.bx.fetch_balance(query["params"][0])
        if _ec and _ec != ZMQError.success:
            self.log.error("bx.fetch_balance: %s", _ec.name)
            return JsonRPCError.internalerror()

        ret = {"confirmed": data[0], "unconfirmed": data[1]}
        return {"result": ret}
Beispiel #7
0
    async def blockchain_scripthash_get_balance(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.get_balance
        Return the confirmed and unconfirmed balances of a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        if not is_hash256_str(query["params"][0]):
            return JsonRPCError.invalidparams()

        _ec, data = await self.bx.fetch_balance(query["params"][0])
        if _ec and _ec != 0:
            self.log.debug("Got error: %s", repr(_ec))
            return JsonRPCError.internalerror()

        # TODO: confirmed/unconfirmed, see what's happening in libbitcoin
        ret = {"confirmed": data, "unconfirmed": 0}
        return {"result": ret}
Beispiel #8
0
    async def blockchain_scripthash_unsubscribe(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.unsubscribe
        Unsubscribe from a script hash, preventing future notifications
        if its status changes.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        scripthash = query["params"][0]
        if not is_hash256_str(scripthash):
            return JsonRPCError.invalidparams()

        if scripthash in self.sh_subscriptions:
            self.sh_subscriptions[scripthash]["task"].cancel()
            await self.bx.unsubscribe_scripthash(scripthash)
            del self.sh_subscriptions[scripthash]
            return {"result": True}

        return {"result": False}
Beispiel #9
0
    async def blockchain_scripthash_subscribe(self, writer, query):  # pylint: disable=W0613
        """Method: blockchain.scripthash.subscribe
        Subscribe to a script hash.
        """
        if "params" not in query or len(query["params"]) != 1:
            return JsonRPCError.invalidparams()

        scripthash = query["params"][0]
        if not is_hash256_str(scripthash):
            return JsonRPCError.invalidparams()

        _ec, history = await self.bx.fetch_history4(scripthash)
        if _ec and _ec != 0:
            return JsonRPCError.internalerror()

        task = asyncio.create_task(self.scripthash_notifier(writer, scripthash))
        self.sh_subscriptions[scripthash] = {"task": task}

        if len(history) < 1:
            return {"result": None}

        # TODO: Check how history4 acts for mempool/unconfirmed
        status = []
        for i in history:
            if "received" in i:
                status.append((
                    hash_to_hex_str(i["received"]["hash"]),
                    i["received"]["height"],
                ))
            if "spent" in i:
                status.append((
                    hash_to_hex_str(i["spent"]["hash"]),
                    i["spent"]["height"],
                ))

        self.sh_subscriptions[scripthash]["status"] = status
        return {"result": ElectrumProtocol.__scripthash_status(status)}