def test_auth_pub_not_found(setup_taker):
    taker = get_taker([(0, 20000000, 3, "mnsquzxrHXpFsZeL42qwbKdCP2y1esN3qw",
                        0, NO_ROUNDING)])
    orderbook = copy.deepcopy(t_orderbook)
    res = taker.initialize(orderbook, [])
    taker.orderbook = copy.deepcopy(
        t_chosen_orders)  #total_cjfee unaffected, all same
    maker_response = copy.deepcopy(t_maker_response)
    utxos = [
        utxostr_to_utxo(x)[1] for x in [
            "03243f4a659e278a1333f8308f6aaf32db4692ee7df0340202750fd6c09150f6:1",
            "498faa8b22534f3b443c6b0ce202f31e12f21668b4f0c7a005146808f250d4c3:0",
            "3f3ea820d706e08ad8dc1d2c392c98facb1b067ae4c671043ae9461057bd2a3c:1"
        ]
    ]
    fake_query_results = [{
        'value':
        200000000,
        'address':
        "mrKTGvFfYUEqk52qPKUroumZJcpjHLQ6pn",
        'script':
        hextobin('76a914767c956efe6092a775fea39a06d1cac9aae956d788ac'),
        'utxo':
        utxos[i],
        'confirms':
        20
    } for i in range(3)]
    jm_single().bc_interface.insert_fake_query_results(fake_query_results)
    res = taker.receive_utxos(maker_response)
    assert not res[0]
    assert res[1] == "Not enough counterparties responded to fill, giving up"
    jm_single().bc_interface.insert_fake_query_results(None)
示例#2
0
def get_utxo_info(upriv, utxo_binary=False):
    """Verify that the input string parses correctly as (utxo, priv)
    and return that. If `utxo_binary` is true, the first element of
    that return tuple is the standard internal form
    (txid-in-binary, index-as-int).
    """
    try:
        u, priv = upriv.split(',')
        u = u.strip()
        priv = priv.strip()
        success, utxo_bin = utxostr_to_utxo(u)
        assert success, utxo
    except:
        #not sending data to stdout in case privkey info
        jmprint("Failed to parse utxo information for utxo", "error")
        raise
    try:
        # see note below for why keytype is ignored, and note that
        # this calls read_privkey to validate.
        raw, _ = BTCEngine.wif_to_privkey(priv)
    except:
        jmprint("failed to parse privkey, make sure it's WIF compressed format.", "error")
        raise
    utxo_to_return = utxo_bin if utxo_binary else u
    return utxo_to_return, priv
示例#3
0
def test_sign_external_psbt(setup_psbt_wallet, walletseed, xpub,
                            spktype_wallet, spktype_destn, partial, psbt):
    bitcoin.select_chain_params("bitcoin")
    wallet_cls = SegwitWallet if spktype_wallet == "p2wpkh" else SegwitLegacyWallet
    wallet = create_volatile_wallet(walletseed, wallet_cls=wallet_cls)

    # if we want to actually sign, our wallet has to recognize the fake utxos
    # as being in the wallet, so we inject them:
    class DummyUtxoManager(object):
        _utxo = {0: {}}

        def add_utxo(self, utxo, path, value, height):
            self._utxo[0][utxo] = (path, value, height)

    wallet._index_cache[0][0] = 1000
    wallet._utxos = DummyUtxoManager()
    p0, p1, p2 = (wallet.get_path(0, 0, i) for i in range(3))
    if not partial:
        wallet._utxos.add_utxo(
            utxostr_to_utxo(
                "0b7468282e0c5fd82ee6b006ed5057199a7b3a1c4422e58ddfb35c5e269684bb:0"
            ), p0, 10000, 1)
    wallet._utxos.add_utxo(
        utxostr_to_utxo(
            "442d551b314efd28f49c89e06b9495efd0fbc8c64fd06f398a73ad47c6447df9:0"
        ), p1, 10000, 1)
    wallet._utxos.add_utxo(
        utxostr_to_utxo(
            "4bda19e193781fb899511a052717fa38cd4d341a4f6dc29b6cb10c854c29e76b:0"
        ), p2, 10000, 1)
    signresult_and_signedpsbt, err = wallet.sign_psbt(base64.b64decode(
        psbt.encode("ascii")),
                                                      with_sign_result=True)
    assert not err
    signresult, signedpsbt = signresult_and_signedpsbt
    if partial:
        assert not signresult.is_final
        assert signresult.num_inputs_signed == 2
        assert signresult.num_inputs_final == 2
    else:
        assert signresult.is_final
        assert signresult.num_inputs_signed == 3
        assert signresult.num_inputs_final == 3
    print(PSBTWalletMixin.human_readable_psbt(signedpsbt))
    bitcoin.select_chain_params("bitcoin/regtest")
