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}
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}
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}
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)}
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}
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}
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}
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}
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)}