예제 #1
0
def spend_p2sh_mediator(redeemScript, txins_str, amounts, daddrs, sig, rein):
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txins_obj = []
    for txin_str in txins_str.split():
        txin_list = txin_str.split("-")
        txins_obj.append(
            CMutableTxIn(COutPoint(lx(txin_list[0]), int(txin_list[1]))))
    txouts = []
    len_amounts = len(amounts)
    for i in range(0, len_amounts):
        txouts.append(
            CMutableTxOut(
                round(amounts[i], 8) * COIN,
                CBitcoinAddress(daddrs[i]).to_scriptPubKey()))
    tx = CMutableTransaction(txins_obj, txouts)
    seckey = CBitcoinSecret(rein.user.dkey)
    ntxins = len(txins_obj)
    sig_list = []
    for s in sig.split():
        sig_list.append(x(s))
    sig2_str = ""
    for i in range(0, ntxins):
        sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL)
        sig2 = seckey.sign(sighash) + x("01")
        sig2_str += " " + b2x(sig2)
        txins_obj[i].scriptSig = CScript(
            [OP_0, sig2, sig_list[i], txin_redeemScript])
        VerifyScript(txins_obj[i].scriptSig, txin_scriptPubKey, tx, i,
                     (SCRIPT_VERIFY_P2SH, ))
    tx_bytes = tx.serialize()
    hash = sha256(sha256(tx_bytes).digest()).digest()
    txid = b2x(hash[::-1])
    txid_causeway = broadcast_tx(b2x(tx_bytes), rein)
    return (txid, sig2_str[1:])
예제 #2
0
def get_public_addresses(key_file):
    keys = read_keys(key_file)
    bitcoin_secrets = [CBitcoinSecret(key) for key in keys]
    bitcoin_addresses = [
        P2PKHBitcoinAddress.from_pubkey(key.pub) for key in bitcoin_secrets
    ]
    return bitcoin_addresses
def sign_and_verify(private_key, message, address):
    key = CBitcoinSecret(private_key)
    signature = SignMessage(key=key, message=BitcoinMessage(message))
    assert VerifyMessage(address=address,
                         message=BitcoinMessage(message),
                         sig=signature)
    return signature
예제 #4
0
def partial_spend_p2sh_mediator(redeemScript,
                                rein,
                                mediator_address,
                                mediator_sig=False):
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet)
    if len(txins) == 0:
        raise ValueError('No unspent txins found')
    txins_str = ""
    txins_obj = []
    for txid, vout in txins:
        txins_str += " " + txid + "-" + str(vout)
        txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout)))
    fee = 0.00025
    amount = round(total_value - fee, 8)
    if amount <= 0:
        raise ValueError('Not enough value in the inputs')
    if mediator_sig:
        txout = CMutableTxOut(
            amount * COIN,
            CBitcoinAddress(mediator_address).to_scriptPubKey())
        tx = CMutableTransaction(txins_obj, [txout])
        seckey = CBitcoinSecret(rein.user.dkey)
        ntxins = len(txins_obj)
        sig = ""
        for i in range(0, ntxins):
            sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL)
            sig += " " + b2x(seckey.sign(sighash) + x("01"))
        return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address),
                sig[1:])
    return (txins_str[1:], "{:.8f}".format(amount), str(mediator_address))
예제 #5
0
def privkey_to_address(privkey):
    try:
        key = CBitcoinSecret(privkey)
        address = str(P2PKHBitcoinAddress.from_pubkey(key.pub))
    except:
        return False
    return address
예제 #6
0
    def test_get_coinbase_variables(self, m_execute_rpc):
        m_execute_rpc.side_effect = [
            [{
                "txid": 'tx_hash_1',
                'address': 'address_hash_1',
                'amount': 50
            }, {
                "txid": 'tx_hash_2',
                'address': 'address_hash_2',
                'amount': 25
            }], 'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc',
            'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc'
        ]

        self.node.create_tx_chains()

        self.assertEqual(m_execute_rpc.call_count, 3)
        self.assertEqual(len(self.node._tx_chains), 2)

        chain_1 = self.node._tx_chains[0]
        self.assertEqual(chain_1.current_unspent_tx, 'tx_hash_1')
        self.assertEqual(chain_1.address, 'address_hash_1')
        self.assertEqual(
            chain_1.seckey,
            CBitcoinSecret(
                'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc'))
        self.assertEqual(chain_1.amount, 5000000000)

        chain_2 = self.node._tx_chains[1]
        self.assertEqual(chain_2.current_unspent_tx, 'tx_hash_2')
        self.assertEqual(chain_2.address, 'address_hash_2')
        self.assertEqual(chain_2.amount, 2500000000)