def test_get_utxo_info():
    load_test_config()
    # this test tests mainnet keys, so temporarily switch network
    select_chain_params("bitcoin")
    jm_single().config.set("BLOCKCHAIN", "network", "mainnet")

    dbci = DummyBlockchainInterface()
    privkey = "L1RrrnXkcKut5DEMwtDthjwRcTTwED36thyL1DebVrKuwvohjMNi"
    #to verify use from_wif_privkey and privkey_to_address
    iaddr = "bc1q6tvmnmetj8vfz98vuetpvtuplqtj4uvvwjgxxc"
    fakeutxo = "aa" * 32 + ":08"
    success, fakeutxo_bin = utxostr_to_utxo(fakeutxo)
    assert success
    fake_query_results = [{
        'value': 200000000,
        'script': BTC_P2WPKH.address_to_script(iaddr),
        'utxo': fakeutxo_bin,
        'confirms': 20
    }]
    dbci.insert_fake_query_results(fake_query_results)
    jm_single().bc_interface = dbci
    u, priv = get_utxo_info(fakeutxo + "," + privkey)
    assert u == fakeutxo
    assert priv == privkey
    #invalid format
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fakeutxo + privkey)
    #invalid index
    fu2 = "ab" * 32 + ":-1"
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fu2 + "," + privkey)
    #invalid privkey
    p2 = privkey[:-1] + 'j'
    with pytest.raises(Exception):
        u, priv = get_utxo_info(fakeutxo + "," + p2)

    utxodatas = [(fakeutxo_bin, privkey)]
    retval = validate_utxo_data(utxodatas, False)
    assert retval
    #try to retrieve
    retval = validate_utxo_data(utxodatas, True)
    assert retval[0] == (fakeutxo_bin, 200000000)
    fake_query_results[0]['script'] = hextobin(
        "76a91479b000887626b294a914501a4cd226b58b23598388ac")
    dbci.insert_fake_query_results(fake_query_results)
    #validate should fail for wrong address
    retval = validate_utxo_data(utxodatas, False)
    assert not retval
    #remove fake query result and trigger not found
    dbci.fake_query_results = None
    dbci.setQUSFail(True)
    retval = validate_utxo_data(utxodatas, False)
    assert not retval
    dbci.setQUSFail(False)
    select_chain_params("bitcoin/regtest")
    jm_single().config.set("BLOCKCHAIN", "network", "regtest")
 def get_utxos_by_mixdepth(self, include_disabled=False, verbose=True,
                           includeheight=False):
     # utxostr conversion routines because taker_test_data uses hex:
     retval = {}
     for mixdepth, v in t_utxos_by_mixdepth.items():
         retval[mixdepth] = {}
         for i, (utxo, val) in enumerate(v.items()):
             retval[mixdepth][utxostr_to_utxo(utxo)[1]] = val
             val["script"] = self._ENGINE.address_to_script(val['address'])
             val["path"] = (b'dummy', mixdepth, i)
     return retval
