Пример #1
0
def get_address_generator(script_pre, script_post, vbyte):
    counter = 0
    while True:
        script = script_pre + struct.pack(b'=LQQ', 0, 0, counter) + script_post
        addr = btc.script_to_address(script, vbyte)
        yield addr, binascii.hexlify(script).decode('ascii')
        counter += 1
Пример #2
0
    def add_tx_notify(self,
                      txd,
                      unconfirmfun,
                      confirmfun,
                      spentfun,
                      notifyaddr,
                      timeoutfun=None):
        if not self.notifythread:
            self.notifythread = BitcoinCoreNotifyThread(self)
            self.notifythread.start()
        one_addr_imported = False
        for outs in txd['outs']:
            addr = btc.script_to_address(outs['script'], get_p2pk_vbyte())
            if self.rpc('getaccount', [addr]) != '':
                one_addr_imported = True
                break
        if not one_addr_imported:
            self.rpc('importaddress', [notifyaddr, 'joinmarket-notify', False])
        tx_output_set = set([(sv['script'], sv['value'])
                             for sv in txd['outs']])
        self.txnotify_fun.append(
            (btc.txhash(btc.serialize(txd)), tx_output_set, unconfirmfun,
             confirmfun, spentfun, timeoutfun, False))

        #create unconfirm timeout here, create confirm timeout in the other thread
        if timeoutfun:
            threading.Timer(cs_single().config.getint('TIMEOUT',
                                                      'unconfirm_timeout_sec'),
                            bitcoincore_timeout_callback,
                            args=(False, tx_output_set, self.txnotify_fun,
                                  timeoutfun)).start()
def test_create_p2sh_output_tx(setup_tx_creation, nw, wallet_structures,
                               mean_amt, sdev_amt, amount, pubs, k):
    wallets = make_wallets(nw, wallet_structures, mean_amt, sdev_amt)
    for w in wallets.values():
        sync_wallet(w['wallet'], fast=True)
    for k, w in enumerate(wallets.values()):
        wallet = w['wallet']
        ins_full = wallet.select_utxos(0, amount)
        script = bitcoin.mk_multisig_script(pubs, k)
        output_addr = bitcoin.script_to_address(script, vbyte=196)
        txid = make_sign_and_push(ins_full,
                                  wallet,
                                  amount,
                                  output_addr=output_addr)
        assert txid
    def tx_watcher(self, txd, unconfirmfun, confirmfun, spentfun, c, n):
        """Called at a polling interval, checks if the given deserialized
        transaction (which must be fully signed) is (a) broadcast, (b) confirmed
        and (c) spent from. (c, n ignored in electrum version, just supports
        registering first confirmation).
        TODO: There is no handling of conflicts here.
        """
        txid = btc.txhash(btc.serialize(txd))
        wl = self.tx_watcher_loops[txid]
        #first check if in mempool (unconfirmed)
        #choose an output address for the query. Filter out
        #p2pkh addresses, assume p2sh (thus would fail to find tx on
        #some nonstandard script type)
        addr = None
        for i in range(len(txd['outs'])):
            if not btc.is_p2pkh_script(txd['outs'][i]['script']):
                addr = btc.script_to_address(txd['outs'][i]['script'],
                                             get_p2sh_vbyte())
                break
        if not addr:
            log.error("Failed to find any p2sh output, cannot be a standard "
                      "joinmarket transaction, fatal error!")
            reactor.stop()
            return
        unconftxs_res = self.get_from_electrum(
            'blockchain.address.get_mempool', addr,
            blocking=True).get('result')
        unconftxs = [str(t['tx_hash']) for t in unconftxs_res]

        if not wl[1] and txid in unconftxs:
            jmprint("Tx: " + str(txid) + " seen on network.", "info")
            unconfirmfun(txd, txid)
            wl[1] = True
            return
        conftx = self.get_from_electrum('blockchain.address.listunspent',
                                        addr,
                                        blocking=True).get('result')
        conftxs = [str(t['tx_hash']) for t in conftx]
        if not wl[2] and len(conftxs) and txid in conftxs:
            jmprint("Tx: " + str(txid) + " is confirmed.", "info")
            confirmfun(txd, txid, 1)
            wl[2] = True
            #Note we do not stop the monitoring loop when
            #confirmations occur, since we are also monitoring for spending.
            return
        if not spentfun or wl[3]:
            return
