コード例 #1
0
def test_mktx(setup_tx_creation):
    """Testing exceptional conditions; not guaranteed
    to create valid tx objects"""
    #outpoint structure must be {"outpoint":{"hash":hash, "index": num}}
    ins = [{
        'outpoint': {
            "hash": x * 32,
            "index": 0
        },
        "script": "",
        "sequence": 4294967295
    } for x in ["a", "b", "c"]]
    pub = vpubs[0]
    addr = bitcoin.pubkey_to_address(pub, magicbyte=get_p2pk_vbyte())
    script = bitcoin.address_to_script(addr)
    outs = [
        script + ":1000", addr + ":2000", {
            "script": script,
            "value": 3000
        }
    ]
    tx = bitcoin.mktx(ins, outs)
    print(tx)
    #rewrite with invalid output
    outs.append({"foo": "bar"})
    with pytest.raises(Exception) as e_info:
        tx = bitcoin.mktx(ins, outs)
コード例 #2
0
def test_verify_tx_input(setup_tx_creation):
    priv = b"\xaa" * 32 + b"\x01"
    pub = bitcoin.privkey_to_pubkey(priv)
    script = bitcoin.pubkey_to_p2sh_p2wpkh_script(pub)
    addr = str(bitcoin.CCoinAddress.from_scriptPubKey(script))
    wallet_service = make_wallets(1, [[2, 0, 0, 0, 0]], 1)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    insfull = wallet_service.select_utxos(0, 110000000)
    outs = [{"address": addr, "value": 1000000}]
    ins = list(insfull.keys())
    tx = bitcoin.mktx(ins, outs)
    scripts = {0: (insfull[ins[0]]["script"], bitcoin.coins_to_satoshi(1))}
    success, msg = wallet_service.sign_tx(tx, scripts)
    assert success, msg
    # testing Joinmarket's ability to verify transaction inputs
    # of others: pretend we don't have a wallet owning the transaction,
    # and instead verify an input using the (sig, pub, scriptCode) data
    # that is sent by counterparties:
    cScrWit = tx.wit.vtxinwit[0].scriptWitness
    sig = cScrWit.stack[0]
    pub = cScrWit.stack[1]
    scriptSig = tx.vin[0].scriptSig
    tx2 = bitcoin.mktx(ins, outs)
    res = bitcoin.verify_tx_input(tx2,
                                  0,
                                  scriptSig,
                                  bitcoin.pubkey_to_p2wpkh_script(pub),
                                  amount=bitcoin.coins_to_satoshi(1),
                                  witness=bitcoin.CScriptWitness([sig, pub]))
    assert res
コード例 #3
0
def test_verify_tx_input(setup_tx_creation, signall, mktxlist):
    priv = "aa" * 32 + "01"
    addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte())
    wallet = make_wallets(1, [[2, 0, 0, 0, 0]], 1)[0]['wallet']
    sync_wallet(wallet)
    insfull = wallet.select_utxos(0, 110000000)
    print(insfull)
    if not mktxlist:
        outs = [{"address": addr, "value": 1000000}]
        ins = insfull.keys()
        tx = bitcoin.mktx(ins, outs)
    else:
        out1 = addr + ":1000000"
        ins0, ins1 = insfull.keys()
        print("INS0 is: " + str(ins0))
        print("INS1 is: " + str(ins1))
        tx = bitcoin.mktx(ins0, ins1, out1)
    desertx = bitcoin.deserialize(tx)
    print(desertx)
    if signall:
        privdict = {}
        for index, ins in enumerate(desertx['ins']):
            utxo = ins['outpoint']['hash'] + ':' + str(
                ins['outpoint']['index'])
            ad = insfull[utxo]['address']
            priv = wallet.get_key_from_addr(ad)
            privdict[utxo] = priv
        tx = bitcoin.signall(tx, privdict)
    else:
        for index, ins in enumerate(desertx['ins']):
            utxo = ins['outpoint']['hash'] + ':' + str(
                ins['outpoint']['index'])
            ad = insfull[utxo]['address']
            priv = wallet.get_key_from_addr(ad)
            if index % 2:
                tx = binascii.unhexlify(tx)
            tx = bitcoin.sign(tx, index, priv)
            if index % 2:
                tx = binascii.hexlify(tx)
    desertx2 = bitcoin.deserialize(tx)
    print(desertx2)
    sig, pub = bitcoin.deserialize_script(desertx2['ins'][0]['script'])
    print(sig, pub)
    pubscript = bitcoin.address_to_script(
        bitcoin.pubkey_to_address(pub, magicbyte=get_p2pk_vbyte()))
    sig = binascii.unhexlify(sig)
    pub = binascii.unhexlify(pub)
    sig_good = bitcoin.verify_tx_input(tx, 0, pubscript, sig, pub)
    assert sig_good
