Exemple #1
0
def create_p2sh():
    '''
    This method creates a P2SH address containing a CHECKLOCKTIMEVERIFY plus
    a P2PKH locking funds with a key up to specific blockchain height
    
    Arguments:
        pubKey: public key for the P2PKH part of the redeem script
        lockBlocks: absolute lock (set to blockchain height)
    Returns:        
        lock_block_height: the specific blockchain height lock (in blocks)
        new_addr_privk: the private key of created P2SH address
        p2sh_addr: the new P2SH address
    '''

    # Setup the network
    setup('regtest')

    # Initialize proxy for RPC calls
    rpcuser = "******"
    rpcpassword = "******"
    rpc_con = AuthServiceProxy("http://%s:%[email protected]:18443" %
                               (rpcuser, rpcpassword))

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

    # Create a new Bitcoin Address (P2PKH)
    # Call the node's getnewaddress JSON-RPC method
    # Returns the address' Public Key
    new_addr_pubk = rpc_con.getnewaddress()

    # ***** Accept a future time expressed either in block height or in UNIX
    #       Epoch time

    # Numbers of blockchain height corresponding to absolute lock time
    lock_block_height = 103

    # Get the corresponding private key from the wallet
    # Call the node's dumpprivkey JSON-RPC method
    new_addr_privk = rpc_con.dumpprivkey(new_addr_pubk)

    # Get information about current blockchain height
    # Call the node's getblockcount JSON-RPC method
    current_block_height = rpc_con.getblockcount()
    if (lock_block_height < current_block_height):
        print(
            '\n***BEWARE*** Given lock (%d blocks) is lower than current blockchain height (%d blocks)'
            % (lock_block_height, current_block_height))
    else:
        print('Current blockchain height: %d blocks' % current_block_height)
        print('Fund\'s lock is set to: %d blocks' % lock_block_height)

    # Setting up an appropriate sequence to provide the script
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock_block_height)

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

    # Get the P2PKH address (from the public key)
    p2pkh_addr = p2pkh_sk.get_public_key().get_address()

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

    # Create a P2SH address from a redeem script
    p2sh_addr = P2shAddress.from_script(redeem_script)

    # VERY IMPORTANT: I must insert P2SH address into my wallet
    rpc_con.importaddress(p2sh_addr.to_address())

    # ***** Display the P2SH address
    print(
        '\nNewly created P2SH address with absolute lock set to %d blockchain height:'
        % lock_block_height)
    print(p2sh_addr.to_address())

    return (lock_block_height, new_addr_privk, p2sh_addr.to_address())
 def test_p2sh_creation(self):
     script = Script([self.pub.to_hex(), 'OP_CHECKSIG'])
     addr = P2shAddress.from_script(script)
     self.assertTrue(addr.to_string(), self.p2sh_address)
 def test_p2sh_p2wsh_creation_1multisig(self):
     p2wpkh_key = PrivateKey.from_wif('cNn8itYxAng4xR4eMtrPsrPpDpTdVNuw7Jb6kfhFYZ8DLSZBCg37')
     script = Script(['OP_1', p2wpkh_key.get_public_key().to_hex(), 'OP_1', 'OP_CHECKMULTISIG'])
     p2wsh_addr = P2wshAddress.from_script(script)
     p2sh_p2wsh_addr = P2shAddress.from_script(p2wsh_addr.to_script_pub_key())
     self.assertTrue(p2sh_p2wsh_addr.to_address(), self.correct_p2sh_p2wsh_address)
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}')
def main():
    # always remember to setup the network
    setup('testnet')

    #
    # This script creates a P2SH address containing a P2PK script and sends
    # some funds to it
    #

    #
    # create transaction output using P2SH scriptPubKey (locking script)
    # (the recipient will give us the final address  but for now we create it
    # for demonstration purposes)
    #

    # secret key corresponding to the pubkey needed for the P2SH (P2PK) transaction
    p2pk_sk = PrivateKey(
        'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
    p2pk_pk = p2pk_sk.get_public_key().to_hex()
    redeem_script = Script([p2pk_pk, 'OP_CHECKSIG'])

    #TESTE_SUZANA
    addressObj = P2shAddress.from_script(redeem_script)
    print("addressObj=" + addressObj.to_address())
    #TESTE_SUZANA

    # you can initially spend a specific UTXO that you know (e.g. with the txid after you send some funds to the address).  Then if everything works you can use the address to find all tx in that address and spend them. Make sure the timelock works and that you can spend the funds as expected.

    # The 2nd program should display the raw signed transaction that is to be sent to a bitcoin node plus _send_ the transaction to a node. The last part is not possible with the bitcoin-utils library since I have not impl. a node proxy yet. So you have to use another lib or finish with the cli commands (commented out of course) that I have to run in order to send the raw tx to a bitcoin node.
    # The P2SH addr could be recalculated in 2nd program since we have the redeem script! Providing the P2SH addr saves you from this small calculation and 'connects' the 2 programs :-)

    # Re fees, I would rather you calculate the 'appropriate' fee and explain in comments how/why you did it this way. Ideally, you would consult an online service to get an estimate of the appropriate fee. This is minor for assignment purposes but major for production systems.

    #https://bitcoin.stackexchange.com/questions/83650/how-does-nsequence-check-sequence-verify-work
    #The 2nd program requires a private key as well... that is what unlock the funds.

    ##### NAO PRECISA PARA O ASSIGNMENT DAQUI EM DIANTE #######

    # create transaction input from tx id of UTXO (contained 0.1 tBTC)
    txin = TxInput(
        '76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f', 0)

    # address we are spending from
    from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR')

    # secret key of address that we are trying to spent
    sk = PrivateKey('cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo')

    #SUZANA ---- ASSINA COM P2SH do SCRIPT
    txout = TxOutput(0.09, redeem_script.to_p2sh_script_pub_key())

    # no change address - the remaining 0.01 tBTC will go to miners)

    # create transaction from inputs/outputs -- default locktime is used
    tx = Transaction([txin], [txout])

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

    # use the private key corresponding to the address that contains the
    # UTXO we are trying to spend to create the signature for the txin
    sig = sk.sign_input(tx, 0, from_addr.to_script_pub_key())
    #print(sig)

    # get public key as hex
    pk = sk.get_public_key()
    pk = pk.to_hex()
    #print (pk)

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

    # print raw signed transaction ready to be broadcasted
    print("\nRaw signed transaction:\n" + signed_tx)
    print("\nTxId:", tx.get_txid())
 def test_p2sh_p2wpkh_creation_pubkey(self):
     addr = PrivateKey.from_wif('cTmyBsxMQ3vyh4J3jCKYn2Au7AhTKvqeYuxxkinsg6Rz3BBPrYKK').get_public_key().get_segwit_address()
     p2sh_addr = P2shAddress.from_script(addr.to_script_pub_key())
     self.assertTrue(p2sh_addr.to_address(), self.correct_p2sh_p2wpkh_address)
Exemple #7
0
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))

