Ejemplo n.º 1
0
def dummy_op_return_tx(key, message, spendables, fee=10000):
    address = key.address()

    if len(message) > 80:
        raise ValueError("message must not be longer than 80 bytes")
    message = hexlify(message).decode()

    bitcoin_sum = sum(spendable.coin_value for spendable in spendables)
    if bitcoin_sum < fee:
        raise Exception("not enough bitcoin to cover fee")

    inputs = [spendable.tx_in() for spendable in spendables]

    outputs = []
    if bitcoin_sum > fee:
        change_output_script = standard_tx_out_script(address)
        outputs.append(TxOut(bitcoin_sum - fee, change_output_script))

    op_return_output_script = script.tools.compile('OP_RETURN %s' % message)
    outputs.append(TxOut(0, op_return_output_script))

    tx = Tx(version=1, txs_in=inputs, txs_out=outputs)
    tx.set_unspents(spendables)
    sign_tx(tx, wifs=[key.wif()])

    return tx
Ejemplo n.º 2
0
    def doit(num_ins, num_outs, master_xpub, subpath="0/%d", fee=10000):
        psbt = BasicPSBT()
        txn = Tx(2, [], [])

        # we have a key; use it to provide "plausible" value inputs
        from pycoin.key.BIP32Node import BIP32Node
        mk = BIP32Node.from_wallet_key(master_xpub)
        xfp = mk.fingerprint()

        psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)]
        psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)]

        for i in range(num_ins):
            # make a fake txn to supply each of the inputs
            # - each input is 1BTC

            # addr where the fake money will be stored.
            subkey = mk.subkey_for_path(subpath % i)
            sec = subkey.sec()
            assert len(sec) == 33, "expect compressed"
            assert subpath[0:2] == '0/'

            psbt.inputs[i].bip32_paths[sec] = xfp + pack('<II', 0, i)

            # UTXO that provides the funding for to-be-signed txn
            supply = Tx(2, [TxIn(pack('4Q', 0xdead, 0xbeef, 0, 0), 73)], [])

            scr = bytes([0x76, 0xa9, 0x14]) + subkey.hash160() + bytes(
                [0x88, 0xac])
            supply.txs_out.append(TxOut(1E8, scr))

            with BytesIO() as fd:
                supply.stream(fd)
                psbt.inputs[i].utxo = fd.getvalue()

            if 0:
                with BytesIO() as fd:
                    supply.stream(fd, include_witness_data=True)
                    psbt.inputs[i].witness_utxo = fd.getvalue()

            spendable = TxIn(supply.hash(), 0)
            txn.txs_in.append(spendable)

        for i in range(num_outs):
            # random P2PKH
            scr = bytes([0x76, 0xa9, 0x14]) + pack(
                'I', i + 1) + bytes(16) + bytes([0x88, 0xac])
            h = TxOut(round(((1E8 * num_ins) - fee) / num_outs, 4), scr)
            txn.txs_out.append(h)

        with BytesIO() as b:
            txn.stream(b)
            psbt.txn = b.getvalue()

        rv = BytesIO()
        psbt.serialize(rv)
        assert rv.tell() <= MAX_TXN_LEN, 'too fat'

        return rv.getvalue()
Ejemplo n.º 3
0
def op_return_this(privatekey, text, prefix = "KEYSTAMP:", bitcoin_fee = 10000):

    bitcoin_keyobj = get_key(privatekey)
    bitcoin_address = bitcoin_keyobj.bitcoin_address()

    ## Get the spendable outputs we are going to use to pay the fee
    all_spendables = get_spendables_blockcypher(bitcoin_address)
    spendables = []
    value = 0
    for unspent in all_spendables:
        while value < bitcoin_fee + 10000:
            coin_value = unspent.get("value")
            script = h2b(unspent.get("script_hex"))
            previous_hash = h2b_rev(unspent.get("tx_hash"))
            previous_index = unspent.get("index")
            spendables.append(Spendable(coin_value, script, previous_hash, previous_index))
            value += coin_value

    bitcoin_sum = sum(spendable.coin_value for spendable in spendables)
    if(bitcoin_sum < bitcoin_fee):
        print "ERROR: not enough balance: available: %s - fee: %s" %(bitcoin_sum, bitcoin_fee)
        return False

    ## Create the inputs we are going to use
    inputs = [spendable.tx_in() for spendable in spendables]
    ## If we will have change left over create an output to send it back
    outputs = []
    if (bitcoin_sum > bitcoin_fee):
        change_output_script = standard_tx_out_script(bitcoin_address)
        total_amout = bitcoin_sum - bitcoin_fee
        outputs.append(TxOut(total_amout, change_output_script))

        # home_address = standard_tx_out_script(bitcoin_address)
        # #TODO: it needs some love and IQ on input mananagement stuff
        # outputs.append(TxOut((bitcoin_sum - bitcoin_fee), home_address))

    ## Build the OP_RETURN output with our message
    if prefix is not None and (len(text) + len(prefix) <= 80):
        text = prefix + text

    message = hexlify(text.encode()).decode('utf8')

    op_return_output_script = tools.compile("OP_RETURN %s" % message)
    outputs.append(TxOut(0, op_return_output_script))

    ## Create the transaction and sign it with the private key
    tx = Tx(version=1, txs_in=inputs, txs_out=outputs)
    # print tx.as_hex()
    # print spendables
    tx.set_unspents(spendables)
    sign_tx(tx, wifs=[privatekey])

    print "singed_tx: %s" %tx.as_hex()

    #TODO: uncomment this when its ready to push data to blockchian
    tx_hash = broadcast_tx_blockr(tx.as_hex())
    return tx_hash