コード例 #4
0
def make_tx_add_notify():
    wallet_dict = make_wallets(1, [[1, 0, 0, 0, 0]], mean_amt=4, sdev_amt=0)[0]
    amount = 250000000
    txfee = 10000
    wallet = wallet_dict['wallet']
    sync_wallet(wallet)
    inputs = wallet.select_utxos(0, amount)
    ins = inputs.keys()
    input_value = sum([i['value'] for i in inputs.values()])
    output_addr = wallet.get_new_addr(1, 0)
    change_addr = wallet.get_new_addr(0, 1)
    outs = [{
        'value': amount,
        'address': output_addr
    }, {
        'value': input_value - amount - txfee,
        'address': change_addr
    }]
    tx = bitcoin.mktx(ins, outs)
    de_tx = bitcoin.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = inputs[utxo]['address']
        priv = wallet.get_key_from_addr(addr)
        tx = bitcoin.sign(tx, index, priv)

    unconfirm_called[0] = confirm_called[0] = False
    timeout_unconfirm_called[0] = timeout_confirm_called[0] = False
    jm_single().bc_interface.add_tx_notify(bitcoin.deserialize(tx),
                                           unconfirm_callback,
                                           confirm_callback, output_addr,
                                           timeout_callback)
    return tx
コード例 #5
0
def test_add_new_utxos(setup_wallet):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    wallet = get_populated_wallet(num=1)

    scripts = [
        wallet.get_new_script(x, BaseWallet.ADDRESS_TYPE_INTERNAL)
        for x in range(3)
    ]
    tx_scripts = list(scripts)
    tx = btc.mktx([(b"\x00" * 32, 2)], [{
        "address": wallet.script_to_addr(s),
        "value": 10**8
    } for s in tx_scripts])
    added = wallet.add_new_utxos(tx, 1)
    assert len(added) == len(scripts)

    added_scripts = {x['script'] for x in added.values()}
    for s in scripts:
        assert s in added_scripts

    balances = wallet.get_balance_by_mixdepth()
    assert balances[0] == 2 * 10**8
    assert balances[1] == 10**8
    assert balances[2] == 10**8
    assert len(balances) == wallet.max_mixdepth + 1
コード例 #6
0
def make_sign_and_push(ins_full,
                       wallet,
                       amount,
                       output_addr=None,
                       change_addr=None,
                       hashcode=btc.SIGHASH_ALL,
                       estimate_fee = False):
    """Utility function for easily building transactions
    from wallets
    """
    total = sum(x['value'] for x in ins_full.values())
    ins = list(ins_full.keys())
    #random output address and change addr
    output_addr = wallet.get_new_addr(1, 1) if not output_addr else output_addr
    change_addr = wallet.get_new_addr(1, 0) if not change_addr else change_addr
    fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000
    outs = [{'value': amount,
             'address': output_addr}, {'value': total - amount - fee_est,
                                       'address': change_addr}]

    de_tx = btc.deserialize(btc.mktx(ins, outs))
    scripts = {}
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        script = wallet.addr_to_script(ins_full[utxo]['address'])
        scripts[index] = (script, ins_full[utxo]['value'])
    binarize_tx(de_tx)
    de_tx = wallet.sign_tx(de_tx, scripts, hashcode=hashcode)
    #pushtx returns False on any error
    tx = binascii.hexlify(btc.serialize(de_tx)).decode('ascii')
    push_succeed = jm_single().bc_interface.pushtx(tx)
    if push_succeed:
        return btc.txhash(tx)
    else:
        return False
コード例 #7
0
def sign(utxo, priv, destaddrs, segwit=True):
    """Sign a tx sending the amount amt, from utxo utxo,
    equally to each of addresses in list destaddrs,
    after fees; the purpose is to create a large
    number of utxos. If segwit=True the (single) utxo is assumed to
    be of type segwit p2sh/p2wpkh.
    """
    results = validate_utxo_data([(utxo, priv)], retrieve=True, segwit=segwit)
    if not results:
        return False
    assert results[0][0] == utxo
    amt = results[0][1]
    ins = [utxo]
    # TODO extend to other utxo types
    txtype = 'p2sh-p2wpkh' if segwit else 'p2pkh'
    estfee = estimate_tx_fee(1, len(destaddrs), txtype=txtype)
    outs = []
    share = int((amt - estfee) / len(destaddrs))
    fee = amt - share * len(destaddrs)
    assert fee >= estfee
    log.info("Using fee: " + str(fee))
    for i, addr in enumerate(destaddrs):
        outs.append({'address': addr, 'value': share})
    unsigned_tx = btc.mktx(ins, outs)
    amtforsign = amt if segwit else None
    return btc.sign(unsigned_tx,
                    0,
                    btc.from_wif_privkey(priv, vbyte=get_p2pk_vbyte()),
                    amount=amtforsign)