def main():
    parser = OptionParser(
        usage='usage: %prog [options] utxo destaddr1 destaddr2 ..',
        description=description,
        formatter=IndentedHelpFormatterWithNL())
    parser.add_option(
        '-t',
        '--utxo-address-type',
        action='store',
        dest='utxo_address_type',
        help=
        ('type of address of coin being spent - one of "p2pkh", "p2wpkh", "p2sh-p2wpkh". '
         'No other scriptpubkey types (e.g. multisig) are supported. If not set, we default '
         'to what is in joinmarket.cfg.'),
        default="")
    add_base_options(parser)
    (options, args) = parser.parse_args()
    load_program_config(config_path=options.datadir)
    if len(args) < 2:
        quit(parser, 'Invalid syntax')
    u = args[0]
    priv = input('input private key for ' + u +
                 ', in WIF compressed format : ')
    u, priv = get_utxo_info(','.join([u, priv]))
    if not u:
        quit(parser, "Failed to parse utxo info: " + u)
    destaddrs = args[1:]
    for d in destaddrs:
        if not validate_address(d):
            quit(parser, "Address was not valid; wrong network?: " + d)
    success, utxo = utxostr_to_utxo(u)
    if not success:
        quit(parser, "Failed to load utxo from string: " + utxo)
    if options.utxo_address_type == "":
        if jm_single().config.get("POLICY", "segwit") == "false":
            utxo_address_type = "p2pkh"
        elif jm_single().config.get("POLICY", "native") == "false":
            utxo_address_type = "p2sh-p2wpkh"
        else:
            utxo_address_type = "p2wpkh"
    else:
        utxo_address_type = options.utxo_address_type
    txsigned = sign(utxo, priv, destaddrs, utxo_address_type)
    if not txsigned:
        log.info(
            "Transaction signing operation failed, see debug messages for details."
        )
        return
    log.info("Got signed transaction:\n" + bintohex(txsigned.serialize()))
    log.info(btc.human_readable_transaction(txsigned))
    if input('Would you like to push to the network? (y/n):')[0] != 'y':
        log.info("You chose not to broadcast the transaction, quitting.")
        return
    jm_single().bc_interface.pushtx(txsigned.serialize())
 def select_utxos(self, mixdepth, amount, utxo_filter=None, select_fn=None,
                  maxheight=None, includeaddr=False):
     if amount > self.get_balance_by_mixdepth()[mixdepth]:
         raise NotEnoughFundsException(amount, self.get_balance_by_mixdepth()[mixdepth])
     # comment as for get_utxos_by_mixdepth:
     retval = {}
     for k, v in t_utxos_by_mixdepth[mixdepth].items():
         success, u = utxostr_to_utxo(k)
         assert success
         retval[u] = v
         retval[u]["script"] = self.addr_to_script(retval[u]["address"])
     return retval
 def deserialize_revelation(cls, ser_rev, separator='|'):
     """ Reads the over-the-wire format as used in
     Joinmarket communication protocol.
     """
     ser_list = ser_rev.split(separator)
     if len(ser_list) != 5:
         raise PoDLEError("Failed to deserialize, wrong format")
     utxostr, P, P2, s, e = ser_list
     success, utxo = utxostr_to_utxo(utxostr)
     assert success, "invalid utxo format in PoDLE."
     return {'utxo': utxo, 'P': hextobin(P),
             'P2': hextobin(P2), 'sig': hextobin(s), 'e': hextobin(e)}
def convert_utxos(utxodict):
    return_dict = {}
    for uk, val in utxodict.items():
        return_dict[utxostr_to_utxo(uk)[1]] = val
    return return_dict