Ejemplo n.º 4
0
    def doit(num_ins, num_outs, fat=0):
        psbt = BasicPSBT()
        txn = Tx(2, [], [])

        for i in range(num_ins):
            h = TxIn(pack('4Q', 0, 0, 0, i), i)
            txn.txs_in.append(h)

        for i in range(num_outs):
            # random P2PKH
            scr = bytes([0x76, 0xa9, 0x14]) + pack(
                'I', i + 1) + bytes(16) + bytes([0x88, 0xac])
            h = TxOut((1E6 * i) if i else 1E8, scr)
            txn.txs_out.append(h)

        with BytesIO() as b:
            txn.stream(b)
            psbt.txn = b.getvalue()

        psbt.inputs = [BasicPSBTInput(idx=i) for i in range(num_ins)]
        psbt.outputs = [BasicPSBTOutput(idx=i) for i in range(num_outs)]

        if fat:
            for i in range(num_ins):
                psbt.inputs[i].utxo = os.urandom(fat)

        rv = BytesIO()
        psbt.serialize(rv)
        assert rv.tell() <= MAX_TXN_LEN, 'too fat'

        return rv.getvalue()
Ejemplo n.º 5
0
    def _create_bip69_tx(spendables: List[Spendable],
                         payables: List[Tuple[str, int]],
                         rbf: bool,
                         version: int = 1) -> Tx:
        spendables.sort(key=lambda utxo: (utxo.as_dict()["tx_hash_hex"],
                                          utxo.as_dict()["tx_out_index"]))

        # Create input list from utxos
        # Set sequence numbers to zero if using RBF.
        txs_in = [spendable.tx_in()
                  for spendable in spendables]  # type: List[TxIn]
        if rbf:
            logging.info("Spending with opt-in Replace by Fee! (RBF)")
            for txin in txs_in:
                txin.sequence = 0

        # Create output list from payables
        txs_out = list()  # type: List[TxOut]
        for payable in payables:
            bitcoin_address, coin_value = payable
            script = standard_tx_out_script(bitcoin_address)  # type: bytes
            txs_out.append(TxOut(coin_value, script))
        txs_out.sort(key=lambda txo: (txo.coin_value, b2h(txo.script)))

        tx = Tx(version=version, txs_in=txs_in, txs_out=txs_out)  # type: Tx
        tx.set_unspents(spendables)
        return tx
Ejemplo n.º 6
0
def nulldata_txout(hexdata):
    data = binary(hexdata)
    if len(data) > common.MAX_NULLDATA:
        raise exceptions.MaxNulldataExceeded(len(data), common.MAX_NULLDATA)
    script_text = "OP_RETURN %s" % b2h(data)
    script_bin = tools.compile(script_text)
    return TxOut(0, script_bin)
Ejemplo n.º 7
0
    def create_raw_transaction(inputs, outputs):
        coins_sources = []
        coins_to = []
        total_unspent = 0
        total_spent = 0

        for intx in inputs:
            tx_out = TxOut(intx['amount'], h2b(intx['scriptPubKey']))
            coins_source = (h2b(intx['txid'])[::-1], intx['vout'], tx_out)
            coins_sources.append(coins_source)
            total_unspent += intx['amount']

        for outtx in outputs:
            self.coins_to.append((outtx['amount'], address))
            total_spent += outtx['amount']

        fee = total_unspent - total_spent

        if fee < 0:
            message = "not enough source coins (%s BTC) for destination (%s BTC). Short %s BTC" % (
                satoshi_to_btc(total_unspent), satoshi_to_btc(total_spent),
                satoshi_to_btc(-fee))
            raise Exception(message)

        unsigned_tx = UnsignedTx.standard_tx(coins_from, coins_to)
        s = io.BytesIO()
        unsigned_tx.stream(s)
        tx_bytes = s.getvalue()
        tx_hex = binascii.hexlify(tx_bytes).decode("utf8")
        return tx_hex