# get address from public key
address = pubkey.get_address()

# get hash of address
hash = address.to_hash160()

# create redeem script
script = Script([
    blockheight, 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160',
    hash, 'OP_EQUALVERIFY', 'OP_CHECKSIG'
])
print("redeem script: " + str(script.get_script()))

# get P2SH address
P2SHaddress = P2shAddress.from_script(script)

#
# 3) display the P2SH address
#

print("p2sh address: " + P2SHaddress.to_string())
Exemple #8
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()
 def test_p2shaddress_to_script_pub_key(self):
     script = Script([self.pub.to_hex(), 'OP_CHECKSIG'])
     fromScript = Script.to_p2sh_script_pub_key(script).to_hex()
     addr = P2shAddress.from_script(script)
     fromP2shAddress = addr.to_script_pub_key().to_hex()
     self.assertTrue(fromScript, fromP2shAddress)
Exemple #10
0
def generate():
    # Tells the library what network we are using
    setup()

    if not mnemonic_phrase:
        # Generate mnemonic from random 192-bit entropy
        entropy_bytes = Bip39EntropyGenerator(
            Bip39EntropyBitLen.BIT_LEN_192).Generate()
        mnemonic = Bip39MnemonicGenerator.FromEntropy(entropy_bytes)
        print("Generated random mnemonic:\n" + mnemonic)
    else:
        print("Using included mnemonic.")
        mnemonic = mnemonic_phrase

    # Get seed bytes from mnemonic
    seed_bytes = Bip39SeedGenerator(mnemonic).Generate()
    bip44_mst = Bip44.FromSeed(
        seed_bytes, Bip44Coins.BITCOIN)  # Could add in multi currency support

    # Derive account 0 for Bitcoin: m/44'/0'/0'
    bip44_acc = bip44_mst.Purpose() \
                        .Coin()    \
                        .Account(0)

    # Derive the external chain: m/44'/0'/0'/0
    bip44_change = bip44_acc.Change(Bip44Changes.CHAIN_EXT)

    with open(output_dest, 'w') as output_file:  # Open the output file
        output_file.write("address, public_key" +
                          (", private_key" if privates else "") + "\n")
        # Go through each address
        for i in range(number):
            bip44_addr = bip44_change.AddressIndex(i)

            # create segwit address
            addr3 = PrivateKey.from_wif(bip44_addr.PrivateKey().ToWif(
            )).get_public_key().get_segwit_address()
            # wrap in P2SH address
            addr4 = P2shAddress.from_script(addr3.to_script_pub_key())

            if addr4.to_string() == compare:
                print("Found it!")
                print("Path: m/44'/0'/0'/0/" + str(i))
                break
            #print("P2SH(P2WPKH):", addr4.to_string())
            if (i % int(number / 10)) == 0:
                print('Finished {}'.format(i))

            out = "{0}, {1}".format(addr4.to_string(),
                                    bip44_addr.PublicKey().ToExtended()
                                    )  # Public addresses not including private
            if (privates):  # Include the private keys
                out = "{0}, {1}, {2}".format(
                    addr4.to_string(),
                    bip44_addr.PublicKey().RawCompressed().ToHex(),
                    bip44_addr.PrivateKey().ToWif())
                #bip44_addr.PublicKey().ToAddress() # This is the regular address (not P2SH(P2WPKH))

            # Print extended keys and address
            if (verbose):
                print(out)

            output_file.write(out + "\n")
