Пример #1
0
 def add(self, txs):
     """
     adds transactions to the list without any rpc calls.
     assuming tx is already watched by the wallet.
     Transactions should be a dict with dicts with fields:
     "<txid>": {
         "txid", - hex txid
         "hex",  - hex raw transaction
         "blockheight", - int blockheight if confirmed, None otherwise
         "blockhash", - str blockhash if confirmed, None otherwise
         "time", - int unix timestamp in seconds when tx was received
         "blocktime",  - int unix timestamp in seconds  the block was mined
         "conflicts", - list of txids spending the same inputs (rbf)
         "bip125-replaceable", - str ("yes" or "no") - is rbf enabled for this tx
     }
     """
     # here we store all addresses in transactions
     # to set them used later
     addresses = []
     # first we add all transactions to cache
     for txid in txs:
         tx = txs[txid]
         # find minimal from 3 times:
         maxtime = 10445238000  # TODO: change after 31 dec 2300 lol
         time = min(
             tx.get("blocktime", maxtime),
             tx.get("timereceived", maxtime),
             tx.get("time", maxtime),
         )
         obj = {
             "txid": txid,
             "blockheight": tx.get("blockheight", None),
             "blockhash": tx.get("blockhash", None),
             "time": time,
             "blocktime": tx.get("blocktime", None),
             "conflicts": tx.get("walletconflicts", []),
             "bip125-replaceable": tx.get("bip125-replaceable", "no"),
             "hex": tx.get("hex", None),
         }
         txitem = self.ItemCls(self, self._addresses, self.rawdir, **obj)
         self[txid] = txitem
         if txitem.tx:
             for vout in txitem.tx.vout:
                 try:
                     addr = vout.script_pubkey.address(
                         get_network(self.chain))
                     if addr not in addresses:
                         addresses.append(addr)
                 except:
                     pass  # maybe not an address, but a raw script?
     self._addresses.set_used(addresses)
     # detect category, amounts and addresses
     for tx in [self[txid] for txid in self if txid in txs]:
         self._fill_missing(tx)
     self._save()
Пример #2
0
    def extract_xpub(
        self,
        derivation=None,
        device_type=None,
        path=None,
        fingerprint=None,
        passphrase="",
        chain="",
    ):
        with self._get_client(
                device_type=device_type,
                fingerprint=fingerprint,
                path=path,
                passphrase=passphrase,
                chain=chain,
        ) as client:
            # Client will be configured for testnet if our Specter instance is
            #   currently connected to testnet. This will prevent us from
            #   getting mainnet xpubs unless we set is_testnet here:
            try:
                client.chain = (Chain.TEST
                                if derivation.split("/")[2].startswith("1")
                                else Chain.MAIN)
            except:
                client.chain = Chain.MAIN

            network = networks.get_network("main" if client.chain ==
                                           Chain.MAIN else "test")

            master_fpr = client.get_master_fingerprint().hex()

            try:
                xpub = client.get_pubkey_at_path(derivation).to_string()
                slip132_prefix = bip32.detect_version(derivation,
                                                      default="xpub",
                                                      network=network)
                xpub = convert_xpub_prefix(xpub, slip132_prefix)
                return "[{}/{}]{}\n".format(master_fpr,
                                            derivation.split("m/")[1], xpub)
            except Exception as e:
                logger.warning(
                    f"Failed to import Nested Segwit singlesig mainnet key. Error: {e}"
                )
Пример #3
0
def fill_external_wallet_derivations(psbt, wallet):
    # fill derivations for receiving wallets if they own address
    net = get_network(wallet.manager.chain)
    wallets = wallet.manager.wallets.values()
    for out in psbt.outputs:
        try:  # if we fail - not a big deal
            # check if output derivation is empty
            if out.bip32_derivations:
                continue
            try:
                # if there is no address representation - continue
                addr = out.script_pubkey.address(net)
            except:
                continue
            for w in wallets:
                # skip sending wallet
                if w == wallet:
                    continue
                if not w.is_address_mine(addr):
                    continue
                # we get here if wallet owns address
                info = w.get_address_info(addr)
                derivation = [int(info.change), int(info.index)]
                # we first one key and build derivation for it
                # it's enough for DIY to do the res
                k = w.keys[0]
                key = bip32.HDKey.from_string(k.xpub)
                if k.fingerprint != "":
                    fingerprint = bytes.fromhex(k.fingerprint)
                else:
                    fingerprint = key.my_fingerprint
                if k.derivation != "":
                    der = bip32.parse_path(k.derivation)
                else:
                    der = []
                pub = key.derive(derivation).key
                out.bip32_derivations[pub] = DerivationPath(
                    fingerprint, der + derivation)
                break
        except Exception as e:
            logger.exception(e)