Ejemplo n.º 8
0
    def generate_return_txouts(self, address_hash160, payload, fee_needed):
        txs_out = []

        script_data = ScriptNulldata(nulldata=payload).script()
        txs_out.append(TxOut(self.return_fee, script_data))

        return txs_out
Ejemplo n.º 9
0
def hash160data_txout(hexdata, dust_limit=common.DUST_LIMIT):
    data = binary(hexdata)
    if len(data) != 20:  # 160 bit
        raise exceptions.InvalidHash160DataSize(len(data))
    script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % b2h(data)
    script_bin = tools.compile(script_text)
    return TxOut(dust_limit, script_bin)
Ejemplo n.º 10
0
 def check_bip143_tx(self, tx_u_hex, tx_s_hex, txs_out_value_scripthex_pair,
                     tx_in_count, tx_out_count, version, lock_time):
     tx_u = Tx.from_hex(tx_u_hex)
     tx_s = Tx.from_hex(tx_s_hex)
     txs_out = [
         TxOut(int(coin_value * 1e8), h2b(script_hex))
         for coin_value, script_hex in txs_out_value_scripthex_pair
     ]
     for tx in (tx_u, tx_s):
         self.assertEqual(len(tx.txs_in), tx_in_count)
         self.assertEqual(len(tx.txs_out), tx_out_count)
         self.assertEqual(tx.version, version)
         self.assertEqual(tx.lock_time, lock_time)
         tx.set_unspents(txs_out)
     self.check_unsigned(tx_u)
     self.check_signed(tx_s)
     tx_hex = tx_u.as_hex()
     self.assertEqual(tx_hex, tx_u_hex)
     tx_hex = tx_s.as_hex()
     self.assertEqual(tx_hex, tx_s_hex)
     tx_u_prime = self.unsigned_copy(tx_s)
     tx_hex = tx_u_prime.as_hex()
     self.assertEqual(tx_hex, tx_u_hex)
     self.assertEqual(b2h_rev(double_sha256(h2b(tx_s_hex))), tx_s.w_id())
     self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.w_id())
     self.assertEqual(b2h_rev(double_sha256(h2b(tx_u_hex))), tx_u.id())
     return tx_u, tx_s
Ejemplo n.º 11
0
 def test_multisig_one_at_a_time(self):
     M = 3
     N = 3
     keys = [
         Key(secret_exponent=i, generator=secp256k1_generator)
         for i in range(1, N + 2)
     ]
     tx_in = TxIn.coinbase_tx_in(script=b'')
     script = script_for_multisig(m=M,
                                  sec_keys=[key.sec() for key in keys[:N]])
     tx_out = TxOut(1000000, script)
     tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
     tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(),
                              [keys[-1].address()])
     ids = [
         "403e5bfc59e097bb197bf77a692d158dd3a4f7affb4a1fa41072dafe7bec7058",
         "5931d9995e83721243dca24772d7012afcd4378996a8b953c458175f15a544db",
         "9bb4421088190bbbb5b42a9eaa9baed7ec7574a407c25f71992ba56ca43d9c44",
         "03a1dc2a63f93a5cf5a7cb668658eb3fc2eda88c06dc287b85ba3e6aff751771"
     ]
     for i in range(1, N + 1):
         self.assertEqual(tx2.bad_signature_count(), 1)
         self.assertEqual(tx2.id(), ids[i - 1])
         hash160_lookup = build_hash160_lookup(
             [keys[i - 1].secret_exponent()], [secp256k1_generator])
         tx2.sign(hash160_lookup=hash160_lookup)
         self.assertEqual(tx2.id(), ids[i])
         t1 = sorted(who_signed_tx(tx2, 0, UI))
         t2 = sorted(((key.address(), SIGHASH_ALL) for key in keys[:i]))
         self.assertEqual(t1, t2)
     self.assertEqual(tx2.bad_signature_count(), 0)
