def address(self) -> str: if not self.scope.script_pubkey.data: return "Fee" if self.scope.script_pubkey.data.startswith(b"\x6a"): if len(self.scope.script_pubkey.data) == 1: return "DUMMY" # dummy output to blind else: return "OP_RETURN " + self.scope.script_pubkey.data[1:].hex() try: # try making a liquid address return liquid_address( self.scope.script_pubkey, self.blinding_key, network=self.network ) except: # if failed - return hex of the scriptpubkey return self.scope.script_pubkey.data.hex()
def decoderawtransaction(self, tx): unblinded = self.unblindrawtransaction(tx)["hex"] obj = super().__getattr__("decoderawtransaction")(unblinded) try: # unblind the rest of outputs b = LTransaction.from_string(tx) mbpk = PrivateKey(bytes.fromhex(self.dumpmasterblindingkey())) net = get_network(self.getblockchaininfo().get("chain")) outputs = obj["vout"] datas = [] fee = 0 # search for datas encoded in rangeproofs for i, out in enumerate(b.vout): o = outputs[i] if isinstance(out.value, int): if "value" in o: assert o["value"] == round(out.value * 1e-8, 8) else: o["value"] = round(out.value * 1e-8, 8) if "asset" in o: assert o["asset"] == bytes(reversed( out.asset[-32:])).hex() else: o["asset"] = bytes(reversed(out.asset[-32:])).hex() try: o["scriptPubKey"]["addresses"] = [ liquid_address(out.script_pubkey, network=net) ] except: pass if out.script_pubkey.data == b"": # fee negative? fee -= out.value pk = slip77.blinding_key(mbpk, out.script_pubkey) try: res = out.unblind(pk.secret, message_length=1000) value, asset, vbf, abf, extra, min_value, max_value = res if "value" in o: assert o["value"] == round(value * 1e-8, 8) else: o["value"] = round(value * 1e-8, 8) if "asset" in o: assert o["asset"] == bytes(reversed(asset[-32:])).hex() else: o["asset"] = bytes(reversed(asset[-32:])).hex() try: o["scriptPubKey"]["addresses"] = [ liquid_address(out.script_pubkey, pk, network=net) ] except: pass if len(extra.rstrip(b"\x00")) > 0: datas.append(extra) except Exception as e: pass # should be changed with seed from tx tx = PSET(b) seed = tagged_hash("liquid/blinding_seed", mbpk.secret) txseed = tx.txseed(seed) pubkeys = {} for extra in datas: s = BytesIO(extra) while True: k = read_string(s) if len(k) == 0: break v = read_string(s) if k[0] == 1 and len(k) == 5: idx = int.from_bytes(k[1:], "little") pubkeys[idx] = v elif k == b"\x01\x00": txseed = v for i, out in enumerate(outputs): o = out if i in pubkeys and len(pubkeys[i]) in [33, 65]: nonce = tagged_hash("liquid/range_proof", txseed + i.to_bytes(4, "little")) if b.vout[i].ecdh_pubkey == PrivateKey(nonce).sec(): try: res = unblind( pubkeys[i], nonce, b.vout[i].witness.range_proof.data, b.vout[i].value, b.vout[i].asset, b.vout[i].script_pubkey, ) value, asset, vbf, abf, extra, min_value, max_value = res if "value" in o: assert o["value"] == round(value * 1e-8, 8) else: o["value"] = round(value * 1e-8, 8) if "asset" in o: assert o["asset"] == bytes( reversed(asset[-32:])).hex() else: o["asset"] = bytes(reversed(asset[-32:])).hex() try: o["scriptPubKey"]["addresses"] = [ liquid_address( b.vout[i].script_pubkey, PublicKey.parse(pubkeys[i]), network=net, ) ] except: pass except Exception as e: logger.warn( f"Failed at unblinding output {i}: {e}") else: logger.warn(f"Failed at unblinding: {e}") if fee != 0: obj["fee"] = round(-fee * 1e-8, 8) except Exception as e: logger.warn(f"Failed at unblinding transaction: {e}") return obj
def address(self) -> str: # TODO: blinding key? try: return liquid_address(self.scope.script_pubkey, network=self.network) except: return None