예제 #1
0
 def add_output(self,
                serial_id: int,
                script: str,
                sats: int) -> None:
     txout = CTxOut(sats, CScript(bytes.fromhex(script)))
     self.outputs.append({'output': txout,
                          'serial_id': serial_id})
예제 #2
0
    def add_witnesses(self,
                      witness_stack) -> str:
        wits = []
        for idx, _in in enumerate(self.inputs):
            privkey = _in['privkey']
            serial_id = _in['serial_id']

            if privkey:
                inkey = privkey_expand(privkey)
                inkey_pub = coincurve.PublicKey.from_secret(inkey.secret)

                address = P2WPKHBitcoinAddress.from_scriptPubKey(CScript([script.OP_0, Hash160(inkey_pub.format())]))

                sighash = script.SignatureHash(address.to_redeemScript(),
                                               self.tx, idx, script.SIGHASH_ALL,
                                               amount=_in['sats'],
                                               sigversion=script.SIGVERSION_WITNESS_V0)
                sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL])

                wits.append(CTxInWitness(CScriptWitness([sig, inkey_pub.format()])))
                continue

            # Every input from the witness stack will be the accepter's
            # which is always an odd serial
            assert(serial_id % 2 == 1)
            elems = witness_stack.pop(0)['witness_element']

            stack = []
            for elem in elems:
                stack.append(bytes.fromhex(elem['witness']))

            wits.append(CTxInWitness(CScriptWitness(stack)))

        self.tx.wit = CTxWitness(wits)
        return self.tx.serialize().hex()
예제 #3
0
def create_trx(op_return_val, issuing_transaction_fee, issuing_address,
               tx_outs, tx_inputs):
    """

    :param op_return_val:
    :param issuing_transaction_fee:
    :param issuing_address:
    :param tx_outs:
    :param tx_input:
    :return:
    """
    cert_out = CMutableTxOut(0, CScript([OP_RETURN, op_return_val]))
    tx_ins = []
    value_in = 0
    for tx_input in tx_inputs:
        tx_ins.append(CTxIn(COutPoint(tx_input.tx_hash,
                                      tx_input.tx_out_index)))
        value_in += tx_input.coin_value

    # send change back to our address
    amount = value_in - issuing_transaction_fee
    if amount > 0:
        change_out = create_transaction_output(issuing_address, amount)
        tx_outs = tx_outs + [change_out]
    tx_outs = tx_outs + [cert_out]
    transaction = CMutableTransaction(tx_ins, tx_outs)
    return transaction
예제 #4
0
    def from_utxo(txid_in: str,
                  tx_index_in: int,
                  sats: int,
                  privkey: str,
                  fee: int,
                  local_node_privkey: str,
                  local_funding_privkey: str,
                  remote_node_privkey: str,
                  remote_funding_privkey: str,
                  chain_hash: str = regtest_hash) -> Tuple['Funding', str]:
        """Make a funding transaction by spending this utxo using privkey: return Funding, tx."""

        # Create dummy one to start: we will fill in txid at the end.
        funding = Funding('', 0, sats - fee, local_node_privkey,
                          local_funding_privkey, remote_node_privkey,
                          remote_funding_privkey, chain_hash)

        # input private key.
        inkey = privkey_expand(privkey)
        inkey_pub = coincurve.PublicKey.from_secret(inkey.secret)

        txin = CTxIn(COutPoint(bytes.fromhex(txid_in), tx_index_in))
        txout = CTxOut(
            sats - fee,
            CScript([script.OP_0,
                     sha256(funding.redeemscript()).digest()]))
        tx = CMutableTransaction([txin], [txout])

        # now fill in funding txid.
        funding.txid = tx.GetTxid().hex()

        # while we're here, sign the transaction.
        address = P2WPKHBitcoinAddress.from_scriptPubKey(
            CScript([script.OP_0, Hash160(inkey_pub.format())]))

        sighash = script.SignatureHash(address.to_redeemScript(),
                                       tx,
                                       0,
                                       script.SIGHASH_ALL,
                                       amount=sats,
                                       sigversion=script.SIGVERSION_WITNESS_V0)
        sig = inkey.sign(sighash, hasher=None) + bytes([script.SIGHASH_ALL])

        tx.wit = CTxWitness(
            [CTxInWitness(CScriptWitness([sig, inkey_pub.format()]))])
        return funding, tx.serialize().hex()
