示例#1
0
def main():

    #Connect to the regtest
    setup('regtest')
    proxy = NodeProxy('user', 'bitcoin').get_proxy()

    #Accept a Public Key from User and derive a P2PKH address from it
    pk = PublicKey.from_hex(input('Please input your Public Key\n'))
    pk_p2pkh_addr = pk.get_address()

    #Accept future absolute block amount from User
    current_blocks = proxy.getblockcount()
    absolute_blocks = int(
        input(
            f'\nPlease input the future block height. The current block height is: {current_blocks}\n'
        ))

    #Set the timelock sequence and create a redeemScript accordingly

    redeem_script = Script([
        absolute_blocks, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        pk_p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    #Generate a P2SH Address from the redeemScript and show it
    p2sh_addr = P2shAddress.from_script(redeem_script)
    print(
        f'\nThe P2SH Address is:\n{p2sh_addr.to_string()} Now, go on and send some funds to it.\n'
    )
示例#2
0
def main():
    # always remember to setup the network
    setup('testnet')

    # get a node proxy using default host and port
    proxy = NodeProxy('rpcuser', 'rpcpw').get_proxy()

    # call the node's getblockcount JSON-RPC method
    count = proxy.getblockcount()

    # call the node's getblockhash JSON-RPC method
    block_hash = proxy.getblockhash(count)

    # call the node's getblock JSON-RPC method and print result
    block = proxy.getblock(block_hash)
    print(block)

    # print only the difficulty of the network
    print(block['difficulty'])
示例#3
0
def issue_op_return(conf, op_return_bstring, interactive=False):

    op_return_hex = binascii.hexlify(op_return_bstring).decode()

    if interactive:
        print('\nConfigured values are:\n')
        print('working_directory:\t{}'.format(conf.working_directory))
        print('issuing_address:\t{}'.format(conf.issuing_address))
        print('full_node_url:\t\t{}'.format(conf.full_node_url))
        print('full_node_rpc_user:\t{}'.format(conf.full_node_rpc_user))
        print('testnet:\t\t{}'.format(conf.testnet))
        print('tx_fee_per_byte:\t{}'.format(conf.tx_fee_per_byte))
        print('Bytes for OP_RETURN:\n{}'.format(op_return_bstring))
        print('Hex for OP_RETURN:\n{}'.format(op_return_hex))

    op_return_cert_protocol = op_return_hex

    if interactive:
        consent = input('Do you want to continue? [y/N]: ').lower() in ('y', 'yes')
        if not consent:
            sys.exit()

    # test explicitly when non interactive
    if not conf.full_node_rpc_password and interactive:
        conf.full_node_rpc_password = getpass.getpass('\nPlease enter the password for the node\'s RPC user: '******'testnet')
    else:
        setup('mainnet')

    host, port = conf.full_node_url.split(':')   # TODO: update when NodeProxy accepts full url!
    proxy = NodeProxy(conf.full_node_rpc_user, conf.full_node_rpc_password,
                      host, port).get_proxy()

    # create transaction
    tx_outputs = []
    unspent = sorted(proxy.listunspent(1, 9999999, [conf.issuing_address]),
                     key=lambda x: x['amount'], reverse=False)

    if not unspent:
        raise ValueError("No UTXOs found")

    issuing_pubkey = proxy.getaddressinfo(conf.issuing_address)['pubkey']

    tx = None
    tx_inputs = []
    inputs_amount = 0

    # coin selection: use smallest UTXO and if not enough satoshis add next
    # smallest, etc. until sufficient tx fees are accumulated
    # TODO wrt dust instead of adding another UTXO we should just remove the
    # change_output and allocate the remaining (<546sats) to fees
    for utxo in unspent:
        txin = TxInput(utxo['txid'], utxo['vout'])
        tx_inputs.append(txin)
        inputs_amount += utxo['amount']

        change_script_out = P2pkhAddress(conf.issuing_address).to_script_pub_key()
        change_output = TxOutput(inputs_amount, change_script_out)

        op_return_output = TxOutput(0, Script(['OP_RETURN', op_return_cert_protocol]))
        tx_outputs = [ change_output, op_return_output ]

        tx = Transaction(tx_inputs, tx_outputs)

        # sign transaction to get its size
        r = proxy.signrawtransactionwithwallet(tx.serialize())
        if r['complete'] == None:
            if interactive:
                sys.exit("Transaction couldn't be signed by node")
            else:
                raise RuntimeError("Transaction couldn't be signed by node")

        signed_tx = r['hex']
        signed_tx_size = len(signed_tx)

        # calculate fees and change
        tx_fee = (signed_tx_size // 2 + 1) * conf.tx_fee_per_byte

        # TODO number_to_decimal8 is temporary here.. should used bitcoin
        # library instead
        change_amount = inputs_amount - number_to_decimal8(tx_fee / 100000000)

        # the default Bitcoin Core node doesn't allow the creation of dust UTXOs
        # https://bitcoin.stackexchange.com/questions/10986/what-is-meant-by-bitcoin-dust
        # if change is less than 546 satoshis that is considered dust (with the
        # default node parameters) then include another UTXO
        if change_amount >= 0.00000550:
            break

    if(change_amount < 0):
        if interactive:
            sys.exit("Specified address cannot cover the transaction fee of: {} satoshis".format(tx_fee))
        else:
            raise RuntimeError("insufficient satoshis, cannot create transaction")

    # update tx out for change and re-sign
    tx.outputs[0].amount = change_amount
    r = proxy.signrawtransactionwithwallet(tx.serialize())
    if r['complete'] == None:
        if interactive:
            sys.exit("Transaction couldn't be signed by node")
        else:
            raise RuntimeError("Transaction couldn't be signed by node")
    signed_tx = r['hex']

    # send transaction
    if interactive:
        print('The fee will be {} satoshis.\n'.format(tx_fee))
        consent = input('Do you want to issue on the blockchain? [y/N]: ').lower() in ('y', 'yes')
        if not consent:
            sys.exit()

    tx_id = proxy.sendrawtransaction(signed_tx)
    return tx_id
def get_connection():
    global proxy
    proxy = NodeProxy(rpcuser='******', rpcpassword='******', port="18443").get_proxy()
#
# Enter private key and bitcoin node username and password here
#

USERNAME      = '******'
PASSWORD_HASH = 'ti8KMfu1Afeh8UZYYN32Lqo5NfBIN6tC-pnSW-OBp7A='
PRIVATE_KEY   = 'cSyZjejfhK5gaVYoG9pgfdMrZzw7rXufpiG4oDaYShanJhwpqGcE'
BLOCKHEIGHT   = 1747851


#
# Connect to testnet
#

setup( 'testnet' )
proxy = NodeProxy( USERNAME, PASSWORD_HASH ).get_proxy()


#
#  1) accept a future time, expressed either in block height or in UNIX Epoch time, 
#     and a private key (to recreate the redeem script as above and also use to unlock the P2PKH part)
#

from_privkey    = PrivateKey( 'cSyZjejfhK5gaVYoG9pgfdMrZzw7rXufpiG4oDaYShanJhwpqGcE' )
from_pubkey     = from_privkey.get_public_key()
from_address    = from_pubkey.get_address()
from_hash       = from_address.to_hash160()
redeem_script   = Script( [BLOCKHEIGHT, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', from_hash, 'OP_EQUALVERIFY', 'OP_CHECKSIG'] )

#
#  2) accept a P2SH address to get the funds from (the one created by the first script)
示例#6
0
def buy_lambo(key, lock, from_addr, to_addr):
    setup(os.getenv("BUY_LAMBO_BTC_NET", "regtest"))

    # Create a proxy to JSON-RPC api
    chain = NodeProxy(os.getenv("BUY_LAMBO_RPC_USER", "rpcuser"),
                      os.getenv("BUY_LAMBO_RPC_PASSWORD",
                                "rpcpassword")).get_proxy()

    # Try executing a command to see if node is running
    try:
        chain.getblockcount()
    except Exception:
        print("Error: Node isn't working!")
        return

    # Check addresses
    if not chain.validateaddress(from_addr)["isvalid"]:
        print("Error: `from_addr` is not a valid address!")
        return
    if not chain.validateaddress(to_addr)["isvalid"]:
        print("Error: `to_addr` is not a valid address!")
        return

    # Set lock sequence prefix
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock)

    # Get public key (found from private key)
    private_key = PrivateKey(key)
    public_key = private_key.get_public_key()

    # Add address to wallet so we can get utxos from bitcoin core
    chain.importaddress(from_addr)

    # Get UTXOs
    utxos = chain.listunspent(1, 9999999, [from_addr])

    # Create inputs
    txin = []
    total_btc = Decimal(0)
    for utxo in utxos:
        # Note that for each input we set the correct nSequence
        txin.append(
            TxInput(utxo["txid"],
                    utxo["vout"],
                    sequence=seq.for_input_sequence()))
        total_btc = total_btc + utxo["amount"]

    if total_btc == 0:
        return print("\nThere aren't any UTXOs :(.")

    # Create a fee-less output
    txout = TxOutput(total_btc - Decimal(0.1),
                     P2pkhAddress(to_addr).to_script_pub_key())

    # Create dummy transaction (to calculate size)
    tx = Transaction([TxInput.copy(inpt) for inpt in txin], [txout],
                     locktime=Locktime(lock).for_transaction())

    # create the redeem script - needed to sign the transaction
    redeem_script = Script([
        seq.for_script(),
        "OP_CHECKLOCKTIMEVERIFY",
        "OP_DROP",
        "OP_DUP",
        "OP_HASH160",
        public_key.get_address().to_hash160(),
        "OP_EQUALVERIFY",
        "OP_CHECKSIG",
    ])

    # use the private key corresponding to the address that contains the
    # UTXO we are trying to spend to create the signature for the txin -
    # note that the redeem script is passed to replace the scriptSig
    for ind, txinput in enumerate(tx.inputs):
        sig = private_key.sign_input(tx, ind, redeem_script)
        txinput.script_sig = Script(
            [sig, public_key.to_hex(),
             redeem_script.to_hex()])

    # Calculate fees
    sat_per_byte = requests.get(
        "https://bitcoinfees.earn.com/api/v1/fees/recommended").json(
        )["fastestFee"]
    fee = Decimal(
        max((len(bytes.fromhex(tx.serialize())) * sat_per_byte) /
            SATOSHIS_PER_BITCOIN, 0))
    if fee == 0:
        print("WARNING: There isn't enough balance to calculate fees.")

    # Create final tx with correct txout value
    txout = TxOutput(total_btc - fee,
                     P2pkhAddress(to_addr).to_script_pub_key())
    tx = Transaction([TxInput.copy(inpt) for inpt in tx.inputs], [txout],
                     locktime=Locktime(lock).for_transaction())
    for ind, txinput in enumerate(tx.inputs):
        sig = private_key.sign_input(tx, ind, redeem_script)
        txinput.script_sig = Script(
            [sig, public_key.to_hex(),
             redeem_script.to_hex()])
    signed_tx = tx.serialize()

    # print raw transaction
    print("\nRaw unsigned transaction:\n{}".format(
        Transaction(txin, [txout]).serialize()))

    # print raw signed transaction ready to be broadcasted
    print("\nRaw signed transaction:\n{}".format(signed_tx))
    print("\nTxId: {}".format(tx.get_txid()))

    # Check if is valid and send it
    if chain.testmempoolaccept([signed_tx])[0]["allowed"]:
        chain.sendrawtransaction(signed_tx)
        print("\nSent to Block-chain! Have fun with those {} BTC.".format(
            total_btc - fee))
    else:
        print("\nCan't send (yet)!")
        print("Reason: `{}`".format(
            chain.testmempoolaccept([signed_tx])[0]["reject-reason"]))
def _fill_pdf_metadata(out_file,
                       issuer,
                       issuer_address,
                       column_fields,
                       data,
                       global_columns,
                       verify_issuer,
                       conf,
                       interactive=False):

    # create version
    version = 2

    # create issuer object (json)
    issuer = {
        "name": issuer,
        "identity": {
            "address": issuer_address,
            "verification": json.loads(verify_issuer)['methods']
        }
    }

    # create metadata object (json) and add metadata
    metadata = {}

    # add custom metadata
    if column_fields:
        metadata_fields = json.loads(column_fields)['columns']
        for f in metadata_fields:
            key = list(f)[0]
            if key in data:
                field_properties = f[key]
                field_properties['value'] = data[key]
                metadata[key] = field_properties

    # add global field metadata
    if global_columns:
        global_fields = json.loads(global_columns)['fields']
        for g in global_fields:
            key = list(g)[0]
            # note that global fields override column data
            metadata[key] = g[key]

    # now look at special owner name/pubkey columns explicitly in code
    # TODO we should probably check if the public key is valid
    owner = None
    owner_address = None
    owner_pk = None
    if '__OWNER_PK__' in data and data[
            '__OWNER_PK__'] and '__OWNER_ADDRESS__' in data and data[
                '__OWNER_ADDRESS__']:
        # TODO maybe just calculate address from public key?
        owner_address = data['__OWNER_ADDRESS__']
        owner_pk = data['__OWNER_PK__']

        owner = {
            "name": data['__OWNER_NAME__'],
            "owner_address":
            data['__OWNER_ADDRESS__'],  # TODO needed? - can be derived
            "pk": owner_pk
        }

        # add the metadata
        pdf_metadata = PdfDict(version=version,
                               issuer=json.dumps(issuer),
                               metadata=json.dumps(metadata),
                               owner=json.dumps(owner),
                               owner_proof='',
                               chainpoint_proof='')
    else:
        # add the metadata (without dumps(owner) to keep owner empty)
        pdf_metadata = PdfDict(version=version,
                               issuer=json.dumps(issuer),
                               metadata=json.dumps(metadata),
                               owner='',
                               owner_proof='',
                               chainpoint_proof='')

    pdf = PdfReader(out_file)
    if pdf.Info:
        pdf.Info.update(pdf_metadata)
    else:
        pdf.Info = pdf_metadata
    PdfWriter().write(out_file, pdf)

    # if owner exists then need to add owner_proof
    # hash pdf, sign hash message using node and add in owner_proof
    if owner:
        ##import time
        ##start = time.time()
        sha256_hash = None
        with open(out_file, 'rb') as pdf:
            sha256_hash = hashlib.sha256(pdf.read()).hexdigest()
        if (conf.testnet):
            setup('testnet')
        else:
            setup('mainnet')

        host, port = conf.full_node_url.split(
            ':')  #TODO: update when NodeProxy accepts full url!
        proxy = NodeProxy(conf.full_node_rpc_user, conf.full_node_rpc_password,
                          host, port).get_proxy()

        # Due to an old unresolved issue still pending in Bitcoin v0.20.0
        # signmessage does not support signing with bech32 key.
        # To resolve we use the public key to get the base58check encoding that
        # signmessage is happy with so that we can sign!
        if (owner_address.startswith('bc') or owner_address.startswith('tb')):
            owner_address = PublicKey(owner_pk).get_address().to_string()

        # NOTE that address (the encoding) might have changed here from bech32
        # to legacy... take care if you use it again in this function!

        sig = proxy.signmessage(owner_address, sha256_hash)

        # add owner_proof to metadata
        pdf_metadata = PdfDict(owner_proof=sig)
        pdf = PdfReader(out_file)
        pdf.Info.update(pdf_metadata)
        PdfWriter().write(out_file, pdf)
        ##end = time.time()
        ##print(end-start, " seconds")
        ##exit()

    if interactive:
        # print progress
        print('.', end="", flush=True)
示例#8
0
def main():

    #Connect to the regtest network
    setup('regtest')
    proxy = NodeProxy('user', 'bitcoin').get_proxy()

    #Accept absolute future block amount User
    current_blocks = proxy.getblockcount()
    absolute_blocks = int(
        input(
            f'\nPlease input the future block height. The current block height is: {current_blocks}.\nIt must match the one in the redeem script from which the P2SH address (with the locked funds) was derived\n'
        ))

    #Accept the Private Key from User
    sk = PrivateKey(
        input(
            '\nPlease enter your Private Key (used to create the address from which the P2SH Address was derived)\n'
        ))

    #Accept the P2SH Address with the funds
    p2sh_addr = input(
        '\nPlease enter the P2SH address which has the locked funds\n')

    #Import the address into the wallet
    proxy.importaddress(f'{p2sh_addr}')
    print(
        f'\nThe P2SH address {p2sh_addr} has been imported into the wallet.\n')

    #Get all UTXOs for this address
    all_utxos = proxy.listunspent(1, 9999999, [f'{p2sh_addr}'])
    print(f'\nAll the UTXO Objects for this address are:\n{all_utxos}\n')

    #Calculate total funds available. Aggregate all UTXO amounts.
    def totalFunds():
        total = Decimal(0)
        for utxo in all_utxos:
            total += Decimal(utxo["amount"])
        return total

    total_funds = totalFunds()
    print("Total funds available: ", total_funds)

    #Instantiate the timelock sequence
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, absolute_blocks)

    #Create an array of inputs from these UTXOs
    def getInputs():
        inputs = []
        count = 0
        for utxo in all_utxos:
            #create inputs and append them into an array
            #First, create an input
            utxo = all_utxos[count]
            txin = TxInput(utxo["txid"],
                           utxo["vout"],
                           sequence=seq.for_input_sequence())
            #then, append it to the array
            inputs.append(txin)
            ++count
        return inputs

    inputs = getInputs()

    print(f'The inputs created from these outputs are:\n {inputs}')

    #Use User's Secret Key (Accepted above) to recreate the Public Key
    pk = sk.get_public_key()

    #We recreate the P2PKH Addr to recreate the other half of the redeemScript
    p2pkh_addr = pk.get_address()

    #We recreate the redeem script
    redeem_script = Script([
        absolute_blocks, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    #Confirm that the P2SH address is the same one to which funds were sent by receating the P2SH from this redeem script
    addr = P2shAddress.from_script(redeem_script).to_string()
    print(
        f'\nCheck if this is the address with the locked funds:\n{addr} vs what you input above {p2sh_addr}'
    )

    #Accept the receiving P2PKH from User
    destination_addr = P2pkhAddress(
        input(
            '\nPlease enter the address you want to send the locked funds to:\n'
        ))

    #Calculate txn size to estimate fee from inputs only so we subtract it from funds
    tx_test = Transaction(inputs, [],
                          Locktime(absolute_blocks).for_transaction())
    tx_size = tx_test.get_size()
    # 0.0001 is an appropriate fee per byte so we use that
    est_tx_fee = tx_size / 1000 * 0.0001

    #Create a txout transferring total locked funds (minus estimated fees).
    txout = TxOutput(to_satoshis(total_funds - Decimal(est_tx_fee)),
                     destination_addr.to_script_pub_key())

    #Create Txn. Passing in the inputs, output, and the future absolute lock time
    tx = Transaction(inputs, [txout],
                     Locktime(absolute_blocks).for_transaction())

    #Print the newly created txn
    print(f'\nThe raw unsigned txn is: {tx.serialize()}\n')

    #Calulate the Appropriate Transaction Fee According to Txn Size.
    #First, get the fee estimate from network. Useful only for mainnet and testnet.
    def getFee():
        fee = proxy.estimatesmartfee(5, "ECONOMICAL")
        if fee["errors"]:
            print(
                'Network data not enough to calculate fee. Setting default fee: 0.0001 BTC'
            )
            return 0.0001
        else:
            return fee["feerate"]


#Then, calculate the size of our Txn and then multiply it by the per-byte fee

    est_fee = getFee()  #per byte
    tx_size = tx.get_size()
    print(f'\nThe transaction size is:\n{tx_size} bytes')
    tx_fee = tx_size / 1000 * est_fee
    print(f'\nThe recommended fee for this transaction is:\n{tx_fee}')

    #Need to sign all inputs
    def signInputs():
        input_index = 0
        for input in inputs:
            #Use the Secret Key corresponding to the P2SH to create the signature for the txn/ sign all inputs
            #Redeem script is passed to replace the scriptSig
            inputSig = sk.sign_input(tx, input_index, redeem_script)
            input.script_sig = Script(
                [inputSig, pk.to_hex(),
                 redeem_script.to_hex()])
            ++input_index

    signInputs()

    signed_tx = tx.serialize()

    #Print the signed raw txn, ready to be checked for validity
    print(f"\nRaw signed transaction:\n{signed_tx}")
    print(
        f"\nTransaction ready to be broadcast. Transaction Id: {tx.get_txid()}"
    )

    #Test for validity
    isValid = proxy.testmempoolaccept([f'{signed_tx}'])
    print(f'\nTransaction validity check result:\n{isValid}')

    #Broadcast txn
    #needs signed_tx
    if isValid[0]["allowed"]:
        if input('\nSend transaction to network? Y / N: ') == 'Y':
            sent_tx_id = proxy.sendrawtransaction(f'{signed_tx}')
            print(
                f'\n***The transaction with id {sent_tx_id} has been sent to the network***'
            )
        else:
            print(
                f'\nUser decided not to send the funds and exited the program.'
            )
            exit()
    else:
        reason = isValid[0]["reject-reason"]
        print(f'\nThe signed raw transaction is invalid. Reason: {reason}')
示例#9
0
 def __init__(self):
     setup('testnet')
     self.proxy = NodeProxy('bitcoinrpc', '123456').get_proxy()
示例#10
0
class Bitcoin():
    def __init__(self):
        setup('testnet')
        self.proxy = NodeProxy('bitcoinrpc', '123456').get_proxy()

    # ==============================================================================================================
    # Encode the challenge data into a bitcoin transaction.
    # The function takes as input the publickey of the paying address,
    # challenge ciphertext and user private key(in the conf file)
    # ==============================================================================================================
    def tx_encf(self, vk_p, ct_c, user_conf_file_path):
        user_conf_file = open(user_conf_file_path)
        conf = json.load(user_conf_file)

        sk_u = conf['SK']
        sk_u = PrivateKey(secret_exponent=int(sk_u, 16))
        vk_u = sk_u.get_public_key()
        addr_u = vk_u.get_address().to_string()

        #txid = '826711590bb543028418d312cf2229eba1b4fbf295fa73dbc37654085e1fc925'
        #txid = '49ab8b8f6913d5fb97c067fe9466710f62e195bab5366e484d1b2334a5b5c0c8'
        #tx_index = 1
        txid = input(
            "Fund the address: {0} \nand insert the txid:\n".format(addr_u))
        tx_index = input("tx_index:\n")
        print("txid: ", txid)
        print("tx_index: ", tx_index)

        signed_tx_hex = self._tx_encf('04' + vk_p, ct_c, sk_u, txid,
                                      int(tx_index))
        #tx_hash = "88e602cc4766edd442ee99270f2e94bf6f7625a9b49721311fc9bba4dfe8defa"
        tx_hash = self.proxy.sendrawtransaction(signed_tx_hex)
        return tx_hash

    def _tx_encf(self, vk_p, ct_c, sk_u, txin_id, txin_index):
        # create transaction input from tx id of UTXO
        txin = TxInput(txin_id, txin_index)

        # having the vk_p from the shared key generate the corresponding address for decoder to use to respond
        vk_p = PublicKey(vk_p)
        addr_p = vk_p.get_address().to_string()

        # create transaction output using P2PKH scriptPubKey for paying address
        paying_addr = P2pkhAddress(addr_p)
        paying_txout = TxOutput(0.00002, paying_addr.to_script_pub_key())

        # create an output where the address is the ciphertext
        cipher_txout = TxOutput(0.00001,
                                Script(['OP_HASH160', ct_c, 'OP_EQUAL']))

        # create transaction from inputs/outputs -- default locktime is used
        tx = Transaction([txin], [paying_txout, cipher_txout])
        #print("\nRaw unsigned transaction:\n" + tx.serialize())

        # use private key corresponding to the address that contains the UTXO we are trying to spend to sign the input
        vk_u = sk_u.get_public_key()
        addr_u = vk_u.get_address().to_string()

        # note that we pass the scriptPubkey as one of the inputs of sign_input because it is used to replace
        # the scriptSig of the UTXO we are trying to spend when creating the transaction digest
        from_addr = P2pkhAddress(addr_u)
        sig = sk_u.sign_input(
            tx, 0,
            from_addr.to_script_pub_key())  # 0 is for the index of the input

        # set the scriptSig (unlocking script)
        vk_u = vk_u.to_hex()
        txin.script_sig = Script([sig, vk_u])
        signed_tx = tx.serialize()

        print("Users input address: ", addr_u)
        print("Decoder paying address: ", addr_p)
        print("\nRaw signed transaction:\n" + signed_tx)

        return signed_tx

    # ================================================================================================
    # This function given a tx hash, decodes it and returns the user's public key and ciphertext
    # ================================================================================================
    def tx_decf(self, tx_hash):
        raw_tx = self.proxy.getrawtransaction(
            tx_hash)  # get the raw transaction from the hash of the tx
        decoded_tx = self.proxy.decoderawtransaction(
            raw_tx)  # decode the raw transaction and get the json format

        # check to see if the tx has 1 input and two outputs and is of type pay2pubkeyhash and pay2scripthash
        if len(decoded_tx['vin']) != 1 or len(decoded_tx['vout']) != 2:
            return -1, -1
        if decoded_tx['vout'][0]['scriptPubKey'][
                'hex'][:6] != '76a914' or decoded_tx['vout'][0][
                    'scriptPubKey']['hex'][-4:] != '88ac':  #pay2pubkeyhash
            return -1, -1
        if decoded_tx['vout'][1]['scriptPubKey'][
                'hex'][:4] != 'a914' or decoded_tx['vout'][1]['scriptPubKey'][
                    'hex'][-2:] != '87':  #pay2scripthash
            return -1, -1

        try:
            vk_u_compressed = decoded_tx['vin'][0]['scriptSig']['hex'][-66:]
            vk_u = PublicKey(vk_u_compressed).to_hex(compressed=False)[2:]
            ct_c = decoded_tx['vout'][1]['scriptPubKey']['hex'][4:-2]
            return vk_u, ct_c
        except:
            return -1, -1

    # ================================================================================================
    # Encode the response data into a bitcoin transaction.
    # The function takes as input the private key of the paying key (derived from the shared key)
    # and the response data (ciphertext)
    # ================================================================================================

    def tx_encb(self, sk_s, ct_r, txid):
        sk_s = PrivateKey(secret_exponent=int(sk_s, 16))
        signed_tx_hex = self._tx_encb(sk_s, ct_r, txid, txin_index=0)
        #tx_hash = "33f4e564128ab824fe5864cc281ee16cb4f58db502a682fb7dca07bf36717b11"
        tx_hash = self.proxy.sendrawtransaction(signed_tx_hex)
        return tx_hash

    def _tx_encb(self, sk_s, ct_r, txin_id, txin_index):
        # create transaction input from tx id of UTXO
        txin = TxInput(txin_id, txin_index)

        # create an output where the address is the ciphertext[0:20]
        cipher1_txout = TxOutput(
            0.000001,
            Script([
                'OP_DUP', 'OP_HASH160', ct_r[:40], 'OP_EQUALVERIFY',
                'OP_CHECKSIG'
            ]))

        # create another output where the address is the ciphertext[20:40]
        cipher2_txout = TxOutput(0.000001,
                                 Script(['OP_HASH160', ct_r[40:], 'OP_EQUAL']))

        # create transaction from inputs/outputs -- default locktime is used
        tx = Transaction([txin], [cipher1_txout, cipher2_txout])
        #print("\nRaw unsigned transaction:\n" + tx.serialize())

        # use private key corresponding to the address that contains the UTXO we are trying to spend to sign the input
        vk_p = sk_s.get_public_key()
        addr_p = vk_p.get_address().to_string()

        # note that we pass the scriptPubkey as one of the inputs of sign_input because it is used to replace
        # the scriptSig of the UTXO we are trying to spend when creating the transaction digest
        from_addr = P2pkhAddress(addr_p)
        sig = sk_s.sign_input(tx, 0, from_addr.to_script_pub_key())

        # set the scriptSig (unlocking script)
        vk_p = vk_p.to_hex()
        txin.script_sig = Script([sig, vk_p])
        signed_tx = tx.serialize()

        print("\nRaw signed transaction:\n" + signed_tx)
        return signed_tx

    # ================================================================================================
    # Given a block id and an public key of transaction return the encoded data in that transaction
    # ================================================================================================
    def tx_decb(self, block_id, vk_p):
        txs_hashes = self.get_block_txs(
            block_id)  # Get the hash of transactions inside this block
        for tx_hash in txs_hashes:
            raw_tx = self.proxy.getrawtransaction(
                tx_hash)  # get the raw transaction from the hash of the tx
            decoded_tx = self.proxy.decoderawtransaction(
                raw_tx)  # decode the raw transaction and get the json format

            # check to see if the tx has 1 input and two outputs and is of type pay2pubkeyhash
            if len(decoded_tx['vin']) != 1 or len(decoded_tx['vout']) != 2:
                continue
            if decoded_tx['vout'][0]['scriptPubKey'][
                    'hex'][:6] != '76a914' or decoded_tx['vout'][0][
                        'scriptPubKey']['hex'][-4:] != '88ac':  # pay2pubkeyhash
                continue
            if decoded_tx['vout'][1]['scriptPubKey'][
                    'hex'][:4] != 'a914' or decoded_tx['vout'][1][
                        'scriptPubKey']['hex'][-2:] != '87':  # pay2scripthash
                continue

            try:
                vk_p_compressed = decoded_tx['vin'][0]['scriptSig']['hex'][
                    -66:]
                ct_r1 = decoded_tx['vout'][0]['scriptPubKey']['hex'][6:-4]
                ct_r2 = decoded_tx['vout'][1]['scriptPubKey']['hex'][4:-2]
                if vk_p_compressed == PublicKey('04' +
                                                vk_p).to_hex(compressed=True):
                    print("Found the transaction with response message")
                    return ct_r1 + ct_r2
            except:
                continue

        return None

    # ================================================================================================
    # Given a block id return the hashes of the transactions in that block.
    # ================================================================================================
    def get_block_txs(self, block_id):
        block_hash = self.proxy.getblockhash(block_id)
        block_info = self.proxy.getblock(block_hash)
        txs_hashes = block_info[
            'tx']  # Get the hash of transactions inside this block
        return txs_hashes
示例#11
0
if __name__ == '__main__':
    # default arguments
    height = 10
    pubk = None

    # retrieve the arguments
    try:
        height = int(sys.argv[1])
        pubk = sys.argv[2]
    except IndexError:
        # ignore missing arguments
        pass

    # set up the environment for regtest
    setup('regtest')
    username, password = '******', 'pass'
    wallet = '~/.bitcoin/regtest/wallets/mywallet'
    # set up a JSON RPC proxy
    rpc_proxy = NodeProxy(username, password).get_proxy()

    # load wallet
    try:
        rpc_proxy.loadwallet(wallet)
    except JSONRPCException:
        # wallet already loaded
        pass

    # run the script
    create_p2sh(rpc_proxy, height, pubk)
示例#12
0
from bitcoinutils.script import Script

#
# Enter private key and bitcoin node username and password here
#

USERNAME = '******'
PASSWORD_HASH = 'ti8KMfu1Afeh8UZYYN32Lqo5NfBIN6tC-pnSW-OBp7A='
PRIVATE_KEY = 'cSyZjejfhK5gaVYoG9pgfdMrZzw7rXufpiG4oDaYShanJhwpqGcE'

#
# Connect to testnet
#

setup('testnet')
proxy = NodeProxy(USERNAME, PASSWORD_HASH).get_proxy()

#
# 1) accept a public (or optionally a private) key for the P2PKH part of the redeem script
#

privkey = PrivateKey(PRIVATE_KEY)
pubkey = privkey.get_public_key()

#
# 2) accept a future time expressed either in block height or in UNIX Epoch time
#

blockheight = proxy.getblockcount() + 1
print("future time in absolute block height: " + str(blockheight))
示例#13
0
def main():
    # always remember to setup the network
    setup('regtest')

    #
    # This script creates a P2SH address containing a CHECKLOCKTIMEVERIFY plus a P2PKH locking funds with a key as
    # well as for an absolute amount of blocks or an absolute amount of seconds since the transaction.
    #

    parser = argparse.ArgumentParser(
        description=
        'Give the private key, a future time expressed either in block height or in UNIX Epoch time and '
        'the P2SH address to send the funds')
    parser.add_argument('key', help="Add the private key.")
    parser.add_argument(
        '-param',
        type=int,
        help="Add the number of blocks or the time expressed in seconds.")
    parser.add_argument('-to_address',
                        type=str,
                        help="Add the adress that will sent/spend")
    args = parser.parse_args()

    # set values
    key = args.key
    absolute_param = args.param
    send_address = args.to_address

    # set Locktime
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, absolute_param)
    locktime = Locktime(absolute_param)

    # set proxy
    username = "******"
    password = "******"
    proxy = NodeProxy(username, password).get_proxy()

    # secret key corresponding to the pubkey needed for the P2SH (P2PKH) transaction
    p2pkh_sk = PrivateKey(key)

    p2pkh_pk = p2pkh_sk.get_public_key()

    # get the address (from the public key)
    p2pkh_addr = p2pkh_pk.get_address()

    # print("Private key: " + p2pkh_sk. to_wif(compressed=True))
    # print("Public key: " + p2pkh_pk.to_hex(compressed=True))
    # print("P2PKH Address: " + p2pkh_addr.to_string())

    # create the redeem script
    redeem_script = Script([
        seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    # accept a P2SH address to get the funds from
    addr = P2shAddress.from_script(redeem_script)
    print("The P2SH address to get the funds from is : " + addr.to_string())

    # check if the P2SH address has any UTXOs to get funds from

    proxy.importaddress(addr.to_string(), "P2SH to get the funds from")
    minconf = 0
    maxconf = 99999999
    my_list = proxy.listunspent(minconf, maxconf, [addr.to_string()])

    # Gather all funds that the P2SH address received to send to the P2PKH address provided

    txin_list = []
    btc_to_send = 0
    for i in my_list:
        txin = TxInput(i['txid'], i['vout'], sequence=seq.for_input_sequence())
        txin_list.append(txin)
        btc_to_send = btc_to_send + i['amount']

    if btc_to_send == 0:
        print("No btc found to send")
        quit()

    # accept a P2PKH address to send the funds to
    to_addr = P2pkhAddress(send_address)
    print("The P2PKH address to send the funds to is : " + to_addr.to_string())

    # calculate the appropriate fees with respect to the size of the transaction
    response = requests.get("https://mempool.space/api/v1/fees/recommended")
    fee_per_byte = response.json()['fastestFee']
    print("Fastest fee per byte is : %d " % fee_per_byte)

    # calculate transaction size as described at
    # https://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending-legacy-non-segwit-p2pkh-p2sh
    tx_size = len(my_list) * 180 + 34 + 10 + len(my_list)
    total_fees = tx_size * fee_per_byte / (1024 * 10**8)
    print('Total fees are : ', total_fees)

    # Calculate the final amount
    amount = btc_to_send - total_fees
    # print(amount)

    # Create transaction output
    txout = TxOutput(to_satoshis(amount), to_addr.to_script_pub_key())

    # Create transaction after the inputs and the outputs
    tx = Transaction(txin_list, [txout], locktime.for_transaction())

    # For each transaction - when dealing with multiple inputs, you will need to sign all of them
    for i, txin in enumerate(my_list):
        sig = p2pkh_sk.sign_input(tx, i, redeem_script)
        # print(sig)
        # set the scriptSig (unlocking script) -- unlock the P2PKH (sig, pk) plus
        # the redeem script, since it is a P2SH
        txin.script_sig = Script(
            [sig, p2pkh_pk.to_hex(),
             redeem_script.to_hex()])

    # display the raw signed transaction, ready to be broadcasted
    signed_tx = tx.serialize()
    print("\nRaw signed transaction:\n" + signed_tx)

    # display the raw unsigned transaction
    print("\nRaw unsigned transaction:\n" + tx.serialize())

    # display the transaction id
    print("\nTxId:", tx.get_txid())

    # verify that the transaction is valid and will be accepted by the Bitcoin nodes
    # if the transaction is valid, send it to the blockchain

    is_valid = proxy.testmempoolaccept([signed_tx])
    # print(is_valid)
    if is_valid[0]['allowed']:
        print("Transaction is valid!")
        print("Sending transaction to blockchain..")
        proxy.sendrawtransaction(signed_tx)
    else:
        print("Transaction not valid")
        quit()
示例#14
0
def main():
    # always remember to setup the network
    setup('regtest')

    # RPC credentials for communicating with the node
    rpcuser = '******'
    rpcpass = '******'
    proxy = NodeProxy(rpcuser, rpcpass).get_proxy()

    # set values
    block_height = 140

    # secret key needed to spend P2PKH that is wrapped by P2SH
    p2pkh_sk = PrivateKey(
        'cSbKZh6a6wNUAQ8pr2KLKeZCQ4eJnFmN35wtReaoU4kCP97XQu6W')
    # this is the P2SH address the funds have been locked in
    p2shaddress = '2NGWStpuXtke1VXCTgNnzUgWbun7eY2f3nH'
    # this is the address the funds will be sent to
    to_addr = P2pkhAddress('mnS1ng5D1hdvLkYAK2oS8R1C4e37aQdVoC')

    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height)
    lock = Locktime(block_height)

    # import the address as watch-only
    print('importaddress')
    proxy.importaddress(p2shaddress, "P2SH absolute timelock", True)
    # find all UTXOs for this address. 10.000.000 should be enough
    print('listunspent')
    list_unspent = proxy.listunspent(0, 9999999, [p2shaddress])

    # create transaction inputs for all UTXOs. Calculate the total amount of
    # bitcoins they contain
    txin_list = []
    total_amount = 0
    for i in list_unspent:
        txin = TxInput(i['txid'], i['vout'], sequence=seq.for_input_sequence())
        txin_list.append(txin)
        total_amount = total_amount + i['amount']
    if total_amount == 0:
        print("No funds to move")
        sys.exit(0)

    # derive public key and adddress from the private key
    p2pkh_pk = p2pkh_sk.get_public_key().to_hex()
    p2pkh_addr = p2pkh_sk.get_public_key().get_address()

    # create the redeem script - needed to sign the transaction
    redeem_script = Script([
        seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    # get fees using API. Although we may be running in regtest, we'll use the
    # fees as if we were using testnet (fees are in satoshis)
    url = 'https://api.blockcypher.com/v1/btc/test3'
    resp = requests.get(url)
    fee_per_kb = resp.json()['medium_fee_per_kb']

    # calculate transaction size according to:
    # in*180 + out*34 + 10 plus or minus 'in'
    # https://bitcoin.stackexchange.com/questions/1195/how-to-calculate-transaction-size-before-sending-legacy-non-segwit-p2pkh-p2sh
    # we'll play it safe and use the upper bound
    tx_size = len(txin_list) * 180 + 34 + 10 + len(txin_list)
    fees = tx_size * fee_per_kb / (1024 * 10**8)
    print('fees:', fees)

    # create the output
    txout = TxOutput(
        Decimal(total_amount) - Decimal(fees), to_addr.to_script_pub_key())

    # create transaction from inputs/outputs
    tx = Transaction(txin_list, [txout], lock.for_transaction())

    # use the private key corresponding to the address that contains the
    # UTXO we are trying to spend to create the signatures for all txins -
    # note that the redeem script is passed to replace the scriptSig
    for i, txin in enumerate(txin_list):
        sig = p2pkh_sk.sign_input(tx, i, redeem_script)
        # set the scriptSig (unlocking script) -- unlock the P2PKH (sig, pk) plus
        # the redeem script, since it is a P2SH
        txin.script_sig = Script([sig, p2pkh_pk, redeem_script.to_hex()])

    # serialize the transaction
    signed_tx = tx.serialize()

    # test if the transaction will be accepted by the mempool
    print('testmempoolaccept')
    res = proxy.testmempoolaccept([signed_tx])
    print(res)
    if not res[0]['allowed']:
        print("Transaction not valid")
        sys.exit(1)

    # print raw transaction
    print("\nRaw unsigned transaction:\n" + tx.serialize())
    # print raw signed transaction ready to be broadcasted
    print("\nRaw signed transaction:\n" + signed_tx)
    print("\nTxId:", tx.get_txid())
示例#15
0
def issue_op_return(conf, op_return_bstring, interactive=False):

    op_return_hex = binascii.hexlify(op_return_bstring).decode()

    if interactive:
        print('\nConfigured values are:\n')
        print('working_directory:\t{}'.format(conf.working_directory))
        print('issuing_address:\t{}'.format(conf.issuing_address))
        print('full_node_url:\t\t{}'.format(conf.full_node_url))
        print('full_node_rpc_user:\t{}'.format(conf.full_node_rpc_user))
        print('testnet:\t\t{}'.format(conf.testnet))
        print('tx_fee_per_byte:\t{}'.format(conf.tx_fee_per_byte))
        print('Bytes for OP_RETURN:\n{}'.format(op_return_bstring))
        print('Hex for OP_RETURN:\n{}'.format(op_return_hex))

    op_return_cert_protocol = op_return_hex

    if interactive:
        consent = input('Do you want to continue? [y/N]: ').lower() in ('y',
                                                                        'yes')
        if not consent:
            sys.exit()

    # test explicitly when non interactive
    if interactive:
        conf.full_node_rpc_password = getpass.getpass(
            '\nPlease enter the password for the node\'s RPC user: '******'testnet')
    else:
        setup('mainnet')

    host, port = conf.full_node_url.split(
        ':')  # TODO: update when NodeProxy accepts full url!
    proxy = NodeProxy(conf.full_node_rpc_user, conf.full_node_rpc_password,
                      host, port).get_proxy()

    # create transaction
    tx_outputs = []
    unspent = sorted(proxy.listunspent(1, 9999999, [conf.issuing_address]),
                     key=lambda x: hash(x['amount']),
                     reverse=True)

    issuing_pubkey = proxy.getaddressinfo(conf.issuing_address)['pubkey']

    tx_inputs = [TxInput(unspent[0]['txid'], unspent[0]['vout'])]
    input_amount = unspent[0]['amount']

    change_script_out = P2pkhAddress(conf.issuing_address).to_script_pub_key()
    change_output = TxOutput(input_amount, change_script_out)

    op_return_output = TxOutput(0,
                                Script(['OP_RETURN', op_return_cert_protocol]))
    tx_outputs = [change_output, op_return_output]

    tx = Transaction(tx_inputs, tx_outputs)

    # sign transaction to get its size
    r = proxy.signrawtransactionwithwallet(tx.serialize())
    if r['complete'] == None:
        if interactive:
            sys.exit("Transaction couldn't be signed by node")
        else:
            raise RuntimeError("Transaction couldn't be signed by node")

    signed_tx = r['hex']
    signed_tx_size = len(signed_tx)

    # calculate fees and change
    tx_fee = (signed_tx_size // 2 + 1) * conf.tx_fee_per_byte

    # note results is sometimes in e- notation
    change_amount = input_amount - (tx_fee / 100000000)

    if (change_amount < 0):
        if interactive:
            sys.exit(
                "Specified address cannot cover the transaction fee of: {} satoshis"
                .format(tx_fee))
        else:
            raise RuntimeError(
                "insufficient satoshis, cannot create transaction")

    # update tx out for change and re-sign
    tx.outputs[0].amount = change_amount
    r = proxy.signrawtransactionwithwallet(tx.serialize())
    if r['complete'] == None:
        if interactive:
            sys.exit("Transaction couldn't be signed by node")
        else:
            raise RuntimeError("Transaction couldn't be signed by node")
    signed_tx = r['hex']

    # send transaction
    if interactive:
        print('The fee will be {} satoshis.\n'.format(tx_fee))
        consent = input('Do you want to issue on the blockchain? [y/N]: '
                        ).lower() in ('y', 'yes')
        if not consent:
            sys.exit()

    tx_id = proxy.sendrawtransaction(signed_tx)
    return tx_id