Пример #5
0
def test_spend_freeze_script(setup_tx_creation):
    ensure_bip65_activated()

    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)

    mediantime = jm_single().bc_interface.rpc("getblockchaininfo", [])["mediantime"]

    timeoffset_success_tests = [(2, False), (-60*60*24*30, True), (60*60*24*30, False)]

    for timeoffset, required_success in timeoffset_success_tests:
        #generate keypair
        priv = "aa"*32 + "01"
        pub = unhexlify(bitcoin.privkey_to_pubkey(priv))
        addr_locktime = mediantime + timeoffset
        redeem_script = bitcoin.mk_freeze_script(pub, addr_locktime)
        script_pub_key = bitcoin.redeem_script_to_p2wsh_script(redeem_script)
        regtest_vbyte = 100
        addr = bitcoin.script_to_address(script_pub_key, vbyte=regtest_vbyte)

        #fund frozen funds address
        amount = 100000000
        funding_ins_full = wallet_service.select_utxos(0, amount)
        funding_txid = make_sign_and_push(funding_ins_full, wallet_service, amount, output_addr=addr)
        assert funding_txid

        #spend frozen funds
        frozen_in = funding_txid + ":0"
        output_addr = wallet_service.get_internal_addr(1)
        miner_fee = 5000
        outs = [{'value': amount - miner_fee, 'address': output_addr}]
        tx = bitcoin.mktx([frozen_in], outs, locktime=addr_locktime+1)
        i = 0
        sig = bitcoin.get_p2sh_signature(tx, i, redeem_script, priv, amount)

        assert bitcoin.verify_tx_input(tx, i, script_pub_key, sig, pub,
            scriptCode=redeem_script, amount=amount)
        tx = bitcoin.apply_freeze_signature(tx, i, redeem_script, sig)
        push_success = jm_single().bc_interface.pushtx(tx)

        assert push_success == required_success
Пример #6
0
def test_script_to_address(setup_tx_creation):
    sample_script = "a914307f099a3bfedec9a09682238db491bade1b467f87"
    assert bitcoin.script_to_address(
        sample_script, vbyte=5) == "367SYUMqo1Fi4tQsycnmCtB6Ces1Z7EZLH"
    assert bitcoin.script_to_address(
        sample_script, vbyte=196) == "2MwfecDHsQTm4Gg3RekQdpqAMR15BJrjfRF"
    def add_tx_notify(self,
                      txd,
                      unconfirmfun,
                      confirmfun,
                      notifyaddr,
                      wallet_name=None,
                      timeoutfun=None,
                      spentfun=None,
                      txid_flag=True,
                      n=0,
                      c=1,
                      vb=None):
        """Given a deserialized transaction txd,
        callback functions for broadcast and confirmation of the transaction,
        an address to import, and a callback function for timeout, set up
        a polling loop to check for events on the transaction. Also optionally set
        to trigger "confirmed" callback on number of confirmations c. Also checks
        for spending (if spentfun is not None) of the outpoint n.
        If txid_flag is True, we create a watcher loop on the txid (hence only
        really usable in a segwit context, and only on fully formed transactions),
        else we create a watcher loop on the output set of the transaction (taken
        from the outs field of the txd).
        """
        if not vb:
            vb = get_p2pk_vbyte()
        if isinstance(self, BitcoinCoreInterface) or isinstance(
                self, RegtestBitcoinCoreInterface):
            #This code ensures that a walletnotify is triggered, by
            #ensuring that at least one of the output addresses is
            #imported into the wallet (note the sweep special case, where
            #none of the output addresses belong to me).
            one_addr_imported = False
            for outs in txd['outs']:
                addr = btc.script_to_address(outs['script'], vb)
                try:
                    if self.is_address_imported(addr):
                        one_addr_imported = True
                        break
                except JsonRpcError as e:
                    log.debug("Failed to getaccount for address: " + addr)
                    log.debug("This is normal for bech32 addresses.")
                    continue
            if not one_addr_imported:
                try:
                    self.rpc('importaddress',
                             [notifyaddr, 'joinmarket-notify', False])
                except JsonRpcError as e:
                    #In edge case of address already controlled
                    #by another account, warn but do not quit in middle of tx.
                    #Can occur if destination is owned in Core wallet.
                    if e.code == -4 and e.message == "The wallet already " + \
                       "contains the private key for this address or script":
                        log.warn("WARNING: Failed to import address: " +
                                 notifyaddr)
                    #No other error should be possible
                    else:
                        raise

        #Warning! In case of txid_flag false, this is *not* a valid txid,
        #but only a hash of an incomplete transaction serialization.
        txid = btc.txhash(btc.serialize(txd))
        if not txid_flag:
            tx_output_set = set([(sv['script'], sv['value'])
                                 for sv in txd['outs']])
            loop = task.LoopingCall(self.outputs_watcher, wallet_name,
                                    notifyaddr, tx_output_set, unconfirmfun,
                                    confirmfun, timeoutfun)
            log.debug("Created watcher loop for address: " + notifyaddr)
            loopkey = notifyaddr
        else:
            loop = task.LoopingCall(self.tx_watcher, txd, unconfirmfun,
                                    confirmfun, spentfun, c, n)
            log.debug("Created watcher loop for txid: " + txid)
            loopkey = txid
        self.tx_watcher_loops[loopkey] = [loop, False, False, False]
        #Hardcoded polling interval, but in any case it can be very short.
        loop.start(5.0)
        #Give up on un-broadcast transactions and broadcast but not confirmed
        #transactions as per settings in the config.
        reactor.callLater(
            float(jm_single().config.get("TIMEOUT", "unconfirm_timeout_sec")),
            self.tx_network_timeout, loopkey)
        confirm_timeout_sec = int(jm_single().config.get(
            "TIMEOUT", "confirm_timeout_hours")) * 3600
        reactor.callLater(confirm_timeout_sec, self.tx_timeout, txd, loopkey,
                          timeoutfun)