コード例 #8
0
def create_tx_and_offerlist(cj_addr,
                            cj_change_addr,
                            other_output_scripts,
                            cj_script=None,
                            cj_change_script=None,
                            offertype='swreloffer'):
    assert len(other_output_scripts) % 2 == 0, "bug in test"

    cj_value = 100000000
    maker_total_value = cj_value * 3

    if cj_script is None:
        cj_script = btc.address_to_script(cj_addr)
    if cj_change_script is None:
        cj_change_script = btc.address_to_script(cj_change_addr)

    inputs = create_tx_inputs(3)
    outputs = create_tx_outputs(
        (cj_script, cj_value),
        (cj_change_script, maker_total_value - cj_value),  # cjfee=0, txfee=0
        *((script, cj_value + (i%2)*(50000000+i)) \
            for i, script in enumerate(other_output_scripts))
    )

    maker_utxos = [inputs[0]]

    tx = btc.deserialize(btc.mktx(inputs, outputs))
    offerlist = construct_tx_offerlist(cj_addr, cj_change_addr, maker_utxos,
                                       maker_total_value, cj_value, offertype)

    return tx, offerlist
コード例 #9
0
def test_spend_p2wpkh(setup_tx_creation):
    #make 3 p2wpkh outputs from 3 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 4)]
    pubs = [bitcoin.privkey_to_pubkey(priv) for priv in privs]
    scriptPubKeys = [bitcoin.pubkey_to_p2wpkh_script(pub) for pub in pubs]
    addresses = [str(bitcoin.CCoinAddress.from_scriptPubKey(
        spk)) for spk in scriptPubKeys]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wpkh_ins = []
    for i, addr in enumerate(addresses):
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full, wallet_service, amount, output_addr=addr)
        assert txid
        p2wpkh_ins.append((txid, 0))
        txhex = jm_single().bc_interface.get_transaction(txid)
        #wait for mining
        jm_single().bc_interface.tick_forward_chain(1)
    #random output address
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount*3 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wpkh_ins, outs)

    for i, priv in enumerate(privs):
        # sign each of 3 inputs; note that bitcoin.sign
        # automatically validates each signature it creates.
        sig, msg = bitcoin.sign(tx, i, priv, amount=amount, native="p2wpkh")
        if not sig:
            assert False, msg
    txid = jm_single().bc_interface.pushtx(tx.serialize())
    assert txid
コード例 #10
0
def create_single_acp_pair(utxo_in,
                           priv,
                           addr_out,
                           amount,
                           bump,
                           segwit=False):
    """Given a utxo and a signing key for it, and its amout in satoshis,
    sign a "transaction" consisting of only 1 input and one output, signed
    with single|acp sighash flags so it can be grafted into a bigger
    transaction.
    Also provide a destination address and a 'bump' value (so the creator
    can claim more output in the final transaction.
    Note that, for safety, bump *should* be positive if the recipient
    is untrusted, since otherwise they can waste your money by simply
    broadcasting this transaction without adding any inputs of their own.
    Returns the serialized 1 in, 1 out, and signed transaction.
    """
    assert bump >= 0, "Output of single|acp pair must be bigger than input for safety."
    out = {"address": addr_out, "value": amount + bump}
    tx = btc.mktx([utxo_in], [out])
    amt = amount if segwit else None
    return btc.sign(tx,
                    0,
                    priv,
                    hashcode=btc.SIGHASH_SINGLE | btc.SIGHASH_ANYONECANPAY,
                    amount=amt)
コード例 #11
0
def test_timelocked_output_signing(setup_wallet):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    ensure_bip65_activated()
    storage = VolatileStorage()
    SegwitLegacyWalletFidelityBonds.initialize(storage, get_network())
    wallet = SegwitLegacyWalletFidelityBonds(storage)

    index = 0
    timenumber = 0
    script = wallet.get_script_and_update_map(
        FidelityBondMixin.FIDELITY_BOND_MIXDEPTH,
        FidelityBondMixin.BIP32_TIMELOCK_ID, index, timenumber)
    utxo = fund_wallet_addr(wallet, wallet.script_to_addr(script))
    timestamp = wallet._time_number_to_timestamp(timenumber)

    tx = btc.mktx([utxo], [{
        "address":
        str(
            btc.CCoinAddress.from_scriptPubKey(
                btc.standard_scripthash_scriptpubkey(btc.Hash160(b"\x00")))),
        "value":
        10**8 - 9000
    }],
                  locktime=timestamp + 1)
    success, msg = wallet.sign_tx(tx, {0: (script, 10**8)})
    assert success, msg
    txout = jm_single().bc_interface.pushtx(tx.serialize())
    assert txout
コード例 #12
0
def test_add_new_utxos(setup_wallet):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    wallet = get_populated_wallet(num=1)

    scripts = [wallet.get_new_script(x, True) for x in range(3)]
    tx_scripts = list(scripts)
    tx_scripts.append(b'\x22' * 17)

    tx = btc.deserialize(
        btc.mktx(['0' * 64 + ':2'], [{
            'script': hexlify(s).decode('ascii'),
            'value': 10**8
        } for s in tx_scripts]))
    binarize_tx(tx)
    txid = b'\x01' * 32
    added = wallet.add_new_utxos_(tx, txid)
    assert len(added) == len(scripts)

    added_scripts = {x['script'] for x in added.values()}
    for s in scripts:
        assert s in added_scripts

    balances = wallet.get_balance_by_mixdepth()
    assert balances[0] == 2 * 10**8
    assert balances[1] == 10**8
    assert balances[2] == 10**8
    assert len(balances) == wallet.max_mixdepth + 1