def mock_listunspent(self, addrs):
    output1 = {'outpoint': COutPoint(lx('34eb81bc0d1a822369f75174fd4916b1ec490d8fbcba33168e820cc78a52f608'), 0),
               'confirmations': 62952, 'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'),
               'spendable': False, 'amount': 49000000, 'solvable': False, 'scriptPubKey': CScript(
            [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY, OP_CHECKSIG]),
               'account': ''}
    output2 = {'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '',
               'spendable': False, 'solvable': False, 'confirmations': 62932,
               'outpoint': COutPoint(lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b'), 1),
               'scriptPubKey': CScript(
                   [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY,
                    OP_CHECKSIG])}
    output3 = {'address': P2PKHBitcoinAddress('mz7poFND7hVGRtPWjiZizcCnjf6wEDWjjT'), 'amount': 2750, 'account': '',
               'spendable': False, 'solvable': False, 'confirmations': 62932,
               'outpoint': COutPoint(lx('6773785b4dc5d2cced67d26fc0820329307a8e10dfaef50d506924984387bf0b'), 5),
               'scriptPubKey': CScript(
                   [OP_DUP, OP_HASH160, x('cc0a909c4c83068be8b45d69b60a6f09c2be0fda'), OP_EQUALVERIFY,
                    OP_CHECKSIG])}
    unspent_outputs = [output1, output2, output3]
    return unspent_outputs
예제 #6
0
def forge_prevtx(
        vouts: Sequence[Tuple[str, int]],
        network: str = "mainnet") -> Tuple[bytes, messages.TransactionType]:
    """
    Forge a transaction with the given vouts.
    """
    bitcoin.SelectParams(network)
    input = messages.TxInputType(
        prev_hash=b"\x00" * 32,
        prev_index=0xFFFFFFFF,
        script_sig=b"\x00",
        sequence=0xFFFFFFFF,
    )
    outputs = [
        messages.TxOutputBinType(
            amount=amount,
            script_pubkey=bytes(CBitcoinAddress(address).to_scriptPubKey()),
        ) for address, amount in vouts
    ]
    tx = messages.TransactionType(
        version=1,
        inputs=[input],
        bin_outputs=outputs,
        lock_time=0,
    )

    cin = CTxIn(
        COutPoint(input.prev_hash, input.prev_index),
        CScript(input.script_sig),
        input.sequence,
    )
    couts = [
        CTxOut(output.amount, CScript(output.script_pubkey))
        for output in tx.bin_outputs
    ]
    txhash = CTransaction([cin], couts, tx.lock_time,
                          tx.version).GetTxid()[::-1]

    bitcoin.SelectParams("mainnet")

    return txhash, tx
예제 #7
0
 def get_unspent_outputs(self, address):
     unspent_outputs = []
     # this calls a different api not accessible through localhost proxy
     unspent_url = 'https://blockchain.info/unspent?active=%s&format=json' % address
     unspent_response = try_get(unspent_url)
     r = unspent_response.json()
     for u in r['unspent_outputs']:
         tx_out = TransactionOutput(
             COutPoint(unhexlify(u['tx_hash']), u['tx_output_n']),
             CBitcoinAddress(address), CScript(unhexlify(u['script'])),
             int(u['value']))
         unspent_outputs.append(tx_out)
     return unspent_outputs
예제 #8
0
def create_trx(op_return_val, issuing_transaction_cost,
               issuing_address, txouts, tx_input):
    cert_out = CMutableTxOut(0, CScript([OP_RETURN, op_return_val]))
    txins = [CTxIn(tx_input.outpoint)]
    value_in = tx_input.amount

    # send change back to our address
    amount = value_in - issuing_transaction_cost.total
    if amount > 0:
        change_out = create_transaction_output(issuing_address, amount)
        txouts = txouts + [change_out]
    txouts = txouts + [cert_out]
    tx = CMutableTransaction(txins, txouts)
    return tx
예제 #9
0
def _build_certificate_transactions(wallet, issuing_address,
                                    revocation_address, certificate_metadata,
                                    fees, tail):
    """Make transactions for the certificates.
    """
    logging.info('Creating tx of certificate for recipient uid: %s ...',
                 certificate_metadata.uid)

    with open(certificate_metadata.certificate_hash_file_name,
              'rb') as in_file:
        # this is the recipient-specific hash that will be recorded on the
        # blockchain
        hashed_certificate = in_file.read()
        cert_out = CMutableTxOut(0, CScript([OP_RETURN, hashed_certificate]))

        # send a transaction to the recipient's public key, and to a revocation
        # address
        txouts = create_recipient_outputs(certificate_metadata.pubkey,
                                          revocation_address,
                                          fees.min_per_output)

        # define transaction inputs
        unspent_outputs = wallet.get_unspent_outputs(issuing_address)
        last_input = unspent_outputs[tail]

        txins = [CTxIn(last_input.outpoint)]
        value_in = last_input.amount

        # very important! If we don't send the excess change back to ourselves,
        # some lucky miner gets it!
        amount = value_in - fees.cost_per_transaction
        if amount > 0:
            change_out = create_transaction_output(issuing_address, amount)
            txouts = txouts + [change_out]

        txouts = txouts + [cert_out]
        tx = CMutableTransaction(txins, txouts)

        # this is the transaction for a recipient, unsigned
        hextx = hexlify(tx.serialize())
        with open(certificate_metadata.unsigned_tx_file_name,
                  'wb') as out_file:
            out_file.write(bytes(hextx, 'utf-8'))

        logging.info('Created unsigned tx for recipient; last_input=%s',
                     last_input)
        return last_input
예제 #10
0
def add_input_output(bitcoind, tx):
    """Add an input and an output to a CMutableTransaction, SIGHASH_ALL."""
    # First we get some coins
    privkey = CKey(os.urandom(32))
    scriptPubKey = CScript([OP_0, Hash160(privkey.pub)])
    address = CBitcoinAddress.from_scriptPubKey(scriptPubKey)
    amount = Decimal("50") * Decimal(COIN) - Decimal("500")
    # This creates a one-output transaction
    txid = bitcoind.pay_to(str(address), amount / Decimal(COIN))
    # We bump the fees by 5000
    tx.vout.append(CTxOut(amount - Decimal("5000"), scriptPubKey))
    tx.vin.append(CTxIn(COutPoint(lx(txid), 0)))
    # Sign the new output with ALL
    tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL,
                            int(amount), SIGVERSION_WITNESS_V0)
    sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL])
    tx.wit.vtxinwit.append(CTxInWitness(CScriptWitness([sig, privkey.pub])))
