Exemple #1
0
def sign(txdata, signatories):
    tx = txutil.from_hex(txdata['tx'])
    for i in range(wally.tx_get_num_inputs(tx)):
        script = wally.hex_to_bytes(txdata['prevout_scripts'][i])
        script_type = txdata['prevout_script_types'][i]
        flags, value, sighash = 0, 0, wally.WALLY_SIGHASH_ALL

        if script_type == gaconstants.P2SH_P2WSH_FORTIFIED_OUT:
            flags = wally.WALLY_TX_FLAG_USE_WITNESS
            value = int(txdata['prevout_values'][i])
        preimage_hash = wally.tx_get_btc_signature_hash(
            tx, i, script, value, sighash, flags)

        sigs = [s.get_signature(preimage_hash) for s in signatories]

        if script_type == gaconstants.P2SH_P2WSH_FORTIFIED_OUT:
            txutil.set_witness(
                tx, i, [None, _to_der(sigs[0]),
                        _to_der(sigs[1]), script])
            flags = wally.WALLY_SCRIPT_SHA256 | wally.WALLY_SCRIPT_AS_PUSH
            script = wally.witness_program_from_bytes(script, flags)
        else:
            sigs = sigs[0] + sigs[1]
            script = wally.scriptsig_multisig_from_bytes(
                script, sigs, [sighash, sighash], 0)
        wally.tx_set_input_script(tx, i, script)

    return tx