Ejemplo n.º 12
0
def txout(testnet, target_address, value):
    testnet = flag(testnet)
    target_address = address(testnet, target_address)
    value = positive_integer(value)
    prefix = b'\x6f' if testnet else b"\0"
    hash160 = b2h(bitcoin_address_to_hash160_sec(target_address, prefix))
    script_text = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG" % hash160
    script_bin = tools.compile(script_text)
    return TxOut(value, script_bin)
Ejemplo n.º 13
0
def tether_tx(tx_ins, private_key, send_amount, receiver):
    """
    simple usdt transaction
    here assume utxo comes from the sender and is used for mine fee
    bitcoin change will be sent back to sender address

    of course different address's utxo can be used for mine fee,
    but should be aware sender is determined by the first input in the tx
    bitcoin change can also be sent back to different address,
    but should be aware receiver is indicated by the last output address that is not the sender

    for full customization, use btc sample p2pkh_tx
    :param tx_ins: utxo from the sender
    :param private_key: private key of the same sender
    :param send_amount: (display amount) * (10 ** 8)
    :param receiver: address to receive usdt
    """
    _txs_in = []
    _un_spent = []
    total_bal = 0

    for tx_id, idx, balance, address in tx_ins:
        total_bal += balance

        # must h2b_rev NOT h2b
        tx_id_b = h2b_rev(tx_id)
        _txs_in.append(TxIn(tx_id_b, idx))

        _un_spent.append(Spendable(balance, standard_tx_out_script(address), tx_id_b, idx))

    txn_fee = estimate_p2pkh_tx_bytes(len(tx_ins), 3) * recommend_satoshi_per_byte()

    _txs_out = [TxOut(total_bal - txn_fee - 546, standard_tx_out_script(tx_ins[0][3])),
                TxOut(0, binascii.unhexlify(omni_tether_script(send_amount))),
                TxOut(546, standard_tx_out_script(receiver))]

    version, lock_time = 1, 0
    tx = Tx(version, _txs_in, _txs_out, lock_time)
    tx.set_unspents(_un_spent)

    solver = build_hash160_lookup([int(private_key, 16)] * len(tx_ins))
    signed_tx = tx.sign(solver, hash_type=SIGHASH_ALL)

    return signed_tx.as_hex(), signed_tx.id()
Ejemplo n.º 14
0
    def parse_tx_out(self):
        tx_out = {}
        tx_out['value'] = self.data_stream.read_int64()
        tx_out['n'] = len(self.data['vout'])
        tx_out['scriptPubKey'] = {
            'hex':
            self.data_stream.read_bytes(self.data_stream.read_compact_size())
        }
        self.data['vout'].append(tx_out)

        new_tx_out = TxOut(tx_out['value'], tx_out['scriptPubKey']['hex'])
        self.new_txs_out.append(new_tx_out)
Ejemplo n.º 15
0
def spend_sh_fund(tx_ins, wif_keys, tx_outs):
    """
    spend script hash fund
    the key point of an input comes from multisig address is that,
    its sign script is combined with several individual signs
    :param tx_ins: list with tuple(tx_id, idx, balance, address, redeem_script)
    :param wif_keys: private keys in wif format,
        technical should be the same order with the pubkey in redeem script,
        but pycoin has inner control, so here order is not mandatory
    :param tx_outs: balance, receiver_address
    :return: raw hex and tx id
    """
    _txs_in = []
    _un_spent = []
    for tx_id, idx, balance, address, _ in tx_ins:
        # must h2b_rev NOT h2b
        tx_id_b = h2b_rev(tx_id)
        _txs_in.append(TxIn(tx_id_b, idx))

        _un_spent.append(
            Spendable(
                balance,
                script_obj_from_address(address, netcodes=[NET_CODE]).script(),
                tx_id_b, idx))

    _txs_out = []
    for balance, receiver_address in tx_outs:
        _txs_out.append(
            TxOut(
                balance,
                script_obj_from_address(receiver_address,
                                        netcodes=[NET_CODE]).script()))

    version, lock_time = 1, 0
    tx = Tx(version, _txs_in, _txs_out, lock_time)
    tx.set_unspents(_un_spent)

    # construct hash160_lookup[hash160] = (secret_exponent, public_pair, compressed) for each individual key
    hash160_lookup = build_hash160_lookup(
        [Key.from_text(wif_key).secret_exponent() for wif_key in wif_keys])

    for i in range(0, len(tx_ins)):
        # you can add some conditions that if the input script is not p2sh type, not provide p2sh_lookup,
        # so that all kinds of inputs can work together
        p2sh_lookup = build_p2sh_lookup([binascii.unhexlify(tx_ins[i][-1])])
        tx.sign_tx_in(hash160_lookup,
                      i,
                      tx.unspents[i].script,
                      hash_type=SIGHASH_ALL,
                      p2sh_lookup=p2sh_lookup)

    return tx.as_hex(), tx.id()