コード例 #13
0
def test_remove_old_utxos(setup_wallet):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    wallet = get_populated_wallet()

    # add some more utxos to mixdepth 1
    for i in range(3):
        txin = jm_single().bc_interface.grab_coins(wallet.get_internal_addr(1),
                                                   1)
        wallet.add_utxo(unhexlify(txin), 0, wallet.get_script(1, 1, i), 10**8)

    inputs = wallet.select_utxos_(0, 10**8)
    inputs.update(wallet.select_utxos_(1, 2 * 10**8))
    assert len(inputs) == 3

    tx_inputs = list(inputs.keys())
    tx_inputs.append((b'\x12' * 32, 6))

    tx = btc.deserialize(
        btc.mktx([
            '{}:{}'.format(hexlify(txid).decode('ascii'), i)
            for txid, i in tx_inputs
        ], ['0' * 36 + ':' + str(3 * 10**8 - 1000)]))
    binarize_tx(tx)

    removed = wallet.remove_old_utxos_(tx)
    assert len(removed) == len(inputs)

    for txid in removed:
        assert txid in inputs

    balances = wallet.get_balance_by_mixdepth()
    assert balances[0] == 2 * 10**8
    assert balances[1] == 10**8
    assert balances[2] == 0
    assert len(balances) == wallet.max_mixdepth + 1
コード例 #14
0
def test_spend_p2sh_utxos(setup_tx_creation):
    #make a multisig address from 3 privs
    privs = [chr(x) * 32 + '\x01' for x in range(1, 4)]
    pubs = [
        bitcoin.privkey_to_pubkey(binascii.hexlify(priv)) for priv in privs
    ]
    script = bitcoin.mk_multisig_script(pubs, 2)
    msig_addr = bitcoin.scriptaddr(script, magicbyte=196)
    #pay into it
    wallet = make_wallets(1, [[2, 0, 0, 0, 1]], 3)[0]['wallet']
    sync_wallet(wallet)
    amount = 350000000
    ins_full = wallet.select_utxos(0, amount)
    txid = make_sign_and_push(ins_full, wallet, amount, output_addr=msig_addr)
    assert txid
    #wait for mining
    time.sleep(1)
    #spend out; the input can be constructed from the txid of previous
    msig_in = txid + ":0"
    ins = [msig_in]
    #random output address and change addr
    output_addr = wallet.get_new_addr(1, 1)
    amount2 = amount - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(ins, outs)
    sigs = []
    for priv in privs[:2]:
        sigs.append(bitcoin.multisign(tx, 0, script, binascii.hexlify(priv)))
    tx = bitcoin.apply_multisignatures(tx, 0, script, sigs)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
コード例 #15
0
def test_remove_old_utxos(setup_wallet):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    wallet = get_populated_wallet()

    # add some more utxos to mixdepth 1
    for i in range(3):
        txin = jm_single().bc_interface.grab_coins(
            wallet.get_internal_addr(1), 1)
        wallet.add_utxo(btc.x(txin), 0, wallet.get_script(1,
                    BaseWallet.ADDRESS_TYPE_INTERNAL, i), 10**8, 1)

    inputs = wallet.select_utxos(0, 10**8)
    inputs.update(wallet.select_utxos(1, 2 * 10**8))
    assert len(inputs) == 3

    tx_inputs = list(inputs.keys())
    tx_inputs.append((b'\x12'*32, 6))

    tx = btc.mktx(tx_inputs,
        [{"address": "2N9gfkUsFW7Kkb1Eurue7NzUxUt7aNJiS1U",
          "value": 3 * 10**8 - 1000}])

    removed = wallet.remove_old_utxos(tx)
    assert len(removed) == len(inputs)

    for txid in removed:
        assert txid in inputs

    balances = wallet.get_balance_by_mixdepth()
    assert balances[0] == 2 * 10**8
    assert balances[1] == 10**8
    assert balances[2] == 0
    assert len(balances) == wallet.max_mixdepth + 1