예제 #11
0
def add_input_output(bitcoind, tx, coin, fees):
    """Add another input to the transaction to bump the feerate."""
    coin_amount = Decimal(coin["amount"]) * Decimal(COIN)
    # First get the private key from bitcoind's wallet.
    privkey = CKey(wif_decode(bitcoind.dumpprivkey(coin["address"])))

    # Add the fetched coin as a new input.
    tx.vin.append(CTxIn(COutPoint(lx(coin["txid"]), coin["vout"])))
    # And likely add an output, otherwise all goes to the fees.
    scriptPubKey = CScript([OP_0, Hash160(privkey.pub)])
    if coin_amount > fees + 294:
        # For simplicity, pay to the same script
        tx.vout.append(CTxOut(coin_amount - Decimal(fees), scriptPubKey))
    address = CBitcoinAddress.from_scriptPubKey(scriptPubKey)
    # We only do this once, sign it with ALL
    tx_hash = SignatureHash(address.to_redeemScript(), tx, 1, SIGHASH_ALL,
                            int(coin_amount), SIGVERSION_WITNESS_V0)
    sig = privkey.sign(tx_hash) + bytes([SIGHASH_ALL])
    tx.wit.vtxinwit.append(
        CTxInWitness(CScriptWitness([sig, privkey.pub]))
    )
    return tx