Ejemplo n.º 16
0
def send_op_return_tx(key, message, fee=10000):
    """
    Send an transaction with an OP_RETURN output.

    Args:
        key: the Bitcoin Key to send the transaction from.
        message: the message to include in OP_RETURN.
        fee: the miner fee that should be paid in Satoshis.
    Returns:
        The broadcasted Tx.
    """
    address = key.address()

    if len(message) > 80:
        raise ValueError("message must not be longer than 80 bytes")
    message = hexlify(message).decode()

    spendables = spendables_for_address(address)
    bitcoin_sum = sum(spendable.coin_value for spendable in spendables)
    if bitcoin_sum < fee:
        raise Exception("not enough bitcoin to cover fee")

    inputs = [spendable.tx_in() for spendable in spendables]

    outputs = []
    if bitcoin_sum > fee:
        change_output_script = standard_tx_out_script(address)
        outputs.append(TxOut(bitcoin_sum - fee, change_output_script))

    op_return_output_script = script.tools.compile('OP_RETURN %s' % message)
    outputs.append(TxOut(0, op_return_output_script))

    tx = Tx(version=1, txs_in=inputs, txs_out=outputs)
    tx.set_unspents(spendables)
    sign_tx(tx, wifs=[key.wif()])

    broadcast_tx(tx)

    return tx
Ejemplo n.º 17
0
def spend_outputs(funding_psbt, finalized_txn, tweaker=None):
    # take details from PSBT that created a finalized txn (also provided)
    # and build a new PSBT that spends those change outputs.
    from pycoin.tx.Tx import Tx
    from pycoin.tx.TxOut import TxOut
    from pycoin.tx.TxIn import TxIn
    funding = Tx.from_bin(finalized_txn)
    b4 = BasicPSBT().parse(funding_psbt)

    # segwit change outputs only
    spendables = [(n, i) for n, i in enumerate(funding.tx_outs_as_spendable())
                  if i.script[0:2] == b'\x00\x14' and b4.outputs[n].bip32_paths
                  ]

    #spendables = list(reversed(spendables))
    random.shuffle(spendables)

    if tweaker:
        tweaker(spendables)

    nn = BasicPSBT()
    nn.inputs = [BasicPSBTInput(idx=i) for i in range(len(spendables))]
    nn.outputs = [BasicPSBTOutput(idx=0)]

    # copy input values from funding PSBT's output side
    for p_in, (f_out, sp) in zip(nn.inputs,
                                 [(b4.outputs[x], s) for x, s in spendables]):
        p_in.bip32_paths = f_out.bip32_paths
        p_in.witness_script = f_out.redeem_script
        with BytesIO() as fd:
            sp.stream(fd)
            p_in.witness_utxo = fd.getvalue()

    # build new txn: single output, no change, no miner fee
    act_scr = fake_dest_addr('p2wpkh')
    dest_out = TxOut(sum(s.coin_value for n, s in spendables), act_scr)

    txn = Tx(2, [s.tx_in() for _, s in spendables], [dest_out])

    # put unsigned TXN into PSBT
    with BytesIO() as b:
        txn.stream(b)
        nn.txn = b.getvalue()

    with BytesIO() as rv:
        nn.serialize(rv)
        raw = rv.getvalue()

    open('debug/spend_outs.psbt', 'wb').write(raw)

    return nn, raw
Ejemplo n.º 18
0
def construct_standard_tx(composed_tx_spec, is_test):
    txouts = []
    STANDARD_SCRIPT_OUT = "OP_DUP OP_HASH160 %s OP_EQUALVERIFY OP_CHECKSIG"
    for txout in composed_tx_spec.get_txouts():
        hash160 = bitcoin_address_to_hash160_sec(txout.target_addr, is_test)
        script_text = STANDARD_SCRIPT_OUT % b2h(hash160)
        script_bin = tools.compile(script_text)
        txouts.append(TxOut(txout.value, script_bin))
    txins = []
    for cts_txin in composed_tx_spec.get_txins():
        txins.append(TxIn(cts_txin.get_txhash(), cts_txin.prevout.n))
    version = 1
    lock_time = 0
    return Tx(version, txins, txouts, lock_time)