Exemple #2
0
def test_recover_2of3(mock_bitcoincore):
    """Test 2of3 happy path"""
    mock_bitcoincore.return_value = AuthServiceProxy('testnet_txs')

    estimate = {'blocks': 3, 'feerate': 1, }
    mock_bitcoincore.return_value.estimatesmartfee.return_value = estimate

    destination_address = 'mynHfTyTWyGGB76NBFbfUrTnn8YWQkTJVs'
    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_6.txt')),
        '--rpcuser=abc',
        '--rpcpassword=abc',
        '2of3',
        '--recovery-mnemonic-file={}'.format(datafile('mnemonic_7.txt')),
        '--rescan',
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
        '--destination-address={}'.format(destination_address),
    ]

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of3_5")).read().strip()

    # Check replace by fee is set
    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1
    assert wally.tx_get_input_sequence(tx, 0) == int(32*'1', 2) - 2

    # Summary
    args = ['--show-summary', ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1
    assert summary[0]['destination address'] == destination_address
Exemple #3
0
def main():
    parser = argparse.ArgumentParser(description="Verify Elements Commitments")
    parser.add_argument("--tx", type=argparse.FileType("r"), required=True)
    parser.add_argument("--blinded",
                        type=argparse.FileType("r"),
                        required=True)
    parser.add_argument("--input-txs", type=argparse.FileType("r"), nargs="+")

    args = parser.parse_args()
    tx = parse_tx_file(args.tx)
    inputs_unblinded, outputs_unblinded = parse_blinded_file(args.blinded)
    input_txs_map = parse_input_txs(args.input_txs)

    ret = {
        "txid": b2h_rev(wally.sha256d(wally.tx_to_bytes(tx, 0))),
        "inputs": [],
        "outputs": [],
    }

    for inp_idx in range(wally.tx_get_num_inputs(tx)):
        input_unblinded = inputs_unblinded.get(inp_idx)
        if not input_unblinded:
            continue
        prev_txid = wally.tx_get_input_txhash(tx, inp_idx)
        prev_vout = wally.tx_get_input_index(tx, inp_idx)
        prev_tx = input_txs_map.get(bytes(prev_txid))
        if not prev_tx:
            continue
        asset_commitment_bin = wally.tx_get_output_asset(prev_tx, prev_vout)
        amount_commitment_bin = wally.tx_get_output_value(prev_tx, prev_vout)
        if asset_commitment_bin != input_unblinded["asset_commitment_bin"]:
            continue
        i = {"vin": inp_idx}
        # TODO: fill also if unblinded
        if input_unblinded.get("asset_id_hex"):
            i["asset"] = input_unblinded["asset_id_hex"]
        if amount_commitment_bin == input_unblinded["amount_commitment_bin"]:
            i["satoshi"] = input_unblinded["amount_satoshi"]

        ret["inputs"].append(i)

    for out_idx in range(wally.tx_get_num_outputs(tx)):
        output_unblinded = outputs_unblinded.get(out_idx)
        if not output_unblinded:
            continue
        asset_commitment_bin = wally.tx_get_output_asset(tx, out_idx)
        amount_commitment_bin = wally.tx_get_output_value(tx, out_idx)
        if asset_commitment_bin != output_unblinded["asset_commitment_bin"]:
            continue
        o = {"vout": out_idx}
        # TODO: fill also if unblinded
        if output_unblinded.get("asset_id_hex"):
            o["asset"] = output_unblinded["asset_id_hex"]
        if amount_commitment_bin == output_unblinded["amount_commitment_bin"]:
            o["satoshi"] = output_unblinded["amount_satoshi"]

        ret["outputs"].append(o)

    print(json.dumps(ret, indent=2))
Exemple #4
0
def verify_txs(txs, utxos, expect_witness):

    txs = [txutil.from_hex(tx) for tx in txs]

    for tx in txs:
        assert wally.tx_get_num_inputs(tx) == 1
        assert wally.tx_get_num_outputs(tx) >= 1
        if expect_witness:
            assert wally.tx_get_witness_count(tx) == 1
        else:
            assert wally.tx_get_witness_count(tx) == 0
        wally.tx_get_total_output_satoshi(tx)  # Throws if total overflows

    assert len(utxos) > 0
    for idx, utxo in enumerate(utxos):
        tx = txs[idx]
        spending_tx = txutil.from_hex(''.join(utxo.split()))
Exemple #5
0
    def fixup_old_nlocktimes(self):
        """Fixup data from old format nlocktimes files

        Older nlocktimes files do not contain explicit prevout_signatures, prevout_scripts or
        prevout_script_types. Detect this and extract them from the raw transaction to make the
        txdata look consistent to the rest of the code. Note that segwit is not being handled
        here because old style nlocktimes predate segwit
        """
        for txdata in self.txdata:
            if 'prevout_signatures' not in txdata:
                tx = txutil.from_hex(txdata['tx'])
                txdata['prevout_script_types'] = []
                txdata['prevout_signatures'] = []
                txdata['prevout_scripts'] = []
                for i in range(wally.tx_get_num_inputs(tx)):
                    inp = wally.tx_get_input_script(tx, i)
                    ga_signature = wally.hex_from_bytes(inp[2:inp[1]+2])
                    redeem_script = wally.hex_from_bytes(inp[-71:])
                    txdata['prevout_signatures'].append(ga_signature)
                    txdata['prevout_scripts'].append(redeem_script)
                    txdata['prevout_script_types'].append(gaconstants.P2SH_FORTIFIED_OUT)
def test_recover_2of2_csv(mock_bitcoincore):
    """Test 2of2-csv happy path"""
    mock_bitcoincore.return_value = AuthServiceProxy('testnet_txs')

    estimate = {
        'blocks': 3,
        'feerate': decimal.Decimal('0.00001'),
    }
    mock_bitcoincore.return_value.estimatesmartfee.return_value = estimate
    mock_bitcoincore.return_value.getnetworkinfo = mock.Mock(
        return_value={'version': 190100})
    mock_bitcoincore.return_value.getblockcount.return_value = 144

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_1.txt')),
        '--rpcuser=abc',
        '--rpcpassword=abc',
        '2of2-csv',
        '--network=testnet',
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
    ]

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of2_csv_1")).read().strip()

    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1

    # Summary
    args = [
        '--show-summary',
    ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1

    # Use scantxoutset instead of importmulti + listunspent
    scantxoutset_result = {
        'success':
        True,
        'unspents': [{
            'txid':
            '0ab5d70ef25a601de455155fdcb8c492d21a9b3063211dc8a969568d9d0fe15b',
            'vout': 0,
            'scriptPubKey': 'a91458ce12e1773dd078940a9dc855b94c3c9a343b8587',
            'desc': 'addr(2N1LnKRLTCWr8H9UdwoREazuFDXHMEgZj9g)#ztm9gzsm',
            'amount': 0.001,
            'height': 0,
        }],
    }
    mock_bitcoincore.return_value.scantxoutset = mock.Mock(
        return_value=scantxoutset_result)
    # output not expired yet
    mock_bitcoincore.return_value.getblockcount.return_value = 143

    args = [
        '--mnemonic-file={}'.format(datafile('mnemonic_1.txt')),
        '--rpcuser=abc',
        '--rpcpassword=abc',
        '2of2-csv',
        '--network=testnet',
        '--key-search-depth={}'.format(key_depth),
        '--search-subaccounts={}'.format(sub_depth),
        '--ignore-mempool',
    ]

    # Raw tx
    raw_tx = get_output(args).strip()
    assert raw_tx == ''

    # output expired
    mock_bitcoincore.return_value.getblockcount.return_value = 144

    # Raw tx
    output = get_output(args).strip()
    assert output == open(datafile("signed_2of2_csv_1")).read().strip()

    # Check replace by fee is set
    tx = txutil.from_hex(output)
    assert wally.tx_get_num_inputs(tx) == 1

    # Summary
    args = [
        '--show-summary',
    ] + args
    output = get_output(args)
    summary = parse_summary(output)
    assert len(summary) == 1
Exemple #7
0
 def num_inputs(self) -> int:
     return wally.tx_get_num_inputs(self.tx)