示例#10
0
def main():
    parser = OptionParser(
        usage=
        'usage: %prog [options] utxo destaddr1 destaddr2 ..',
        description="For creating multiple utxos from one (for commitments in JM)."
                    "Provide a utxo in form txid:N that has some unspent coins;"
                    "Specify a list of destination addresses and the coins will"
                    "be split equally between them (after bitcoin fees)."

                    "You'll be prompted to enter the private key for the utxo"
                    "during the run; it must be in WIF compressed format."
                    "After the transaction is completed, the utxo strings for"

                    "the new outputs will be shown."
                    "Note that these utxos will not be ready for use as external"

                    "commitments in Joinmarket until 5 confirmations have passed."
                    " BE CAREFUL about handling private keys!"
                    " Don't do this in insecure environments."
                    " Works only with p2pkh ('1') or p2sh-p2wpkh (segwit '3')"
                    " utxos - set segwit=False in the POLICY section of"
                    " joinmarket.cfg for the former."
    )
    parser.add_option(
        '-t',
        '--utxo-address-type',
        action='store',
        dest='utxo_address_type',
        help=('type of address of coin being spent - one of "p2pkh", "p2wpkh", "p2sh-p2wpkh". '
        'No other scriptpubkey types (e.g. multisig) are supported. If not set, we default '
        'to what is in joinmarket.cfg.'),
        default=""
    )
    add_base_options(parser)
    (options, args) = parser.parse_args()
    load_program_config(config_path=options.datadir)
    if len(args) < 2:
        quit(parser, 'Invalid syntax')
    u = args[0]
    priv = input(
        'input private key for ' + u + ', in WIF compressed format : ')
    u, priv = get_utxo_info(','.join([u, priv]))
    if not u:
        quit(parser, "Failed to parse utxo info: " + u)
    destaddrs = args[1:]
    for d in destaddrs:
        if not validate_address(d):
            quit(parser, "Address was not valid; wrong network?: " + d)
    success, utxo = utxostr_to_utxo(u)
    if not success:
        quit(parser, "Failed to load utxo from string: " + utxo)
    if options.utxo_address_type == "":
        if jm_single().config.get("POLICY", "segwit") == "false":
            utxo_address_type = "p2pkh"
        elif jm_single().config.get("POLICY", "native") == "false":
            utxo_address_type = "p2sh-p2wpkh"
        else:
            utxo_address_type = "p2wpkh"
    else:
        utxo_address_type = options.utxo_address_type
    txsigned = sign(utxo, priv, destaddrs, utxo_address_type)
    if not txsigned:
        log.info("Transaction signing operation failed, see debug messages for details.")
        return
    log.info("Got signed transaction:\n" + bintohex(txsigned.serialize()))
    log.info(btc.human_readable_transaction(txsigned))
    if input('Would you like to push to the network? (y/n):')[0] != 'y':
        log.info("You chose not to broadcast the transaction, quitting.")
        return
    jm_single().bc_interface.pushtx(txsigned.serialize())
示例#11
0
def main() -> None:
    parser = OptionParser(
        usage="usage: %prog [options] UTXO or amount",
        description=DESCRIPTION,
    )
    add_base_options(parser)
    parser.add_option(
        "-i",
        "--interest",
        action="store",
        type="float",
        dest="interest",
        help=
        "Interest rate to use for fidelity bond calculation (instead of interest_rate config)",
    )
    parser.add_option(
        "-e",
        "--exponent",
        action="store",
        type="float",
        dest="exponent",
        help=
        "Exponent to use for fidelity bond calculation (instead of bond_value_exponent config)",
    )
    parser.add_option(
        "-m",
        "--months",
        action="store",
        type="int",
        dest="months",
        help=
        "For how many months to calculate the fidelity bond values, each month has its own stats (default 12)",
        default=12,
    )
    parser.add_option(
        "-o",
        "--orderbook",
        action="store",
        type="str",
        dest="path_to_json",
        help="Path to the exported orderbook in JSON format",
    )

    options, args = parser.parse_args()
    load_program_config(config_path=options.datadir)
    if len(args) != 1:
        log.error("Invalid arguments, see --help")
        sys.exit(EXIT_ARGERROR)
    if options.path_to_json:
        try:
            with open(options.path_to_json, "r",
                      encoding="UTF-8") as orderbook:
                orderbook = loads(orderbook.read())
        except FileNotFoundError as exc:
            log.error(exc)
            sys.exit(EXIT_ARGERROR)
    else:
        orderbook = None
    try:
        amount = amount_to_sat(args[0])
        confirm_time = None
    except ValueError:
        # If it's not a valid amount then it has to be a UTXO
        if jm_single().bc_interface is None:
            log.error(
                "For calculation based on UTXO access to Bitcoin Core is required"
            )
            sys.exit(EXIT_FAILURE)
        success, utxo = utxostr_to_utxo(args[0])
        if not success:
            # utxo contains the error message
            log.error(utxo)
            sys.exit(EXIT_ARGERROR)
        utxo_data = jm_single().bc_interface.query_utxo_set(
            utxo, includeconfs=True)[0]
        amount = utxo_data["value"]
        if utxo_data["confirms"] == 0:
            log.warning(
                "Given UTXO is unconfirmed, current time will be used as confirmation time"
            )
            confirm_time = None
        elif utxo_data["confirms"] < 0:
            log.error("Given UTXO is invalid, reason: conflicted")
            sys.exit(EXIT_ARGERROR)
        else:
            current_height = jm_single().bc_interface.get_current_block_height(
            )
            block_hash = jm_single().bc_interface.get_block_hash(
                current_height - utxo_data["confirms"] + 1)
            confirm_time = jm_single().bc_interface.get_block_time(block_hash)

    parameters, results = get_bond_values(amount, options.months, confirm_time,
                                          options.interest, options.exponent,
                                          orderbook)
    jmprint(f"Amount locked: {amount} ({sat_to_btc(amount)} btc)")
    jmprint(
        f"Confirmation time: {datetime.fromtimestamp(parameters['confirm_time'])}"
    )
    jmprint(
        f"Interest rate: {parameters['interest']} ({parameters['interest'] * 100}%)"
    )
    jmprint(f"Exponent: {parameters['exponent']}")
    jmprint(f"\nFIDELITY BOND VALUES (BTC^{parameters['exponent']})")
    jmprint("\nSee /docs/fidelity-bonds.md for complete formula and more")

    for result in results:
        locktime = datetime.fromtimestamp(result["locktime"])
        # Mimic the locktime value the user would have to insert to create such fidelity bond
        jmprint(f"\nLocktime: {locktime.year}-{locktime.month}")
        # Mimic orderbook value
        jmprint(
            f"Bond value: {float(Decimal(result['value']) / Decimal(1e16)):.16f}"
        )
        if options.path_to_json:
            jmprint(
                f"Weight: {result['weight']:.5f} ({result['weight'] * 100:.2f}% of all bonds)"
            )
            jmprint(f"Top {result['percentile']}% of the orderbook by value")
