Beispiel #1
0
def test_sign_standard_txs(addrtype):
    # liberally copied from python-bitcoinlib tests,
    # in particular see:
    # https://github.com/petertodd/python-bitcoinlib/pull/227

    # Create the (in)famous correct brainwallet secret key.
    priv = hashlib.sha256(b'correct horse battery staple').digest() + b"\x01"
    pub = btc.privkey_to_pubkey(priv)

    # Create an address from that private key.
    # (note that the input utxo is fake so we are really only creating
    # a destination here).
    scriptPubKey = btc.CScript([btc.OP_0, btc.Hash160(pub)])
    address = btc.P2WPKHCoinAddress.from_scriptPubKey(scriptPubKey)

    # Create a dummy outpoint; use same 32 bytes for convenience
    txid = priv[:32]
    vout = 2
    amount = btc.coins_to_satoshi(float('0.12345'))

    # Calculate an amount for the upcoming new UTXO. Set a high fee to bypass
    # bitcoind minfee setting.
    amount_less_fee = int(amount - btc.coins_to_satoshi(0.01))

    # Create a destination to send the coins.
    destination_address = address
    target_scriptPubKey = scriptPubKey

    # Create the unsigned transaction.
    txin = btc.CTxIn(btc.COutPoint(txid[::-1], vout))
    txout = btc.CTxOut(amount_less_fee, target_scriptPubKey)
    tx = btc.CMutableTransaction([txin], [txout])

    # Calculate the signature hash for the transaction. This is then signed by the
    # private key that controls the UTXO being spent here at this txin_index.
    if addrtype == "p2wpkh":
        sig, msg = btc.sign(tx, 0, priv, amount=amount, native="p2wpkh")
    elif addrtype == "p2sh-p2wpkh":
        sig, msg = btc.sign(tx, 0, priv, amount=amount, native=False)
    elif addrtype == "p2pkh":
        sig, msg = btc.sign(tx, 0, priv)
    else:
        assert False
    if not sig:
        print(msg)
        raise
    print("created signature: ", bintohex(sig))
    print("serialized transaction: {}".format(bintohex(tx.serialize())))
    print("deserialized transaction: {}\n".format(
        btc.human_readable_transaction(tx)))
def test_spend_then_rbf(setup_tx_creation):
    """ Test plan: first, create a normal spend with
    rbf enabled in direct_send, then broadcast but
    do not mine a block. Then create a re-spend of
    the same utxos with a higher fee and check
    that broadcast succeeds.
    """
    # First phase: broadcast with RBF enabled.
    #
    # set a baseline feerate:
    old_feerate = jm_single().config.get("POLICY", "tx_fees")
    jm_single().config.set("POLICY", "tx_fees", "20000")
    # set up a single wallet with some coins:
    wallet_service = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    # ensure selection of two utxos, doesn't really matter
    # but a more general case than only one:
    amount = 350000000
    # destination doesn't matter; this is easiest:
    destn = wallet_service.get_internal_addr(1)
    # While `direct_send` usually encapsulates utxo selection
    # for user, here we need to know what was chosen, hence
    # we return the transaction object, not directly broadcast.
    tx1 = direct_send(wallet_service,
                      amount,
                      0,
                      destn,
                      answeryes=True,
                      return_transaction=True,
                      optin_rbf=True)
    assert tx1
    # record the utxos for reuse:
    assert isinstance(tx1, bitcoin.CTransaction)
    utxos_objs = (x.prevout for x in tx1.vin)
    utxos = [(x.hash[::-1], x.n) for x in utxos_objs]
    # in order to sign on those utxos, we need their script and value.
    scrs = {}
    vals = {}
    for u, details in wallet_service.get_utxos_by_mixdepth()[0].items():
        if u in utxos:
            scrs[u] = details["script"]
            vals[u] = details["value"]
    assert len(scrs.keys()) == 2
    assert len(vals.keys()) == 2

    # This will go to mempool but not get mined because
    # we don't call `tick_forward_chain`.
    push_succeed = jm_single().bc_interface.pushtx(tx1.serialize())
    if push_succeed:
        # mimics real operations with transaction monitor:
        wallet_service.process_new_tx(tx1)
    else:
        assert False

    # Second phase: bump fee.
    #
    # we set a larger fee rate.
    jm_single().config.set("POLICY", "tx_fees", "30000")
    # just a different destination to avoid confusion:
    destn2 = wallet_service.get_internal_addr(2)
    # We reuse *both* utxos so total fees are comparable
    # (modulo tiny 1 byte differences in signatures).
    # Ordinary wallet operations would remove the first-spent utxos,
    # so for now we build a PSBT using the code from #921 to select
    # the same utxos (it could be done other ways).
    # Then we broadcast the PSBT and check it is allowed

    # before constructing the outputs, we need a good fee estimate,
    # using the bumped feerate:
    fee = estimate_tx_fee(2, 2, wallet_service.get_txtype())
    # reset the feerate:
    total_input_val = sum(vals.values())
    jm_single().config.set("POLICY", "tx_fees", old_feerate)
    outs = [{
        "address": destn2,
        "value": 1000000
    }, {
        "address": wallet_service.get_internal_addr(0),
        "value": total_input_val - 1000000 - fee
    }]
    tx2 = bitcoin.mktx(utxos, outs, version=2, locktime=compute_tx_locktime())
    spent_outs = []
    for u in utxos:
        spent_outs.append(bitcoin.CTxOut(nValue=vals[u], scriptPubKey=scrs[u]))
    psbt_unsigned = wallet_service.create_psbt_from_tx(tx2,
                                                       spent_outs=spent_outs)
    signresultandpsbt, err = wallet_service.sign_psbt(
        psbt_unsigned.serialize(), with_sign_result=True)
    assert not err
    signresult, psbt_signed = signresultandpsbt
    tx2_signed = psbt_signed.extract_transaction()
    # the following assertion is sufficient, because
    # tx broadcast would fail if the replacement were
    # not allowed by Core:
    assert jm_single().bc_interface.pushtx(tx2_signed.serialize())