예제 #7
0
def test_get_coinbase_variables(m_execute_rpc, setup):
    m_execute_rpc.side_effect = [
        [{
            "txid": 'tx_hash_1',
            'address': 'address_hash_1',
            'amount': 50
        }, {
            "txid": 'tx_hash_2',
            'address': 'address_hash_2',
            'amount': 25
        }], 'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc',
        'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc'
    ]

    setup.create_tx_chains()

    assert m_execute_rpc.call_count == 3
    assert len(setup._tx_chains) == 2

    chain_1 = setup._tx_chains[0]
    assert chain_1.current_unspent_tx == 'tx_hash_1'
    assert chain_1.address == 'address_hash_1'
    assert chain_1.seckey == CBitcoinSecret(
        'cTCrrgVLfBqEZ1dxmCnEwmiEWzeZHU8uw3CNvLVvbT4CrBeDdTqc')
    assert chain_1.amount == 5000000000

    chain_2 = setup._tx_chains[1]
    assert chain_2.current_unspent_tx == 'tx_hash_2'
    assert chain_2.address == 'address_hash_2'
    assert chain_2.amount == 2500000000
예제 #8
0
파일: node.py 프로젝트: andreaskern/simcoin
    def create_tx_chains(self):
        for unspent_tx in self.execute_rpc('listunspent'):
            seckey = CBitcoinSecret(
                self.execute_rpc('dumpprivkey', unspent_tx['address']))
            tx_chain = TxChain(unspent_tx['txid'], unspent_tx['address'],
                               seckey, unspent_tx['amount'] * 100000000)

            self._tx_chains.append(tx_chain)
예제 #9
0
    def __init__(self, private_key=None, encrypted_private_key=None, password=None):
        if private_key is None and encrypted_private_key is None:
            _, secret_hash = generate_secret_with_hash()
            self.private_key = CBitcoinSecret.from_secret_bytes(secret=secret_hash)

        elif private_key is not None:
            self.private_key = CBitcoinSecret(private_key)

        elif encrypted_private_key is not None and password is not None:
            self.private_key = CBitcoinSecret(self.decrypt_private_key(encrypted_private_key, password))

        elif password is None:
            raise TypeError(
                "__init__() missing 'password' argument, since 'encrypted_private_key' argument was provided"
            )

        self.public_key = self.private_key.pub
        self.address = str(P2PKHBitcoinAddress.from_pubkey(self.public_key))
예제 #10
0
def fetch_key_for_address(key_file, address):
    keys = read_keys(key_file)
    bitcoin_secrets = [CBitcoinSecret(key) for key in keys]
    for key in bitcoin_secrets:
        addr = P2PKHBitcoinAddress.from_pubkey(key.pub)
        if str(addr) == address:
            return key

    return None
예제 #11
0
def makeSinglePrivKey():
    """
    make private key python bitcoin object
    :return: python-bitcoin key object
    """
    randbits = generateNewSecretKey()
    wifPriv = wif.privToWif(randbits.hex())
    cPrivObj = CBitcoinSecret(wifPriv)
    return cPrivObj
예제 #12
0
def get_core_priv():
    proxy = Proxy()
    address = proxy.getnewaddress()
    # address = 'tb1qntuv4la0lh072jtr6ce3avrsghnc200dgamlpq'
    proxy._call("walletpassphrase", "P@55w0rd", 5)
    wif = proxy.dumpprivkey(address)
    proxy._call("walletlock")
    print("address", address)
    return CBitcoinSecret(str(wif))
예제 #13
0
    def create_checksum_signature(self):
        key = CBitcoinSecret(self.primary_private_key.wif())
        address = P2PKHBitcoinAddress.from_pubkey(key.pub)

        signature = None

        print(self.primary_private_key.wif(), str(address))

        return str(address), signature
예제 #14
0
def sign_certs(certificates_metadata):
    """Sign certificates. Internet should be off for the scope of this function."""
    logging.info('signing certificates')
    pk = helpers.import_key()
    secret_key = CBitcoinSecret(pk)
    for uid, certificate_metadata in certificates_metadata.items():
        with open(certificate_metadata.unsigned_certificate_file_name, 'r') as cert_in, \
                open(certificate_metadata.signed_certificate_file_name, 'wb') as signed_cert:
            cert = do_sign(cert_in.read(), secret_key)
            signed_cert.write(bytes(cert, 'utf-8'))