Ejemplo n.º 19
0
    async def broadcast(self, tx_hex: str, chg_out: TxOut) -> str:
        txid = await self.connection.listen_rpc(self.methods["broadcast"],
                                                [tx_hex])  # type: str

        change_address = chg_out.address(
            netcode=self.chain.netcode)  # type:str
        change_key = self.search_for_key(change_address, change=True)
        scripthash = self.get_address(change_key)

        logging.info("Subscribing to new change address...")
        self.connection.listen_subscribe(self.methods["subscribe"],
                                         [scripthash])
        logging.info("Finished subscribing to new change address...")
        return txid
Ejemplo n.º 20
0
 def multisig_M_of_N(self, M, N, unsigned_id, signed_id):
     keys = [Key(secret_exponent=i) for i in range(1, N+2)]
     tx_in = TxIn.coinbase_tx_in(script=b'')
     script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script()
     tx_out = TxOut(1000000, script)
     tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
     tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [keys[-1].address()])
     self.assertEqual(tx2.id(), unsigned_id)
     self.assertEqual(tx2.bad_signature_count(), 1)
     hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys)
     tx2.sign(hash160_lookup=hash160_lookup)
     self.assertEqual(tx2.id(), signed_id)
     self.assertEqual(tx2.bad_signature_count(), 0)
     self.assertEqual(sorted(who_signed.who_signed_tx(tx2, 0)),
                      sorted(((key.address(), SIGHASH_ALL) for key in keys[:M])))
Ejemplo n.º 21
0
def standard_tx(coins_from, coins_to):
    txs_in = []
    unspents = []
    for h, idx, tx_out in coins_from:
        txs_in.append(TxIn(h, idx))
        unspents.append(tx_out)

    txs_out = []
    for coin_value, address in coins_to:
        txs_out.append(TxOut(coin_value, script_for_address(address)))

    version, lock_time = 1, 0
    tx = Tx(version, txs_in, txs_out, lock_time)
    tx.set_unspents(unspents)
    return tx
Ejemplo n.º 22
0
 def test_sign_pay_to_script_multisig(self):
     M, N = 3, 3
     keys = [Key(secret_exponent=i) for i in range(1, N+2)]
     tx_in = TxIn.coinbase_tx_in(script=b'')
     underlying_script = ScriptMultisig(m=M, sec_keys=[key.sec() for key in keys[:N]]).script()
     address = address_for_pay_to_script(underlying_script)
     self.assertEqual(address, "39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q")
     script = standard_tx_out_script(address)
     tx_out = TxOut(1000000, script)
     tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
     tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
     hash160_lookup = build_hash160_lookup(key.secret_exponent() for key in keys[:N])
     p2sh_lookup = build_p2sh_lookup([underlying_script])
     tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)
     self.assertEqual(tx2.bad_signature_count(), 0)
     self.assertRaises(who_signed.NoAddressesForScriptTypeError, who_signed.who_signed_tx, tx2, 0)
Ejemplo n.º 23
0
def test_txout_ordering(txout_small_coin_small_script,
                        txout_large_coin_small_script,
                        txout_small_coin_large_script,
                        txout_large_coin_large_script):
    a, b = txout_large_coin_large_script, TxOut(10, b"\xFF")
    assert (a.coin_value, b2h(a.script)) == (b.coin_value, b2h(b.script))

    txout_list = [
        txout_small_coin_small_script, txout_large_coin_small_script,
        txout_small_coin_large_script, txout_large_coin_large_script
    ]
    random.shuffle(txout_list)
    txout_list.sort(key=lambda txo: (txo.coin_value, b2h(txo.script)))

    assert txout_list[0] == txout_small_coin_small_script
    assert txout_list[1] == txout_small_coin_large_script
    assert txout_list[2] == txout_large_coin_small_script
    assert txout_list[3] == txout_large_coin_large_script
Ejemplo n.º 24
0
    def create_change(self, address: str, existing_txouts, balance: int):
        new_txouts = []
        change_size = 100 * 1000000  # 100 coins
        total_out = sum(txo.coin_value for txo in existing_txouts)
        balance = balance - total_out

        spendables = self.get_spendables(address, get_all=True)

        # Prune out spendables that we will spend.
        for spendable in spendables.copy():
            if total_out == 0:
                continue

            if total_out < 0:
                raise Exception(f"total_out is negative. ({total_out})")

            if spendable.coin_value > total_out:
                spendables.remove(spendable)
                break
            elif total_out > spendable.coin_value:
                spendables.remove(spendable)
                total_out -= spendable.coin_value

        # XXX: Find a way to cleanly unify this.
        _, _, address_hash160 = netcode_and_type_for_text(address)

        # 15 TXs in our own wallet should be a good buffer to have.
        if len(spendables) >= 15:
            return []

        # Create our payment to ourselves if we still have the coins.
        if (balance - (change_size * len(spendables))) < change_size:
            print("Warning: Low balance in address.")
            balance -= (change_size * len(spendables))

        for x in range(len(spendables), 50):
            balance -= change_size
            if balance < 0:
                break

            script_pay = ScriptPayToAddress(hash160=address_hash160).script()
            new_txouts.append(TxOut(change_size, script_pay))

        return new_txouts