コード例 #16
0
def test_spend_p2wsh(setup_tx_creation):
    #make 2 x 2 of 2multisig outputs; will need 4 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 5)]
    privs = [binascii.hexlify(priv).decode('ascii') for priv in privs]
    pubs = [bitcoin.privkey_to_pubkey(priv) for priv in privs]
    redeemScripts = [
        bitcoin.mk_multisig_script(pubs[i:i + 2], 2) for i in [0, 2]
    ]
    scriptPubKeys = [
        bitcoin.pubkeys_to_p2wsh_script(pubs[i:i + 2]) for i in [0, 2]
    ]
    addresses = [
        bitcoin.pubkeys_to_p2wsh_address(pubs[i:i + 2]) for i in [0, 2]
    ]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wsh_ins = []
    for addr in addresses:
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full,
                                  wallet_service,
                                  amount,
                                  output_addr=addr)
        assert txid
        p2wsh_ins.append(txid + ":0")
        #wait for mining
        time.sleep(1)
    #random output address and change addr
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount * 2 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wsh_ins, outs)
    sigs = []
    for i in range(2):
        sigs = []
        for priv in privs[i * 2:i * 2 + 2]:
            # sign input j with each of 2 keys
            sig = bitcoin.multisign(tx,
                                    i,
                                    redeemScripts[i],
                                    priv,
                                    amount=amount)
            sigs.append(sig)
            # check that verify_tx_input correctly validates;
            assert bitcoin.verify_tx_input(tx,
                                           i,
                                           scriptPubKeys[i],
                                           sig,
                                           bitcoin.privkey_to_pubkey(priv),
                                           scriptCode=redeemScripts[i],
                                           amount=amount)
        tx = bitcoin.apply_p2wsh_multisignatures(tx, i, redeemScripts[i], sigs)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
コード例 #17
0
def test_spend_p2wpkh(setup_tx_creation):
    #make 3 p2wpkh outputs from 3 privs
    privs = [struct.pack(b'B', x) * 32 + b'\x01' for x in range(1, 4)]
    pubs = [
        bitcoin.privkey_to_pubkey(binascii.hexlify(priv).decode('ascii'))
        for priv in privs
    ]
    scriptPubKeys = [bitcoin.pubkey_to_p2wpkh_script(pub) for pub in pubs]
    addresses = [bitcoin.pubkey_to_p2wpkh_address(pub) for pub in pubs]
    #pay into it
    wallet_service = make_wallets(1, [[3, 0, 0, 0, 0]], 3)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    amount = 35000000
    p2wpkh_ins = []
    for addr in addresses:
        ins_full = wallet_service.select_utxos(0, amount)
        txid = make_sign_and_push(ins_full,
                                  wallet_service,
                                  amount,
                                  output_addr=addr)
        assert txid
        p2wpkh_ins.append(txid + ":0")
        #wait for mining
        time.sleep(1)
    #random output address
    output_addr = wallet_service.get_internal_addr(1)
    amount2 = amount * 3 - 50000
    outs = [{'value': amount2, 'address': output_addr}]
    tx = bitcoin.mktx(p2wpkh_ins, outs)
    sigs = []
    for i, priv in enumerate(privs):
        # sign each of 3 inputs
        tx = bitcoin.p2wpkh_sign(tx,
                                 i,
                                 binascii.hexlify(priv),
                                 amount,
                                 native=True)
        # check that verify_tx_input correctly validates;
        # to do this, we need to extract the signature and get the scriptCode
        # of this pubkey
        scriptCode = bitcoin.pubkey_to_p2pkh_script(pubs[i])
        witness = bitcoin.deserialize(tx)['ins'][i]['txinwitness']
        assert len(witness) == 2
        assert witness[1] == pubs[i]
        sig = witness[0]
        assert bitcoin.verify_tx_input(tx,
                                       i,
                                       scriptPubKeys[i],
                                       sig,
                                       pubs[i],
                                       scriptCode=scriptCode,
                                       amount=amount)
    txid = jm_single().bc_interface.pushtx(tx)
    assert txid
コード例 #18
0
def test_create_and_sign_psbt_with_legacy(setup_psbt_wallet):
    """ The purpose of this test is to check that we can create and
    then partially sign a PSBT where we own one input and the other input
    is of legacy p2pkh type.
    """
    wallet_service = make_wallets(1, [[1, 0, 0, 0, 0]], 1)[0]['wallet']
    wallet_service.sync_wallet(fast=True)
    utxos = wallet_service.select_utxos(0, bitcoin.coins_to_satoshi(0.5))
    assert len(utxos) == 1
    # create a legacy address and make a payment into it
    legacy_addr = bitcoin.CCoinAddress.from_scriptPubKey(
        bitcoin.pubkey_to_p2pkh_script(bitcoin.privkey_to_pubkey(b"\x01" *
                                                                 33)))
    tx = direct_send(wallet_service,
                     bitcoin.coins_to_satoshi(0.3),
                     0,
                     str(legacy_addr),
                     accept_callback=dummy_accept_callback,
                     info_callback=dummy_info_callback,
                     return_transaction=True)
    assert tx
    # this time we will have one utxo worth <~ 0.7
    my_utxos = wallet_service.select_utxos(0, bitcoin.coins_to_satoshi(0.5))
    assert len(my_utxos) == 1
    # find the outpoint for the legacy address we're spending
    n = -1
    for i, t in enumerate(tx.vout):
        if bitcoin.CCoinAddress.from_scriptPubKey(
                t.scriptPubKey) == legacy_addr:
            n = i
    assert n > -1
    utxos = copy.deepcopy(my_utxos)
    utxos[(tx.GetTxid()[::-1], n)] = {
        "script": legacy_addr.to_scriptPubKey(),
        "value": bitcoin.coins_to_satoshi(0.3)
    }
    outs = [{
        "value": bitcoin.coins_to_satoshi(0.998),
        "address": wallet_service.get_addr(0, 0, 0)
    }]
    tx2 = bitcoin.mktx(list(utxos.keys()), outs)
    spent_outs = wallet_service.witness_utxos_to_psbt_utxos(my_utxos)
    spent_outs.append(tx)
    new_psbt = wallet_service.create_psbt_from_tx(tx2,
                                                  spent_outs,
                                                  force_witness_utxo=False)
    signed_psbt_and_signresult, err = wallet_service.sign_psbt(
        new_psbt.serialize(), with_sign_result=True)
    assert err is None
    signresult, signed_psbt = signed_psbt_and_signresult
    assert signresult.num_inputs_signed == 1
    assert signresult.num_inputs_final == 1
    assert not signresult.is_final