예제 #15
0
    def test_sign_message_simple(self):
        key = CBitcoinSecret(
            "L4vB5fomsK8L95wQ7GFzvErYGht49JsCPJyJMHpB4xGM6xgi2jvG")
        address = "1F26pNMrywyZJdr22jErtKcjF8R3Ttt55G"
        message = address

        message = BitcoinMessage(message)
        signature = SignMessage(key, message)

        self.assertTrue(signature)
        self.assertTrue(VerifyMessage(address, message, signature))
예제 #16
0
def makeSinglePrivKeyNodeId(nodeid):
    """
    make and return a python bitcoin cprivobj
    :param nodeid: nodeid int
    :return: CBitcoinSecret obj
    """
    key = nodeid + 1  # we add 1 because keys cannot be 0
    privBits = key.to_bytes(32, "big")
    wifPriv = wif.privToWif(privBits.hex())
    cPrivObj = CBitcoinSecret(wifPriv)
    return cPrivObj
예제 #17
0
def print_verbose(signature, key, msg):
    secret = CBitcoinSecret(key)
    address = P2PKHBitcoinAddress.from_pubkey(secret.pub)
    message = BitcoinMessage(msg)
    print('Address: %s' % address)
    print('Message: %s' % msg)
    print('Signature: %s' % signature)
    print('Verified: %s' % VerifyMessage(address, message, signature))
    print('\nTo verify using bitcoin core:')
    print('\n`bitcoin-cli verifymessage %s \'%s\' \'%s\'`\n' %
          (address, signature.decode('ascii'), msg))
예제 #18
0
    def test_sign_message_vectors(self):
        for vector in load_test_vectors('signmessage.json'):
            key = CBitcoinSecret(vector['wif'])
            message = BitcoinMessage(vector['address'])

            signature = SignMessage(key, message)

            self.assertTrue(signature,
                            "Failed to sign for [%s]" % vector['address'])
            self.assertTrue(
                VerifyMessage(vector['address'], message, vector['signature']),
                "Failed to verify signature for [%s]" % vector['address'])
예제 #19
0
def sign_certs(certificates):
    """
    Sign certificates. Internet should be off for the scope of this function.
    :param certificates:
    :return:
    """
    logging.info('signing certificates')
    private_key = helpers.import_key()
    secret_key = CBitcoinSecret(private_key)
    for _, certificate in certificates.items():
        with open(certificate.unsigned_certificate_file_name, 'r') as cert_in, \
                open(certificate.signed_certificate_file_name, 'wb') as signed_cert:
            cert = _sign(cert_in.read(), secret_key)
            signed_cert.write(bytes(cert, 'utf-8'))
예제 #20
0
def partial_spend_p2sh(redeemScript,
                       rein,
                       daddr=None,
                       alt_amount=None,
                       alt_daddr=None):
    if daddr is None:
        daddr = rein.user.daddr
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txin_p2sh_address = CBitcoinAddress.from_scriptPubKey(txin_scriptPubKey)
    (txins, total_value) = unspent_txins(txin_p2sh_address, rein.testnet)
    if len(txins) == 0:
        raise ValueError(
            'Primary escrow is empty. Please inform client to add funds.')
    txins_str = ""
    txins_obj = []
    for txid, vout in txins:
        txins_str += " " + txid + "-" + str(vout)
        txins_obj.append(CMutableTxIn(COutPoint(lx(txid), vout)))
    fee = float(PersistConfig.get(rein, 'fee', 0.001))
    amount = round(total_value - fee, 8)
    if alt_amount:
        amount = round(amount - alt_amount, 8)
    if amount <= 0. or alt_amount > total_value - fee:
        click.echo("amount: " + str(amount) + " alt_amount: " +
                   str(alt_amount) + " total_value: " + str(total_value))
        raise ValueError(
            'Primary escrow balance too low. Please inform client to add funds.'
        )
    txouts = []
    txout = CMutableTxOut(amount * COIN,
                          CBitcoinAddress(daddr).to_scriptPubKey())
    txouts.append(txout)
    if alt_amount:
        txout_alt = CMutableTxOut(
            round(alt_amount, 8) * COIN,
            CBitcoinAddress(alt_daddr).to_scriptPubKey())
        txouts.append(txout_alt)
    tx = CMutableTransaction(txins_obj, txouts)
    ntxins = len(txins_obj)
    seckey = CBitcoinSecret(rein.user.dkey)
    sig = ""
    for i in range(0, ntxins):
        sighash = SignatureHash(txin_redeemScript, tx, i, SIGHASH_ALL)
        sig += " " + b2x(seckey.sign(sighash)) + "01"
    if alt_amount:
        return (txins_str[1:], "{:.8f}".format(amount), daddr,
                "{:.8f}".format(alt_amount), alt_daddr, sig[1:])
    return (txins_str[1:], "{:.8f}".format(amount), daddr, sig[1:])