def main():
    parser = OptionParser(
        usage='usage: %prog [options] utxo destaddr1 destaddr2 ..',
        description=
        "For creating multiple utxos from one (for commitments in JM)."
        "Provide a utxo in form txid:N that has some unspent coins;"
        "Specify a list of destination addresses and the coins will"
        "be split equally between them (after bitcoin fees)."
        "You'll be prompted to enter the private key for the utxo"
        "during the run; it must be in WIF compressed format."
        "After the transaction is completed, the utxo strings for"
        "the new outputs will be shown."
        "Note that these utxos will not be ready for use as external"
        "commitments in Joinmarket until 5 confirmations have passed."
        " BE CAREFUL about handling private keys!"
        " Don't do this in insecure environments."
        " Works only with p2pkh ('1') or p2sh-p2wpkh (segwit '3')"
        " utxos - set segwit=False in the POLICY section of"
        " joinmarket.cfg for the former.")
    parser.add_option(
        '-v',
        '--validate-utxos',
        action='store_true',
        dest='validate',
        help='validate the utxos and pubkeys provided against the blockchain',
        default=False)
    parser.add_option(
        '-o',
        '--validate-only',
        action='store_true',
        dest='vonly',
        help='only validate the provided utxos (file or command line), not add',
        default=False)
    parser.add_option(
        '-n',
        '--non-segwit-input',
        action='store_true',
        dest='nonsegwit',
        help=
        'input is p2pkh ("1" address), not segwit; if not used, input is assumed to be segwit type.',
        default=False)
    add_base_options(parser)
    (options, args) = parser.parse_args()
    load_program_config(config_path=options.datadir)
    if len(args) < 2:
        quit(parser, 'Invalid syntax')
    u = args[0]
    priv = input('input private key for ' + u +
                 ', in WIF compressed format : ')
    u, priv = get_utxo_info(','.join([u, priv]))
    if not u:
        quit(parser, "Failed to parse utxo info: " + u)
    destaddrs = args[1:]
    for d in destaddrs:
        if not validate_address(d):
            quit(parser, "Address was not valid; wrong network?: " + d)
    success, utxo = utxostr_to_utxo(u)
    if not success:
        quit(parser, "Failed to load utxo from string: " + utxo)
    txsigned = sign(utxo, priv, destaddrs, segwit=not options.nonsegwit)
    if not txsigned:
        log.info(
            "Transaction signing operation failed, see debug messages for details."
        )
        return
    log.info("Got signed transaction:\n" + bintohex(txsigned.serialize()))
    log.debug("Deserialized:")
    log.debug(pformat(str(txsigned)))
    if input('Would you like to push to the network? (y/n):')[0] != 'y':
        log.info("You chose not to broadcast the transaction, quitting.")
        return
    jm_single().bc_interface.pushtx(txsigned.serialize())