Пример #4
0
 def network_parameters(self):
     try:
         return self._network_parameters
     except Exception:
         return get_network("main")
Пример #5
0
    def check_info(self):
        self._is_configured = self.rpc is not None
        self._is_running = False
        if self.rpc is not None and self.rpc.test_connection():
            try:
                res = [
                    r["result"] for r in self.rpc.multi([
                        ("getblockchaininfo", None),
                        ("getnetworkinfo", None),
                        ("getmempoolinfo", None),
                        ("uptime", None),
                        ("getblockhash", 0),
                        ("scantxoutset", "status", []),
                    ])
                ]
                self._info = res[0]
                self._network_info = res[1]
                self._info["mempool_info"] = res[2]
                self._info["uptime"] = res[3]
                try:
                    self.rpc.getblockfilter(res[4])
                    self._info["blockfilterindex"] = True
                except:
                    self._info["blockfilterindex"] = False
                self._info["utxorescan"] = (res[5]["progress"]
                                            if res[5] is not None
                                            and "progress" in res[5] else None)
                if self._info["utxorescan"] is None:
                    self.utxorescanwallet = None
                self._network_parameters = get_network(self.chain)
                self._is_running = True
            except Exception as e:
                self._info = {"chain": None}
                self._network_info = {"subversion": "", "version": 999999}
                self._network_parameters = get_network("main")
                logger.error(
                    f"connection {self.rpc} could not suceed check_info")
                logger.exception("Exception %s while check_info()" % e)
        else:
            if self.rpc is None:
                logger.warning(f"connection of {self} is None in check_info")
            elif not self.rpc.test_connection():
                logger.debug(
                    f"connection {self.rpc} failed test_connection in check_info:"
                )
                try:
                    self.rpc.multi([
                        ("getblockchaininfo", None),
                        ("getnetworkinfo", None),
                        ("getmempoolinfo", None),
                        ("uptime", None),
                        ("getblockhash", 0),
                        ("scantxoutset", "status", []),
                    ])
                except Exception as e:
                    logger.error(e)
            self._info = {"chain": None}
            self._network_info = {"subversion": "", "version": 999999}

        if not self._is_running:
            self._info["chain"] = None
Пример #6
0
from embit.liquid.descriptor import LDescriptor as Descriptor
from embit.descriptor.checksum import add_checksum
from embit.bip32 import HDKey
from embit.liquid.networks import get_network
from embit.liquid.pset import PSET as PSBT
from embit.liquid.transaction import LSIGHASH
from embit.liquid.finalizer import finalize_psbt
from embit.liquid.addresses import addr_decode
from embit.ec import PrivateKey

wallet_prefix = "test" + random.randint(0, 0xFFFFFFFF).to_bytes(4, 'big').hex()
root = HDKey.from_string(
    "tprv8ZgxMBicQKsPf27gmh4DbQqN2K6xnXA7m7AeceqQVGkRYny3X49sgcufzbJcq4k5eaGZDMijccdDzvQga2Saqd78dKqN52QwLyqgY8apX3j"
)
fgp = root.child(0).fingerprint.hex()
net = get_network('elreg')


def random_wallet_name():
    return "test" + random.randint(0, 0xFFFFFFFF).to_bytes(4, 'big').hex()


class PSETTest(TestCase):
    """Complete tests with Core on regtest - should catch problems with signing of transactions"""
    def sign_with_descriptor(self, d1, d2, root, selfblind=False):
        rpc = daemon.rpc
        wname = random_wallet_name()
        # to derive addresses
        desc1 = Descriptor.from_string(d1)
        desc2 = Descriptor.from_string(d2)
        # recv addr 2
Пример #7
0
    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
Пример #8
0
 def address(self, idx=None, network=None):
     if network is None:
         net = get_network("test" if self.testnet else "main")
     else:
         net = get_network(network)
     return self.scriptpubkey(idx).address(net)