예제 #21
0
파일: ewcore.py 프로젝트: RCasatta/ew-core
 def __init__(self):
     conf = read_config_file("ew.conf")
     if conf['entropy']:
         entropy = binascii.unhexlify(conf['entropy'])
     else:
         mnemo = Mnemonic('english')
         entropy = mnemo.to_entropy(conf['passphrase'])
     print("entropy=" + entropy.hex())
     master = BIP32Node.from_master_secret(entropy, 'BTC')
     print("master address=" + master.address())
     # /m/4544288'/0'/0'/0/0  alias
     alias = master.subkey(i=EW_DERIVATION, is_hardened=True).subkey(i=0, is_hardened=True).subkey(i=0, is_hardened=True).subkey(i=0, is_hardened=False).subkey(i=0, is_hardened=False)
     self.address = alias.address()
     print("alias address=" + self.address)
     self.key = CBitcoinSecret(alias.wif())
예제 #22
0
    def add_private_key(self):
        seckey_str = input('\nInsert private key (WIF-compressed format):')
        if len(seckey_str) != 52 or (seckey_str[0] != 'K'
                                     and seckey_str[0] != 'L'):
            print("The key format is not valid!")
            return
        seckey = CBitcoinSecret(seckey_str)
        '''
        Calculate and store each data element of the scriptPubKey/scriptSig related to this private key.
        These data elements will be used in the Bloom Filters.
         
        From BIP 37:
        For each output, test each data element of the output script. This means each hash and key in the output script is tested independently. 
        For each input, test each data element of the input script (note: input scripts only ever contain data elements).
        
        The default scriptPubKey/scriptSig used by Bitcoin Core 0.16.0 are:
        - scriptPubKey: OP_HASH160 [20-byte-hash of {OP_0 hash160[pubkey]}] OP_EQUAL
        - scriptSig: 0x16 OP_0 hash160[pubkey]
        
        Note: 0x16 => The next opcode bytes is data to be pushed onto the stack

        The data element of the scriptSig should be only hash160[pubkey].
        Using only that data element the bloom filter doesn't work properly.
        Instead the filter works well using OP_0 hash160[pubkey].
        '''
        scriptPubKey_data_element = bitcoin.core.Hash160(
            CScript([OP_0, bitcoin.core.Hash160(seckey.pub)]))
        scriptSig_data_element = CScript(
            [OP_0, bitcoin.core.Hash160(seckey.pub)])
        # Calculate and store also scriptPubKey/scriptSig
        scriptSig = CScript(
            [CScriptOp(0x16), OP_0,
             bitcoin.core.Hash160(seckey.pub)])
        scriptPubKey = CScript([OP_0, bitcoin.core.Hash160(seckey.pub)
                                ]).to_p2sh_scriptPubKey()
        self.keys[seckey_str] = {
            "data_elements":
            [b2x(scriptPubKey_data_element),
             b2x(scriptSig_data_element)],
            "scriptSig":
            b2x(scriptSig),
            "scriptPubKey":
            b2x(scriptPubKey)
        }
        self.save_to_file()
예제 #23
0
def partial_spend_p2sh_mediator_2 (redeemScript,txins_str,amount,daddr,rein):
    txin_redeemScript = CScript(x(redeemScript))
    txin_scriptPubKey = txin_redeemScript.to_p2sh_scriptPubKey()
    txins_obj = []
    for txin_str in txins_str.split():
        txin_list = txin_str.split("-")
        txins_obj.append(CMutableTxIn(COutPoint(lx(txin_list[0]),int(txin_list[1]))))
    txout = CMutableTxOut(amount*COIN,CBitcoinAddress(daddr).to_scriptPubKey())
    tx = CMutableTransaction(txins_obj,[txout])
    seckey = CBitcoinSecret(rein.user.dkey)
    ntxins = len(txins_obj)
    for i in range(0,ntxins):
        sighash = SignatureHash(txin_redeemScript,tx,i,SIGHASH_ALL)
        sig = seckey.sign(sighash)+x("01")
        txins_obj[i].scriptSig = CScript([OP_0, sig, txin_redeemScript])
        #VerifyScript(txins_obj[i].scriptSig, txin_scriptPubKey, tx, i, (SCRIPT_VERIFY_P2SH,))
    tx_bytes = tx.serialize()
    return b2x(tx_bytes)