Ejemplo n.º 25
0
    def get_raw_unsigned(self, fee_satoshi):
        """Return raw transaction ready for signing

        May return a transaction with amount=0 if the input amount is not enough to cover fees
        """
        txout = self.tx.txs_out[self.vout]
        amount_satoshi = txout.coin_value

        if fee_satoshi >= amount_satoshi:
            logging.warning('Insufficient funds to cover fee')
            logging.warning('txout has value of {}, fee = {}'.format(
                amount_satoshi, fee_satoshi))

        # Calculate adjusted amount = input amount - fee
        adjusted_amount_satoshi = max(0, amount_satoshi - fee_satoshi)
        logging.debug('tx amount = amount - fee = {} - {} = {}'.format(
            amount_satoshi, fee_satoshi, adjusted_amount_satoshi))
        assert adjusted_amount_satoshi >= 0
        adjusted_amount_btc = decimal.Decimal(
            adjusted_amount_satoshi) / satoshi_per_btc

        logging.debug("Create tx: {} sat -> {}".format(adjusted_amount_satoshi,
                                                       self.dest_address))
        logging.info("Input tx id = {}, vout={}".format(
            self.tx.id().encode("ascii"), self.vout))
        txin = TxIn(self.tx.hash(),
                    self.vout,
                    sequence=MAX_BIP125_RBF_SEQUENCE)
        scriptPubKey = pycoin.ui.script_obj_from_address(self.dest_address)
        txout = TxOut(adjusted_amount_satoshi, scriptPubKey.script())

        # Set nlocktime to the current blockheight to discourage 'fee sniping', as per the core
        # wallet implementation
        nlocktime = util.get_current_blockcount() or 0

        version = 1
        tx = Tx(version, [
            txin,
        ], [
            txout,
        ], nlocktime)
        return tx.as_hex()
Ejemplo n.º 26
0
    def _create_replacement_tx(self,
                               hist_obj: History,
                               version: int = 1) -> Tuple[Tx, Set[str], int]:
        """
        Builds a replacement Bitcoin transaction based on a given History
        object in order to implement opt in Replace-By-Fee.

        :param hist_obj: a History object from our tx history data
        :param version: an int representing the Tx version
        :returns: A not-fully-formed and unsigned replacement Tx object
        :raise: Raises a ValueError if tx not a spend or is already confirmed
        """
        if hist_obj.height == 0 and hist_obj.is_spend:
            old_tx = hist_obj.tx_obj  # type: Tx
            spendables = old_tx.unspents  # type: List[Spendable]
            chg_vout = None  # type: int

            in_addrs = set()  # type: Set[str]
            for utxo in spendables:
                in_addrs.add(utxo.address(self.chain.netcode))

            txs_out = list()  # type: List[TxOut]
            for i, txout in enumerate(old_tx.txs_out):
                value = None  # type: int
                if txout.coin_value / Wallet.COIN == hist_obj.value:
                    value = txout.coin_value
                else:
                    value = 0
                    chg_vout = i
                txs_out.append(TxOut(value, txout.script))

            new_tx = Tx(version=version,
                        txs_in=old_tx.txs_in,
                        txs_out=txs_out)  # type: Tx
            new_tx.set_unspents(spendables)
            return new_tx, in_addrs, chg_vout
        else:
            raise ValueError("This transaction is not replaceable")