コード例 #19
0
def create_coinjoin_proposal(bobdata, alicedata, verbose=True, incentive=0):
    """A very crude/static implementation of a coinjoin for SNICKER.
    **VERY DELIBERATELY STUPIDLY SIMPLE VERSION!**
    We assume only one utxo for each side (this will certainly change, Alice
    side, for flexibility). Two outputs equal size are created with 1 change
    for Alice also (Bob's utxo is completely satisfied by 1 output).
    The data for each side is utxo, and amount; alice must provide
    privkey for partial sign. All scriptpubkeys assumed p2sh/p2wpkh for now.
    Bob's destination is tweaked and included as a destination which he
    will verify.
    What is returned is (tweak, partially signed tx) which is enough information
    for Bob to complete.
    """
    fee = estimate_tx_fee(2, 3, 'p2sh-p2wpkh')
    bob_utxo, bob_pubkey, amount = bobdata
    alice_utxo, alice_privkey, alice_amount, alice_destination, change = alicedata
    ins = [bob_utxo, alice_utxo]
    random.shuffle(ins)
    tweak, dest_pt, bob_destination = create_recipient_address(bob_pubkey,
                                                               segwit=True)
    print('using amount, alice_amount,incentive, fee: ' +
          ','.join([str(x) for x in [amount, alice_amount, incentive, fee]]))
    coinjoin_amount = amount + incentive
    change_amount = alice_amount - coinjoin_amount - incentive - fee
    outs = [{
        "address": alice_destination,
        "value": coinjoin_amount
    }, {
        "address": bob_destination,
        "value": coinjoin_amount
    }, {
        "address": change,
        "value": change_amount
    }]
    random.shuffle(outs)
    unsigned_tx = btc.mktx(ins, outs)
    if verbose:
        print('here is proposed transaction:\n',
              pformat(btc.deserialize(unsigned_tx)))
        print('destination for Bob: ', bob_destination)
        print('destination for Alice: ', alice_destination)
        print('destination for Alice change: ', change)
        if not raw_input("Is this acceptable? (y/n):") == "y":
            return (None, None)
    #Alice signs her input; assuming segwit here for now
    partially_signed_tx = btc.sign(unsigned_tx,
                                   1,
                                   alice_privkey,
                                   amount=alice_amount)
    #return the material to be sent to Bob
    return (tweak, partially_signed_tx)
コード例 #20
0
def make_sign_and_push(ins_full,
                       wallet_service,
                       amount,
                       output_addr=None,
                       change_addr=None,
                       hashcode=btc.SIGHASH_ALL,
                       estimate_fee=False):
    """Utility function for easily building transactions
    from wallets.
    `ins_full` should be a list of dicts in format returned
    by wallet.select_utxos:
    {(txid, index): {"script":..,"value":..,"path":..}}
    ... although the path is not used.
    The "script" and "value" data is used to allow signing.
    """
    assert isinstance(wallet_service, WalletService)
    total = sum(x['value'] for x in ins_full.values())
    ins = list(ins_full.keys())
    #random output address and change addr
    output_addr = wallet_service.get_new_addr(
        1,
        BaseWallet.ADDRESS_TYPE_INTERNAL) if not output_addr else output_addr
    change_addr = wallet_service.get_new_addr(
        0,
        BaseWallet.ADDRESS_TYPE_INTERNAL) if not change_addr else change_addr
    fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000
    outs = [{
        'value': amount,
        'address': output_addr
    }, {
        'value': total - amount - fee_est,
        'address': change_addr
    }]

    tx = btc.mktx(ins, outs)
    scripts = {}
    for i, j in enumerate(ins):
        scripts[i] = (ins_full[j]["script"], ins_full[j]["value"])

    success, msg = wallet_service.sign_tx(tx, scripts, hashcode=hashcode)
    if not success:
        return False
    #pushtx returns False on any error
    push_succeed = jm_single().bc_interface.pushtx(tx.serialize())
    if push_succeed:
        # in normal operation this happens automatically
        # but in some tests there is no monitoring loop:
        wallet_service.process_new_tx(tx)
        return tx.GetTxid()[::-1]
    else:
        return False