Exemple #11
0
def main():
    # always remember to setup the network
    setup('testnet')

    #
    # This script creates a P2SH address containing a P2PK script and sends
    # some funds to it
    #

    #
    # create transaction output using P2SH scriptPubKey (locking script)
    # (the recipient will give us the final address  but for now we create it
    # for demonstration purposes)
    #

    # secret key corresponding to the pubkey needed for the P2SH (P2PK) transaction
    p2pk_sk = PrivateKey(
        'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
    p2pk_pk = p2pk_sk.get_public_key().to_hex()
    redeem_script = Script([p2pk_pk, 'OP_CHECKSIG'])

    #TESTE_SUZANA
    addressObj = P2shAddress.from_script(redeem_script)
    print("addressObj=" + addressObj.to_address())
    #TESTE_SUZANA

    # create transaction input from tx id of UTXO (contained 0.1 tBTC)
    txin = TxInput(
        '76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f', 0)

    # address we are spending from
    from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR')

    # secret key of address that we are trying to spent
    sk = PrivateKey('cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo')

    #SUZANA ---- ASSINA COM P2SH do SCRIPT
    txout = TxOutput(0.09, redeem_script.to_p2sh_script_pub_key())

    # no change address - the remaining 0.01 tBTC will go to miners)

    # create transaction from inputs/outputs -- default locktime is used
    tx = Transaction([txin], [txout])

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

    # use the private key corresponding to the address that contains the
    # UTXO we are trying to spend to create the signature for the txin
    sig = sk.sign_input(tx, 0, from_addr.to_script_pub_key())
    #print(sig)

    # get public key as hex
    pk = sk.get_public_key()
    pk = pk.to_hex()
    #print (pk)

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

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