예제 #12
0
    def close_tx(self, fee: int, privkey_dest: str) -> str:
        """Create a (mutual) close tx"""
        txin = CTxIn(COutPoint(bytes.fromhex(self.txid), self.output_index))

        out_privkey = privkey_expand(privkey_dest)

        txout = CTxOut(
            self.amount - fee,
            CScript([
                script.OP_0,
                Hash160(
                    coincurve.PublicKey.from_secret(
                        out_privkey.secret).format())
            ]))

        tx = CMutableTransaction(vin=[txin], vout=[txout])
        sighash = script.SignatureHash(self.redeemscript(),
                                       tx,
                                       inIdx=0,
                                       hashtype=script.SIGHASH_ALL,
                                       amount=self.amount,
                                       sigversion=script.SIGVERSION_WITNESS_V0)

        sigs = [
            key.sign(sighash, hasher=None)
            for key in self.funding_privkeys_for_tx()
        ]
        # BOLT #3:
        # ## Closing Transaction
        # ...
        #    * `txin[0]` witness: `0 <signature_for_pubkey1> <signature_for_pubkey2>`
        witness = CScriptWitness([
            bytes(), sigs[0] + bytes([script.SIGHASH_ALL]),
            sigs[1] + bytes([script.SIGHASH_ALL]),
            self.redeemscript()
        ])
        tx.wit = CTxWitness([CTxInWitness(witness)])
        return tx.serialize().hex()
    def transfer(self,
                 src_addrs_key_map: OrderedDict,
                 dst_addrs_amount_map: dict,
                 txfee: Decimal,
                 auto_calc_pay_back: bool,
                 pay_back_index: int = 0xfffffff,
                 ensure_one_txout: bool = False) -> str:
        """

        :param src_addrs_key_map: {'addr1': 'privkey1', 'addr2': 'privkey2'  }   私钥为  hex字符串
        :param dst_addrs_amount_map: {'addr1':Decimal(0.1234), 'addr2':Deciaml(0.234) }
        :param txfee:  矿工费
        :param auto_calc_pay_back: 是否自动计算并找零
        :param pay_back_index: 找零地址索引  即在 src_addrs_key_map 中的索引
        :param ensure_one_txout:   确认只有一个交易输出(比如: 提币不需要找零的情况, 归集)
        :return: txid
        """
        #仅支持 P2PKH 类型的from地址

        assert isinstance(src_addrs_key_map,
                          OrderedDict), 'src_addrs_key_map is not OrderedDict'
        assert isinstance(dst_addrs_amount_map,
                          dict), 'dst_addrs_amount_map is not dict'
        assert Decimal('0.00001') <= txfee <= Decimal(
            '0.001'), 'invalid txfee, please check txfee'
        assert len(
            src_addrs_key_map) >= 1, 'src_addrs_key_map length must >= 1'
        assert  not (True == auto_calc_pay_back  == ensure_one_txout) , \
                'True == auto_calc_pay_back  == ensure_one_txout , must be mutex '

        if ensure_one_txout:
            assert (len(dst_addrs_amount_map) == 1
                    ), 'dst_addrs_amount_map length must equal 1'
        elif not auto_calc_pay_back:
            assert (len(dst_addrs_amount_map) >=
                    1), 'dst_addrs_amount_map length must >= 2'

        if auto_calc_pay_back and pay_back_index >= len(src_addrs_key_map):
            raise Exception('pay_back_index is to large')

        self.logger.info(
            f'dst_addrs_amount_map is { json.dumps(dst_addrs_amount_map, indent=4, default=decimal_default) }'
        )

        assert self.ping() == True, 'bitcoind rpc is gone'

        total_amount = sum(dst_addrs_amount_map.values()) + txfee
        self.logger.info(f'total_amount is {total_amount}')

        source_addrs = list(src_addrs_key_map.keys())  #WARNING: 禁止打印私钥!!!

        is_enough, founded_utxos = self.search_utxo(addrs=source_addrs,
                                                    total_amount=total_amount)
        if not is_enough:
            msg = 'balance is not enough'
            self.logger.error(msg)
            raise Exception(msg)

        self.logger.info(
            f'founded_utxos is { json.dumps(founded_utxos, indent=4, default=decimal_default) }'
        )

        #设置全局变量
        SelectParams(self.net_type)

        #构造inputs
        txins = []
        utxo_owner_map = dict()
        for addr, utxos in founded_utxos.items():

            assert addr in src_addrs_key_map, 'addr is not in src_addrs_key_map'

            for utxo in utxos:
                txin = CMutableTxIn(
                    prevout=COutPoint(hash=lx(utxo['txid']), n=utxo['vout']))
                txins.append(txin)

                #因为顺序不会被打乱, 所以可以直接使用 索引进行对应
                utxo_owner_map[len(txins) - 1] = addr

        #构造outputs
        txouts = []
        for to_addr, amount in dst_addrs_amount_map.items():
            out = CMutableTxOut(
                nValue=amount * COIN,
                scriptPubKey=CBitcoinAddress(to_addr).to_scriptPubKey())
            txouts.append(out)

        #自动结算
        if auto_calc_pay_back:
            sum_in_satoshi = 0
            for addr, utxos in founded_utxos.items():
                for utxo in utxos:
                    sum_in_satoshi += utxo['value']
            pay_back_in_satoshi = int(sum_in_satoshi -
                                      int(total_amount * COIN))

            #判断找零的金额, 如果太小就不要了, 作为矿工费
            if pay_back_in_satoshi >= MIN_AVAILABLE_UTXO_VALUE_IN_SATOSHI:
                pay_back_addr = list(src_addrs_key_map.keys())[pay_back_index]
                pay_back_out = CMutableTxOut(
                    nValue=pay_back_in_satoshi,
                    scriptPubKey=CBitcoinAddress(
                        pay_back_addr).to_scriptPubKey())
                txouts.append(pay_back_out)

        muttx = CMutableTransaction(vin=txins, vout=txouts)

        #对每个 input 进行签名
        for n in range(len(txins)):

            #查找这个utxo属于哪个地址
            owner_addr = utxo_owner_map[n]
            privkey = src_addrs_key_map[owner_addr]

            if len(privkey) == 64:  # hex
                wif_key = PrivKeyToWIFCompress(privkey,
                                               self.net_type != 'mainnet')
                seckey = CBitcoinSecret(s=wif_key)
            elif len(privkey) == 52:  #base58格式
                seckey = CBitcoinSecret(s=privkey)
            else:
                raise Exception("invalid privkey")

            txin_script_pubkey = CScript([
                OP_DUP, OP_HASH160,
                Hash160(seckey.pub), OP_EQUALVERIFY, OP_CHECKSIG
            ])
            sig_hash = SignatureHash(txin_script_pubkey, muttx, n, SIGHASH_ALL)
            sig = seckey.sign(sig_hash) + bytes([SIGHASH_ALL])
            muttx.vin[n].scriptSig = CScript([sig, seckey.pub])

            #TODO: 处理验签失败抛异常
            VerifyScript(muttx.vin[n].scriptSig, txin_script_pubkey, muttx, n,
                         (SCRIPT_VERIFY_P2SH, ))
            pass

        raw_tx_hex = b2x(muttx.serialize())
        self.logger.info(f'raw_tx_hex is: {raw_tx_hex}')

        # local_tx_hash = muttx.GetTxid()
        # self.logger.info(f'local_tx_hash is: {b2x(local_tx_hash)}')

        #广播交易
        assert self.ping(
        ) == True, 'bitcoind rpc is gone'  #测试 bitcoind的 rpc服务是否还在
        txid = self.send_raw_tx(raw_tx_hex=raw_tx_hex)
        self.logger.info(f'send_raw_tx txid is: {txid}')

        return txid