コード例 #21
0
def test_all_same_priv(setup_tx_creation):
    #recipient
    priv = "aa" * 32 + "01"
    addr = bitcoin.privkey_to_address(priv, magicbyte=get_p2pk_vbyte())
    wallet = make_wallets(1, [[1, 0, 0, 0, 0]], 1)[0]['wallet']
    #make another utxo on the same address
    addrinwallet = wallet.get_addr(0, 0, 0)
    jm_single().bc_interface.grab_coins(addrinwallet, 1)
    sync_wallet(wallet)
    insfull = wallet.select_utxos(0, 110000000)
    outs = [{"address": addr, "value": 1000000}]
    ins = insfull.keys()
    tx = bitcoin.mktx(ins, outs)
    tx = bitcoin.signall(tx, wallet.get_key_from_addr(addrinwallet))
コード例 #22
0
def test_signing_simple(setup_wallet, wallet_cls, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    wallet_cls.initialize(storage, get_network())
    wallet = wallet_cls(storage)
    utxo = fund_wallet_addr(wallet, wallet.get_internal_addr(0))
    tx = btc.deserialize(btc.mktx(['{}:{}'.format(hexlify(utxo[0]).decode('ascii'), utxo[1])],
                                  ['00'*17 + ':' + str(10**8 - 9000)]))
    binarize_tx(tx)
    script = wallet.get_script(0, 1, 0)
    wallet.sign_tx(tx, {0: (script, 10**8)})
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(hexlify(btc.serialize(tx)).decode('ascii'))
    assert txout
コード例 #23
0
def test_signing_simple(setup_wallet, wallet_cls, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    wallet_cls.initialize(storage, get_network())
    wallet = wallet_cls(storage)
    utxo = fund_wallet_addr(wallet, wallet.get_internal_addr(0))
    # The dummy output is constructed as an unspendable p2sh:
    tx = btc.deserialize(btc.mktx(['{}:{}'.format(
        hexlify(utxo[0]).decode('ascii'), utxo[1])],
        [btc.p2sh_scriptaddr(b"\x00",magicbyte=196) + ':' + str(10**8 - 9000)]))
    script = wallet.get_script(0, 1, 0)
    tx = wallet.sign_tx(tx, {0: (script, 10**8)})
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(btc.serialize(tx))
    assert txout
コード例 #24
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 = b"\xaa" * 32 + b"\x01"
        pub = 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)
        # cannot convert to address within wallet service, as not known
        # to wallet; use engine directly:
        addr = wallet_service._ENGINE.script_to_address(script_pub_key)

        #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, success = bitcoin.sign(tx,
                                    i,
                                    priv,
                                    amount=amount,
                                    native=redeem_script)
        assert success
        push_success = jm_single().bc_interface.pushtx(tx.serialize())
        assert push_success == required_success