Ejemplo n.º 27
0
 def test_sign_pay_to_script_multisig(self):
     M, N = 3, 3
     keys = [
         Key(secret_exponent=i, generator=secp256k1_generator)
         for i in range(1, N + 2)
     ]
     tx_in = TxIn.coinbase_tx_in(script=b'')
     underlying_script = script_for_multisig(
         m=M, sec_keys=[key.sec() for key in keys[:N]])
     address = address_for_p2s(underlying_script)
     self.assertEqual(address, "39qEwuwyb2cAX38MFtrNzvq3KV9hSNov3q")
     script = script_for_address(address)
     tx_out = TxOut(1000000, script)
     tx1 = Tx(version=1, txs_in=[tx_in], txs_out=[tx_out])
     tx2 = tx_utils.create_tx(tx1.tx_outs_as_spendable(), [address])
     hash160_lookup = build_hash160_lookup(
         (key.secret_exponent() for key in keys[:N]), [secp256k1_generator])
     p2sh_lookup = build_p2sh_lookup([underlying_script])
     tx2.sign(hash160_lookup=hash160_lookup, p2sh_lookup=p2sh_lookup)
     self.assertEqual(tx2.bad_signature_count(), 0)
     self.assertEqual(
         sorted(who_signed_tx(tx2, 0, UI)),
         sorted(((key.address(), SIGHASH_ALL) for key in keys[:M])))
Ejemplo n.º 28
0
    def generate_addr_txouts(self, address_hash160, _payload, fee_needed):
        txs_out = []
        payload = io.BytesIO(_payload)
        # XXX: constants file
        payload_size = 20

        # Create all the payments to the data addresses.
        # Chunking from https://github.com/vilhelmgray/FamaMonetae/blob/master/famamonetae.py
        while True:
            chunk = payload.read(payload_size)
            chunk_size = len(chunk)

            # Break once our chunk is smaller than the payload size
            if chunk_size < payload_size:
                if chunk_size == 0:
                    break

                chunk = chunk + (B'\x00') * (payload_size - chunk_size)

            script_data = ScriptPayToAddress(hash160=chunk).script()
            txs_out.append(TxOut(self.return_fee, script_data))

        return txs_out
Ejemplo n.º 29
0
def spend_pkh_fund(tx_ins, in_keys, tx_outs):
    """
    p2pkh address send to p2pkh p2sh transaction
    :param tx_ins: list with tuple(tx_id, idx, balance, address)
    :param in_keys: list of private keys in hex format corresponding to each input
    :param tx_outs: balance, receiver_address
    :return: raw hex and tx id
    """
    _txs_in = []
    _un_spent = []
    for tx_id, idx, balance, address in tx_ins:
        # must h2b_rev NOT h2b
        tx_id_b = h2b_rev(tx_id)
        _txs_in.append(TxIn(tx_id_b, idx))

        _un_spent.append(
            Spendable(
                balance,
                script_obj_from_address(address, netcodes=[NET_CODE]).script(),
                tx_id_b, idx))

    _txs_out = []
    for balance, receiver_address in tx_outs:
        _txs_out.append(
            TxOut(
                balance,
                script_obj_from_address(receiver_address,
                                        netcodes=[NET_CODE]).script()))

    version, lock_time = 1, 0
    tx = Tx(version, _txs_in, _txs_out, lock_time)
    tx.set_unspents(_un_spent)

    solver = build_hash160_lookup([int(pri_hex, 16) for pri_hex in in_keys])
    tx.sign(solver, hash_type=SIGHASH_ALL)

    return tx.as_hex(), tx.id()
Ejemplo n.º 30
0
    def _create_bip69_tx(spendables: List[Spendable],
                         payables: List[Tuple[str, int]],
                         rbf: bool,
                         version: int = 1) -> Tx:
        """ Create tx inputs and outputs from spendables and payables.
        Sort lexicographically and return unsigned Tx object.

        :param spendables: A list of Spendable objects
        :param payables: A list of payable tuples
        :param rbf: Replace by fee flag
        :param version: Tx format version
        :returns: Fully formed but unsigned Tx object
        """
        spendables.sort(key=lambda utxo: (utxo.as_dict()["tx_hash_hex"],
                                          utxo.as_dict()["tx_out_index"]))

        # Create input list from utxos
        # Set sequence numbers to zero if using RBF.
        txs_in = [spendable.tx_in()
                  for spendable in spendables]  # type: List[TxIn]
        if rbf:
            logging.info("Spending with opt-in Replace by Fee! (RBF)")
            for txin in txs_in:
                txin.sequence = 0

        # Create output list from payables
        txs_out = []  # type: List[TxOut]
        for payable in payables:
            bitcoin_address, coin_value = payable
            script = standard_tx_out_script(bitcoin_address)  # type: bytes
            txs_out.append(TxOut(coin_value, script))
        txs_out.sort(key=lambda txo: (txo.coin_value, b2h(txo.script)))

        tx = Tx(version=version, txs_in=txs_in, txs_out=txs_out)  # type: Tx
        tx.set_unspents(spendables)
        return tx