예제 #24
0
 def test_signmessagewithprivkey(self):
     """As of now, signmessagewithprivkey returns string of 
     signature. Later this should change 
     """
     if self._IS_ACTIVE:
         proxy = bitcoin.rpc.Proxy()
         c_sig = "Hy+OtvwJnE0ylgORtqG8/U9ZP11IW38GaSCxIvlAcrLVGWJV61Zxfb/h/A51VPEJZkIFogqxceIMTCppfEOyl5I="
         privkey_txt = "Kya9eoTsoct6rsztC5rSLfuU2S4Dw5xtgCy2uPJgbkSLXd4FqquD"
         privkey = CBitcoinSecret(privkey_txt)
         msg = "So Long as Men Die"
         # Check from CBitcoinSecret
         sig = proxy.signmessagewithprivkey(privkey, msg)
         self.assertEqual(sig, c_sig)
         # Check from str
         sig2 = proxy.signmessagewithprivkey(privkey_txt, msg)
         self.assertEqual(sig2, c_sig)
     else:
         pass
예제 #25
0
    def sign_certs(self, certificates):
        """
        Sign certificates. Internet should be off for the scope of this function.
        :param certificates:
        :return:
        """
        logging.info('signing certificates')

        self.secret_manager.start()
        wif = self.secret_manager.get_wif()

        secret_key = CBitcoinSecret(wif)
        for _, certificate in certificates.items():
            with open(certificate.unsigned_cert_file_name, 'r') as cert_in, \
                    open(certificate.signed_cert_file_name, 'wb') as signed_cert:
                cert = _sign(cert_in.read(), secret_key)
                signed_cert.write(bytes(cert, 'utf-8'))
        self.secret_manager.stop()
    def analyze_key_pair(self, key_pair):
        #pub = binascii.unhexlify(key_pair["pub"])
        pub = CBitcoinSecret(key_pair["priv"]).pub

        return {
            "addr": {
                "base58": key_pair["addr"]
            },
            "pub": {
                "hex": key_pair["pub"],
                "bin": pub
            },
            "priv": {
                "wif": key_pair["priv"],
                "hex": None,
                "bin": None
            }
        }
예제 #27
0
def sign(to_sign, private_key, options, chain_name='mainnet'):
    import copy
    copy = copy.deepcopy(to_sign)
    if 'signature' in copy:
        del copy['signature']

    # normalize and get data to hash
    normalized = normalize_jsonld(to_sign)
    to_hash = _getDataToHash(normalized, options=options)

    # TODO: obtain lock while modifying global state
    bitcoin.SelectParams(chain_name)
    message = BitcoinMessage(to_hash)
    secret_key = CBitcoinSecret(private_key)
    signature = SignMessage(secret_key, message)

    # compact just signature part against all contexts
    signature_payload = {
        '@context': SECURITY_CONTEXT_URL,
        'type': algorithm,
        'creator': options.creator,
        'created': options.created,
        'signatureValue': signature.decode('utf-8')
    }

    tmp = {'https://w3id.org/security#signature': signature_payload}

    prev_contexts = JsonLdProcessor.get_values(to_sign, '@context')
    if not SECURITY_CONTEXT_URL in prev_contexts:
        prev_contexts.append(SECURITY_CONTEXT_URL)
    c = {'@context': prev_contexts}
    res = jsonld.compact(tmp,
                         c,
                         options={'documentLoader': cached_document_loader})
    copy['@context'] = prev_contexts
    copy['signature'] = res['signature']
    return copy
    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
def sign_message(message, private_key):
    key = CBitcoinSecret(private_key)
    return SignMessage(key=key, message=BitcoinMessage(message)).decode()
예제 #30
0
 def sign(privKey, m):
     secret = CBitcoinSecret(privKey)
     message = BitcoinMessage(m)
     return SignMessage(secret, message)