コード例 #25
0
def test_signing_simple(setup_wallet, wallet_cls, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    wallet_cls.initialize(storage, get_network())
    wallet = wallet_cls(storage)
    utxo = fund_wallet_addr(wallet, wallet.get_internal_addr(0))
    # The dummy output is of length 25 bytes, because, for SegwitWallet, we else
    # trigger the tx-size-small DOS limit in Bitcoin Core (82 bytes is the
    # smallest "normal" transaction size (non-segwit size, ie no witness)
    tx = btc.deserialize(
        btc.mktx(['{}:{}'.format(hexlify(utxo[0]).decode('ascii'), utxo[1])],
                 ['00' * 25 + ':' + str(10**8 - 9000)]))
    script = wallet.get_script(0, 1, 0)
    tx = wallet.sign_tx(tx, {0: (script, 10**8)})
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(btc.serialize(tx))
    assert txout
コード例 #26
0
def test_signing_imported(setup_wallet, wif, keytype, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    SegwitLegacyWallet.initialize(storage, get_network())
    wallet = SegwitLegacyWallet(storage)

    MIXDEPTH = 0
    path = wallet.import_private_key(MIXDEPTH, wif, keytype)
    utxo = fund_wallet_addr(wallet, wallet.get_addr_path(path))
    tx = btc.deserialize(
        btc.mktx(['{}:{}'.format(hexlify(utxo[0]).decode('ascii'), utxo[1])],
                 ['00' * 17 + ':' + str(10**8 - 9000)]))
    script = wallet.get_script_path(path)
    tx = wallet.sign_tx(tx, {0: (script, 10**8)})
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(btc.serialize(tx))
    assert txout
コード例 #27
0
def test_signing_simple(setup_wallet, wallet_cls, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    wallet_cls.initialize(storage, get_network(), entropy=b"\xaa"*16)
    wallet = wallet_cls(storage)
    utxo = fund_wallet_addr(wallet, wallet.get_internal_addr(0))
    # The dummy output is constructed as an unspendable p2sh:
    tx = btc.mktx([utxo],
            [{"address": str(btc.CCoinAddress.from_scriptPubKey(
                btc.CScript(b"\x00").to_p2sh_scriptPubKey())),
              "value": 10**8 - 9000}])    
    script = wallet.get_script(0, BaseWallet.ADDRESS_TYPE_INTERNAL, 0)
    success, msg = wallet.sign_tx(tx, {0: (script, 10**8)})
    assert success, msg
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(tx.serialize())
    assert txout
コード例 #28
0
def make_sign_and_push(ins_full,
                       wallet_service,
                       amount,
                       output_addr=None,
                       change_addr=None,
                       hashcode=btc.SIGHASH_ALL,
                       estimate_fee=False):
    """Utility function for easily building transactions
    from wallets
    """
    assert isinstance(wallet_service, WalletService)
    total = sum(x['value'] for x in ins_full.values())
    ins = list(ins_full.keys())
    #random output address and change addr
    output_addr = wallet_service.get_new_addr(
        1, 1) if not output_addr else output_addr
    change_addr = wallet_service.get_new_addr(
        0, 1) if not change_addr else change_addr
    fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000
    outs = [{
        'value': amount,
        'address': output_addr
    }, {
        'value': total - amount - fee_est,
        'address': change_addr
    }]

    de_tx = btc.deserialize(btc.mktx(ins, outs))
    scripts = {}
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        script = wallet_service.addr_to_script(ins_full[utxo]['address'])
        scripts[index] = (script, ins_full[utxo]['value'])
    binarize_tx(de_tx)
    de_tx = wallet_service.sign_tx(de_tx, scripts, hashcode=hashcode)
    #pushtx returns False on any error
    push_succeed = jm_single().bc_interface.pushtx(btc.serialize(de_tx))
    if push_succeed:
        txid = btc.txhash(btc.serialize(de_tx))
        # in normal operation this happens automatically
        # but in some tests there is no monitoring loop:
        wallet_service.process_new_tx(de_tx, txid)
        return txid
    else:
        return False
コード例 #29
0
def make_sign_and_push(ins_full,
                       wallet_service,
                       amount,
                       output_addr=None,
                       change_addr=None,
                       hashcode=btc.SIGHASH_ALL,
                       estimate_fee=False):
    """Utility function for easily building transactions
    from wallets.
    """
    assert isinstance(wallet_service, WalletService)
    total = sum(x['value'] for x in ins_full.values())
    ins = ins_full.keys()
    #random output address and change addr
    output_addr = wallet_service.get_new_addr(
        1,
        BaseWallet.ADDRESS_TYPE_INTERNAL) if not output_addr else output_addr
    change_addr = wallet_service.get_new_addr(
        0,
        BaseWallet.ADDRESS_TYPE_INTERNAL) if not change_addr else change_addr
    fee_est = estimate_tx_fee(len(ins), 2) if estimate_fee else 10000
    outs = [{
        'value': amount,
        'address': output_addr
    }, {
        'value': total - amount - fee_est,
        'address': change_addr
    }]

    tx = btc.mktx(ins, outs)
    de_tx = btc.deserialize(tx)
    for index, ins in enumerate(de_tx['ins']):
        utxo = ins['outpoint']['hash'] + ':' + str(ins['outpoint']['index'])
        addr = ins_full[utxo]['address']
        priv = wallet_service.get_key_from_addr(addr)
        if index % 2:
            priv = binascii.unhexlify(priv)
        tx = btc.sign(tx, index, priv, hashcode=hashcode)
    #pushtx returns False on any error
    print(btc.deserialize(tx))
    push_succeed = jm_single().bc_interface.pushtx(tx)
    if push_succeed:
        return btc.txhash(tx)
    else:
        return False
コード例 #30
0
def test_signing_imported(setup_wallet, wif, keytype, type_check):
    jm_single().config.set('BLOCKCHAIN', 'network', 'testnet')
    storage = VolatileStorage()
    SegwitLegacyWallet.initialize(storage, get_network())
    wallet = SegwitLegacyWallet(storage)

    MIXDEPTH = 0
    path = wallet.import_private_key(MIXDEPTH, wif, keytype)
    utxo = fund_wallet_addr(wallet, wallet.get_address_from_path(path))
    # The dummy output is constructed as an unspendable p2sh:
    tx = btc.deserialize(btc.mktx(['{}:{}'.format(
        hexlify(utxo[0]).decode('ascii'), utxo[1])],
        [btc.p2sh_scriptaddr(b"\x00",magicbyte=196) + ':' + str(10**8 - 9000)]))
    script = wallet.get_script_from_path(path)
    tx = wallet.sign_tx(tx, {0: (script, 10**8)})
    type_check(tx)
    txout = jm_single().bc_interface.pushtx(btc.serialize(tx))
    assert txout