예제 #14
0
for x in hashes_missing_in_genesis_block:
    if missing_addresses[x] in ignore_because_refunded:
        continue
    print "  ->",x," height:" + str(missing_heights[x]) + " XEL:" + amtamt(missing_heights[x],float(missing_amounts_per_address[missing_addresses[x]])) + " [" + missing_addresses[x] + "] =",missing_amounts_per_address[missing_addresses[x]],"BTC in total (dont count addrs twice)"





print "\n\nNow, Handing the Abnormal ..."
# Now handling the abnormals
abnormal_add_map = {}
btc_abnormal = 0
for x in abnormal:
    btc_abnormal += float(x["btc_amount"])
    scr = CScript(hash_to_script[x["btc_tx"]].decode("hex"))
    reas=""
    for kk in iter(scr):
        reas = kk
    scr2 = CScript(reas)
    reas=""
    want = 0
    have = 0
    cnt=0
    for kk in iter(scr2):
        if cnt==0:
            want=kk
        else:
            if len(str(kk))>30:
                reas += str(P2PKHBitcoinAddress.from_pubkey(kk)) + "-"
            else:
예제 #15
0
 def locking_script_keys(key_one: coincurve.PublicKey, key_two: coincurve.PublicKey) -> CScript:
     return CScript([script.OP_0, sha256(Funding.redeemscript_keys(key_one, key_two)).digest()])
예제 #16
0
 def redeemscript_keys(key_one: coincurve.PublicKey, key_two: coincurve.PublicKey) -> CScript:
     return CScript([script.OP_2]
                    + [k.format() for k in Funding.sort_by_keys(key_one, key_two, key_one, key_two)]
                    + [script.OP_2,
                       script.OP_CHECKMULTISIG])
예제 #17
0
def create_raw_velvet_tx(payload_buf):
    VELVET_FORK_MARKER = b'interlink'
    digest_outs = [CMutableTxOut(0, CScript([OP_RETURN, VELVET_FORK_MARKER, payload_buf]))]
    tx = CMutableTransaction([], digest_outs)
    return tx.serialize().hex()
예제 #18
0
 def __init__(self, raw_hex):
     self._hex = raw_hex
     self._script = CScript(self._hex)
     self._operations = None
예제 #19
0
 def redeemscript(self) -> CScript:
     return CScript([script.OP_2] +
                    [k.format() for k in self.funding_pubkeys_for_tx()] +
                    [script.OP_2, script.OP_CHECKMULTISIG])