Пример #8
0
 def script_to_address(cls, script):
     return btc.script_to_address(script, vbyte=cls.VBYTE)
Пример #9
0
 def pubkey_to_address(cls, pubkey):
     script = cls.pubkey_to_script(pubkey)
     return btc.script_to_address(script, cls.VBYTE)
Пример #10
0
def scan_for_coinjoins(privkey, amount, filename):
    """Given a file which contains encrypted coinjoin proposals,
    and a private key for a pubkey with a known utxo existing
    which we can spend, scan the entries in the file, all assumed
    to be ECIES encrypted to a pubkey, for one which is encrypted
    to *this* pubkey, if found, output the retrieved partially signed
    transaction, and destination key, address to a list which is
    returned to the caller.
    Only if the retrieved coinjoin transaction passes basic checks
    on validity in terms of amount paid, is it returned.
    This is an elementary implementation that will obviously fail
    any performance test (i.e. moderately large lists).
    Note that the tweaked output address must be of type p2sh/p2wpkh.
    """
    try:
        with open(filename, "rb") as f:
            msgs = f.readlines()
    except:
        print("Failed to read from file: ", filename)
        return
    valid_coinjoins = []
    for msg in msgs:
        try:
            decrypted_msg = decrypt_message(msg, privkey)
            tweak, tx = deserialize_coinjoin_proposal(decrypted_msg)
        except:
            print("Could not decrypt message, skipping")
            continue
        if not tweak:
            print("Could not decrypt message, reason: " + str(tx))
            continue
        #We analyse the content of the transaction to check if it follows
        #our requirements
        try:
            deserialized_tx = btc.deserialize(tx)
        except:
            print("Proposed transaction is not correctly formatted, skipping.")
            continue
        #construct our receiving address according to the tweak
        pubkey = btc.privkey_to_pubkey(privkey)
        tweak, destnpt, my_destn_addr = create_recipient_address(pubkey,
                                                                 tweak=tweak,
                                                                 segwit=True)
        #add_privkeys requires both inputs to be compressed (or un-) consistently.
        tweak_priv = tweak + "01"
        my_destn_privkey = btc.add_privkeys(tweak_priv, privkey, True)
        my_output_index = -1
        for i, o in enumerate(deserialized_tx['outs']):
            addr = btc.script_to_address(o['script'], get_p2sh_vbyte())
            if addr == my_destn_addr:
                print('found our output address: ', my_destn_addr)
                my_output_index = i
                break
        if my_output_index == -1:
            print("Proposal doesn't contain our output address, rejecting")
            continue
        my_output_amount = deserialized_tx['outs'][i]['value']
        required_amount = amount - 2 * estimate_tx_fee(3, 3, 'p2sh-p2wpkh')
        if my_output_amount < required_amount:
            print("Proposal pays too little, difference is: ",
                  required_amount - my_output_amount)
            continue
        #now we know output is acceptable to us, we should check that the
        #ctrprty input is signed and the other input is ours, but will do this
        #later; if it's not, it just won't work so NBD for now.
        valid_coinjoins.append((my_destn_addr, my_destn_privkey, tx))
    return valid_coinjoins
Пример #11
0
 def privkey_to_address(cls, privkey):
     script = cls.key_to_script(privkey)
     return btc.script_to_address(script, cls.VBYTE)