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
    # until a certain block_height is reached
    #

    # set values
    block_height = 140

    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height)

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

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

    # 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'])

    # create a P2SH address from a redeem script
    addr = P2shAddress.from_script(redeem_script)
    print(addr.to_string())
示例#2
0
def create_HODL_address(key, lock, is_priv=False):
    setup(os.getenv("BUY_LAMBO_BTC_NET", "regtest"))

    # Get public key (given or found from private key)
    public_key = PrivateKey(key).get_public_key() if is_priv else PublicKey(key)

    # Get address from public key
    address_from_key = public_key.get_address()

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

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

    # create a P2SH address from a redeem script
    addr = P2shAddress.from_script(redeem_script)
    print("Time-locked address: {}".format(addr.to_string()))
示例#3
0
def main():
    # always remember to setup the network
    setup('testnet')

    #
    # This script creates a P2SH address containing a CHECKSEQUENCEVERIFY plus
    # a P2PKH locking funds with a key as well as for 20 blocks
    #

    # set values
    relative_blocks = 20

    seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks)

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

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

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

    # create a P2SH address from a redeem script
    addr = P2shAddress.from_script(redeem_script)
    print(addr.to_string())
示例#4
0
    def setUp(self):
        setup('testnet')
        self.txin = TxInput(
            "76464c2b9e2af4d63ef38a77964b3b77e629dddefc5cb9eb1a3645b1608b790f",
            0)
        self.from_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR')
        self.sk = PrivateKey(
            'cTALNpTpRbbxTCJ2A5Vq88UxT44w1PE2cYqiB3n4hRvzyCev1Wwo')
        self.p2pk_sk = PrivateKey(
            'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
        self.p2pk_redeem_script = Script(
            [self.p2pk_sk.get_public_key().to_hex(), 'OP_CHECKSIG'])
        self.txout = TxOutput(to_satoshis(0.09),
                              self.p2pk_redeem_script.to_p2sh_script_pub_key())
        self.create_p2sh_and_send_result = '02000000010f798b60b145361aebb95cfcdedd29e6773b4b96778af33ed6f42a9e2b4c4676000000006b483045022100fd3a3fd4aeec5db0f3f9c5c5ef7f60f37920be7464a80edacbc3b6b9d0624173022031ce309330e60b19d39cec8c5597460c840adcdd66f7dbbf896eef3ec42b472f012102d82c9860e36f15d7b72aa59e29347f951277c21cd4d34822acdeeadbcff8a546ffffffff01405489000000000017a9142910fc0b1b7ab6c9789c5a67c22c5bcde5b903908700000000'

        self.txin_spend = TxInput(
            '7db363d5a7fabb64ccce154e906588f1936f34481223ea8c1f2c935b0a0c945b',
            0)
        # self.p2pk_sk , self.p2pk_redeem_script from above
        self.to_addr = self.from_addr
        self.txout2 = TxOutput(to_satoshis(0.08),
                               self.to_addr.to_script_pub_key())
        self.spend_p2sh_result = '02000000015b940c0a5b932c1f8cea231248346f93f18865904e15cecc64bbfaa7d563b37d000000006c47304402204984c2089bf55d5e24851520ea43c431b0d79f90d464359899f27fb40a11fbd302201cc2099bfdc18c3a412afb2ef1625abad8a2c6b6ae0bf35887b787269a6f2d4d01232103a2fef1829e0742b89c218c51898d9e7cb9d51201ba2bf9d9e9214ebb6af32708acffffffff0100127a00000000001976a914fd337ad3bf81e086d96a68e1f8d6a0a510f8c24a88ac00000000'

        # P2SH(CSV+P2PKH)
        self.sk_csv_p2pkh = PrivateKey(
            'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
        self.seq = Sequence(TYPE_RELATIVE_TIMELOCK, 200)
        self.txin_seq = TxInput(
            'f557c623e55f0affc696b742630770df2342c4aac395e0ed470923247bc51b95',
            0,
            sequence=self.seq.for_input_sequence())
        self.another_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR')
        self.spend_p2sh_csv_p2pkh_result = '0200000001951bc57b24230947ede095c3aac44223df70076342b796c6ff0a5fe523c657f5000000008a483045022100c123775e69ec27094f7940facb9ad769c09f48a7fc88250a2fce67bd92c9b4cf02204ebdbed84af46e584fe6db9a23c420b7370879e883b555e119465f84bf34d82f012103a2fef1829e0742b89c218c51898d9e7cb9d51201ba2bf9d9e9214ebb6af327081e02c800b27576a914c3f8e5b0f8455a2b02c29c4488a550278209b66988acc80000000100ab9041000000001976a914fd337ad3bf81e086d96a68e1f8d6a0a510f8c24a88ac00000000'
示例#5
0
    def get_CSV_Seq_Value(cls, epochlockperiod, blockslockPeriod):
        """
        bip related conversion for correct csv sequencing
        """
        # keep only the first 16 bits by stripping the rest
        epochlockperiod &= cls.SEQUENCE_LOCKTIME_MASK

        if epochlockperiod > 0:
            print('lock seconds: ' + str(epochlockperiod))
            return Sequence(TYPE_RELATIVE_TIMELOCK, epochlockperiod)

        elif blockslockPeriod >= 0:

            print('blocks to lock: ' + str(blockslockPeriod))

            # blocks even if zero as a default parameter to the csv script
            return Sequence(TYPE_RELATIVE_TIMELOCK, blockslockPeriod)

        else:
            return 0
示例#6
0
def getTxEROutputLockScript(pubkey: PublicKey, rel_timelock: int) -> Script:
    """
    Create lock script for output of enable-refund transaction

    :param pubkey: public key owned by corresponding payment participant
    :param rel_timelock: relative lock on outputs. Should be same for all outputs of transaction
    :return: lock script
    """

    seq = Sequence(TYPE_RELATIVE_TIMELOCK, rel_timelock)
    return Script([seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160', pubkey.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])
示例#7
0
    def get_redeem_script_from_conf(cls, pub_key_obj):
        """
        Great when method name are self explanatory
        """
        csv_args = cls.get_relative_time_seconds_blocks()
        seq_number_in_hex = Sequence(TYPE_RELATIVE_TIMELOCK, csv_args)

        print("seconds to wait: " +
              str(csv_args[0]) + ", blocks to wait: " + str(csv_args[1]))
        print('sequence number in little endian format: ' + seq_number_in_hex)

        redeem_script = cls.get_redeem_script(seq_number_in_hex, pub_key_obj)

        to_P2SH_addr = P2shAddress.from_script(redeem_script)
        print('Redeem script generated P2SH addr: ' +
              to_P2SH_addr.to_address() + "\n")

        return redeem_script
示例#8
0
    def get_redeem_script_from_conf(cls, pub_key_obj):
        """
        Return a P2SH address for a redemption scription encaptulating 
            CHECKSEQUENCEVERIFY
                +
            P2PKH script with a paying to public address possibly locked up to
            x blocks read from program.conf [relative_blocks_to_wait] 
        """
        blocks_wait = Common.get_conf_wait_blocks()

        seq_number_in_hex = Sequence(TYPE_RELATIVE_TIMELOCK, blocks_wait)

        redeem_script = cls.get_redeem_csv_script(seq_number_in_hex,
                                                  pub_key_obj)

        to_P2SH_addr = P2shAddress.from_script(redeem_script)
        print('Redeem script generated P2SH addr: ' +
              to_P2SH_addr.to_string() + "\n")

        return redeem_script
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 public key, a future time expressed either in block height or in UNIX Epoch time and '
                    'the P2SH address will be displayed') 
    parser.add_argument('pubkey', help="Add the public key.")
    parser.add_argument('-param', type=int, help="Add the number of blocks or the time expressed in seconds.")
    args = parser.parse_args()

    # set values
    key = args.pubkey
    absolute_param = args.param

    p2pkh_pk = PublicKey(key)

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

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

    # 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'])

    # create a P2SH address from a redeem script
    addr = P2shAddress.from_script(redeem_script)
    print("The P2SH address is : " + addr.to_string())
def main() :
    setup('testnet')
    
    relative_blocks = 20
    
    seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks)
    
    p2pkh_sk = PrivateKey('cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
    
    p2pkh_addr = p2pkh_sk.get_public_key().get_address()
    
    print("Address : " + p2pkh_addr.to_string())
    
    
    redeem_script = Script([seq.for_script(), 'OP_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP', 'OP_HASH160'
                            , p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'])
    
    
    addr = P2shAddress.from_script(redeem_script)
    
    
    print(addr.to_string())
示例#11
0
def create_p2sh(proxy, block_height=10, address_pubk=None):
    """
    Creates a P2SH address with an absolute block locktime.

        :param proxy: JSON RPC proxy for connecting to the network.
        :param block_height: Block height the lock is valid for. Default value is 10.
        :param address_pubk: Public key of the address locking the funds. If None, a new address will be created.
    """

    # if a public key is not specified, create a new address and display its keys for future use
    if not address_pubk:
        print('Public key not provided. Created a new address.')
        address = proxy.getnewaddress()
        print('Address:', address)
        address_privk = proxy.dumpprivkey(address)
        print('Private key:', address_privk)
        address_pubk = proxy.getaddressinfo(address)['pubkey']
        print('Public key:', address_pubk)
    # create the public key object
    p2pkh_pk = PublicKey(address_pubk)

    # create sequence for the redeem script
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height)
    # create the redeem script
    redeem_script = Script([
        seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        p2pkh_pk.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    # create the P2SH address from the redeem script
    p2sh_addr = P2shAddress.from_script(redeem_script)
    # insert the P2SH address into the wallet
    proxy.importaddress(p2sh_addr.to_string())

    # display the P2SH address
    print('Created P2SH address:', p2sh_addr.to_string())
示例#12
0
def create_spending_signed_trx(p2pkh_addr_to_str, priv_key_from_obj):
    """
    Gather related data and generate
    the single transation that transfers the btc value of the
    found UTXO transactions.

    """

    p2pkh_addr_to_obj = P2pkhAddress(p2pkh_addr_to_str)

    blocks_wait = Common.get_conf_wait_blocks()

    seq = Sequence(TYPE_RELATIVE_TIMELOCK, blocks_wait)

    redeem_script = Common.get_redeem_script_from_conf(
        get_redeem_pub_key_obj())

    p2sh_paid_to_addr = P2shAddress.from_script(redeem_script).to_string()

    utxo_results = get_input_trx_from_utxo(priv_key_from_obj,
                                           p2sh_paid_to_addr, seq,
                                           redeem_script)

    # No sense in creating a transaction with 0 UTXOs
    if utxo_results[0] > 0 and len(utxo_results[1]) > 0:

        signed_tx = get_signed_trx(utxo_results, p2pkh_addr_to_obj,
                                   priv_key_from_obj, redeem_script)

        # print raw signed transaction ready to be broadcasted
        print("\nSigned raw transaction:\n" + signed_tx)

        trasmit_finalized_trx(signed_tx)

    else:
        print("\nNo UTXOs found. Nothing to do!\n")
示例#13
0


# ***** Send all funds that the P2SH address received to the P2PKH address provided

# Didn't manage to sign a multi-input transaction so instead I will create a
# single-input transaction spending only the first UTXO found for the P2SH address

# Prepare the elements needed for the transaction

# Create the Inputs
# I will use the data from the first UTXO
in_txid, in_amount = list(p2sh_utxos.items())[0]
vout = 0
# Set sequence values for inputs as in part 1
seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, lock_block_height)
txin = TxInput(in_txid, vout, sequence=seq.for_input_sequence())

# Create the Output
# I will spend the whole input amount minus a fixed fee. No change output needed
# Clear amount to transfer
in_amount = float(in_amount)
out_amount = round(in_amount-fixed_fee, 8)
txout = TxOutput(out_amount, rec_p2pkh_addr.to_script_pub_key())

# Lock time (in blocks) to be used in transaction
lock_time = Locktime(lock_block_height).for_transaction()

# Compose transaction (Raw Unsigned Transaction)
p2sh_out_tx = Transaction(inputs=[txin], outputs=[txout], locktime=lock_time)
示例#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())
#     The string representation of this address starts with m on n, because it is a Bitcoin testnet address
address = priv.get_public_key().get_address()
address.to_string()
address.to_hash160()

address._is_address_valid(address.to_string())   # True
address._is_address_valid(address.to_hash160())  # False


# 3. Create an input sequence for a relative timelock of 10 blocks.
#    Notes: Locktime defines the earliest time that a transaction can be added to the blockchain.
#    If locktime is < 500.000.000 it is interpreted as a block height, else it is interpreted as UNIX Epoch timestamp
help(Sequence)

relative_blocks = 10
seq = Sequence(seq_type=TYPE_RELATIVE_TIMELOCK, value=relative_blocks)

seq.is_type_block  # True
seq.value          # 10

# Note: I will use regtest node (from scratch) so the relative_blocks restriction can be tested.

# 4. What is the redeem script? Create it.
#  Redeem script is a special type of script.
#  - The hash of the redeem script used to lock the outputs of a transaction.
#  - Then the redeem script used to unlock these UTXOs.

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

# Script code explanation:
# - add on top of the stack the relative_blocks number (10) and the check if this sequence have been verified, ie the locktime have been pass. (T/F)
示例#16
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()
示例#17
0
def spend_p2sh_cltv_p2pkh(proxy, block_height, sender_priv_key, p2sh_addr,
                          rec_addr):
    """
    Spends funds from a P2SH address with an absolute locktime to a P2PKH receiver address.
    :param proxy: JSON RPC proxy for connecting to the network.
    :param block_height: Block height the lock is valid for.
    :param sender_priv_key: Private key of the address locking the funds.
    :param p2sh_addr: P2SH address containing the funds.
    :param rec_addr: P2PKH address receiving the funds.
    """

    # mine 100 blocks and send bitcoin to the P2SH address
    proxy.generatetoaddress(100, p2sh_addr)
    # mine 100 blocks to make mined bitcoin spendable, emulates 'bitcoin-cli -generate 100'
    for _ in range(100):
        proxy.generatetoaddress(1, proxy.getnewaddress())

    # retrieve unspent UTXOs for the P2SH address
    p2sh_addr_unspent = proxy.listunspent(0, 99999999, [p2sh_addr])

    # create absolute-block locking sequence for the transaction inputs
    seq = Sequence(TYPE_ABSOLUTE_TIMELOCK, block_height)

    # create transaction inputs for unspent UTXOs
    # and calculate the total unspent bitcoins they contain
    tx_inputs = []
    total_unspent = 0
    for utxo in p2sh_addr_unspent:
        tx_inputs.append(
            TxInput(utxo['txid'],
                    utxo['vout'],
                    sequence=seq.for_input_sequence()))
        total_unspent += utxo['amount']
    print("Unspent bitcoin in address {} : {}".format(p2sh_addr,
                                                      total_unspent))

    # get the public key of the receiving address for the funds to be sent to
    rec_pub_key = proxy.getaddressinfo(rec_addr)['pubkey']
    rec_pk = PublicKey(rec_pub_key)

    # calculate fee
    satoshis_per_kb = requests \
        .get('https://api.blockcypher.com/v1/btc/test3') \
        .json()['medium_fee_per_kb']
    # formula: |inputs| * 180 + 34 * |outputs| +- |inputs|
    tx_size = len(tx_inputs) * 180 + 34 * 1 + 10 + len(tx_inputs)
    # we calculate fees in terms of bitcoin
    fee = (tx_size / 1024) * (satoshis_per_kb / 10e8)

    # create the transaction output
    tx_output = TxOutput(to_satoshis(Decimal(total_unspent) - Decimal(fee)),
                         rec_pk.get_address().to_script_pub_key())
    # set a lock time in blocks for the transaction
    lock = Locktime(block_height)
    # create the transaction
    tx = Transaction(tx_inputs, [tx_output], lock.for_transaction())
    unsigned_tx = tx.serialize()
    print('Raw unsigned transaction:', unsigned_tx)

    # we need to rebuild the redeem script from the P2SH private key
    # make the locking P2PKH address private key
    sender_sk = PrivateKey(sender_priv_key)
    # retrieve the public key of the locking address
    sender_pk = sender_sk.get_public_key()
    # rebuild the redeem script
    redeem_script = Script([
        seq.for_script(), 'OP_CHECKLOCKTIMEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        sender_pk.get_address().to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    # for every input of the transaction
    for i, txin in enumerate(tx.inputs):
        # create the signature for redeeming the funds
        sig = sender_sk.sign_input(tx, i, redeem_script)
        # and sign the input
        txin.script_sig = Script(
            [sig, sender_pk.to_hex(),
             redeem_script.to_hex()])

    signed_tx = tx.serialize()
    print('Raw signed transaction:', signed_tx)
    print('Transaction ID:', tx.get_txid())

    # verify that the transaction is valid
    ver = proxy.testmempoolaccept([signed_tx])
    if ver[0]['allowed']:
        # if the transaction is valid send the transaction to the blockchain
        print('Transaction is valid.')
        proxy.sendrawtransaction(signed_tx)
        print('{} Bitcoin sent to address {}'.format(
            Decimal(total_unspent) - Decimal(fee), rec_addr))
    else:
        # otherwise, display the reason the transaction failed
        print('Transaction rejected. Reason:', ver[0]['reject-reason'])
def load_data_json(priv=False,
                   pub=False,
                   pub_hash=False,
                   timelock_csv=False,
                   timelock_tx=False,
                   timelock_log=False,
                   p2pk=False):
    """loads parameters used to create P2SH address and spending transactions
    from the data.json file - initiates/converts applicable objects/data

    returns : dict of data for the Attributes specified
        - e.g {'priv_key': object, 'pub': object, 'pub_hash': 'string'}
    """

    # reads user data from data.json
    with open('data.json', 'r') as json_file:
        data = json.load(json_file)
        usr_inputs = data['csv_timelock']['inputs']

    # initiates key objects
    if priv or pub or pub_hash:
        usr_priv = usr_inputs['priv_key']
        usr_pub = usr_inputs['pub_key']
        if priv and not usr_priv:
            errors.missing_data('private key')
        elif usr_priv:
            priv_key = PrivateKey.from_wif(usr_priv)
            pub_key = priv_key.get_public_key()
        elif usr_pub:
            pub_key = PublicKey.from_hex(usr_pub)
        else:
            # prints error msg & raises systemExit
            errors.missing_data('public key')

    # loads timelock condition and converts format
    if timelock_csv or timelock_tx or timelock_log:
        lock_height = usr_inputs['block_lock']
        if lock_height:
            seq = Sequence(TYPE_RELATIVE_TIMELOCK, lock_height)
            timelock_script = seq.for_script()
            timelock_txin = seq.for_input_sequence()
        else:
            # prints error msg & raises systemExit
            errors.missing_data('timelock period')

    # initaites P2pkhAddress object
    if p2pk:
        address = usr_inputs['p2pkh_address']
        if address:
            p2pkh_address = P2pkhAddress.from_address(address)
        else:
            # prints error msg & raises systemExit
            errors.missing_data('P2PKH address')

    # fills return outputs with specified data from func arguments
    outputs = {}
    if priv:
        outputs['priv_key'] = priv_key
    if pub:
        outputs['pub_key'] = pub_key
    if pub_hash:
        outputs['pub_key_hash'] = pub_key.to_hash160()
    if timelock_csv:
        outputs['timelock_csv'] = timelock_script
    if timelock_tx:
        outputs['timelock_tx'] = timelock_txin
    if timelock_log:
        outputs['timelock_log'] = lock_height
    if p2pk:
        outputs['p2pk_addr'] = p2pkh_address

    return outputs
示例#19
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"]))
示例#20
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())
示例#21
0
def main():
    setup.setup('testnet')
    eps = 200  # value owned by each participant in enable-refund transaction. Could be 1 satoshi
    delta = 10  # upper bound for tx to be confirmed
    T = 2100200  # funds for payment locked until this time
    t_channel = 35  # upper bound for closing a channel

    id_in_channel_left = Id('616c26241bb007883f13aff556bb07d28374b52b81aa675f30dcf35c04103da4')
    tx_in_channel_left = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 0)
    id_in_channel_right = Id('f74b11ae3ca8d2c2d0424296f0de316198b4fda2ca984b5e3c6681abd2c72b2c')
    tx_in_channel_right = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 1)

    id_channel_left = Id('e6ad38d70bf775e7e74bcd598e9282141dac09f79374565c3ebdf61e4f9ef4ed')
    id_channel_right = Id('a3dbcea1e46edecbd1da13231f385ebe7f2beea382e3f7227c4c00d21b7e8455')

    tx_channel = createOpenChannelTx(tx_in_channel_left, tx_in_channel_right, to_satoshis(0.000009), to_satoshis(0.000009),
                                  id_channel_left.public_key, id_channel_right.public_key)

    tx_channel = signOpenChannelTxLeft(tx_channel, id_in_channel_left)
    tx_channel = signOpenChannelTxRight(tx_channel, id_in_channel_right)
    print_tx(tx_channel, 'tx channel open')
    tx_channel_id = '7b2ff59b6070a70249fd3f06efd1e0944d69597e5871e72098304adae94e7316'

    id_er_in = Id('89270091320614b25f88b84497ff4e4a017cbf1d25c1462b1352ea44f45708db')
    tx_er_input = TxInput('14c5b01c28a133fb55c03cfd756d70ccdacbdc0229c4a96d49c65c25df53afb5', 3)

    id_er_u1 = Id('3223c869874bad6933f14d1bf3bc9354125641e0aef3484dcf313c24a18655c7')
    id_er_u2 = Id('ac54ff9bc498ac9fa15f1e76a670fa0acdc85316fb6a97fc161f3871ab59e3bd')
    id_er_u3 = Id('05b91a17dbe63db245c6a2ba84a9a2b01ed86b494b61cc2dad5a0a44fe6ddc0e')

    tx_er_rel_timelock = t_channel + 2 * delta

    tx_er = createTxER(tx_er_input, [id_er_u1.public_key, id_er_u2.public_key, id_er_u3.public_key], tx_er_rel_timelock, eps)
    signTxER(tx_er, id_er_in)
    print_tx(tx_er, 'tx_er, 3 out')

    tx_er_id = '1e3c3465793126d4115f49750fab61a66c20bfbece436016d00066730704969b'

    id_state_left = Id('ce7bca0ec8d38f945390e64627f4b669eca9afd2bae77d036421ce96b6767728')  # left can receive a - c coins
    id_state_right = Id('ad5813d9719179da0e561aa22295017559b247a3bb325ce438bc8247bf79962e')  # right can receive b coins
    id_refund_mulsig_left = Id('e34d37fdeb88addac291ae0fa084f33490d756d8298e7219b0d4f073616dd251')  # left will receive c coins if publish tx_refund (using tx_er output)
    id_refund_mulsig_right = Id('4d87652d513e0f7a5be51894b7fa862c8ca3ea8ef222f6b6ea7ed6a949f67672') # left will receive c coins if publish tx_refund (using tx_er output)
    id_pay_right = Id('0a08c11255f48d66b0d1dcab0e3b9479a7e1275d078663fde3dc9fd92355e784')  # right will receive c coins after T if publish tx_pay

    tx_state_in = TxInput(tx_channel_id, 0)
    state_lock_script = getTxStateLockScript(T, delta, id_pay_right.public_key,
                             id_refund_mulsig_left.public_key, id_refund_mulsig_right.public_key)

    lock_amount = to_satoshis(0.00000500)
    tx_state = createTxState(tx_state_in, id_state_left.public_key, id_state_right.public_key, id_pay_right.public_key,
                             id_refund_mulsig_left.public_key, id_refund_mulsig_right.public_key,
                             lock_amount, to_satoshis(0.00000300), to_satoshis(0.00000100), T, delta)

    sig_tx_state_left = getChannelStateScriptSigLeft(tx_state, id_channel_left, id_channel_right.public_key)
    sig_tx_state_right = getChannelStateScriptSigRight(tx_state, id_channel_right, id_channel_left.public_key)
    tx_state = signChannelStateTx(tx_state, sig_tx_state_left, sig_tx_state_right)
    print_tx(tx_state, 'tx state')
    tx_state_id = '229caba8498d320c60b78f347ad70ff8e324bd39a9318e3a94a788dc53f1516f'

    tx_er_for_refund_input = TxInput(tx_er_id, 0, sequence=Sequence(TYPE_RELATIVE_TIMELOCK, tx_er_rel_timelock).for_input_sequence())
    tx_state_lock_input = TxInput(tx_state_id, 0, sequence=Sequence(TYPE_RELATIVE_TIMELOCK, delta).for_input_sequence())

    id_refund_receiver = Id('e2bd3bf28c7e0994ef87a8d61b67f4f926ab2e315bc9f1e55da2394a594b4e66')    # new address for refund
    id_pay_receiver = Id('9d2b4722df4e870ef4fd6a7be03b39c9a056bf0562852018e0c995cbc0d5756c')       # new address for pay to right

    tx_refund, sig_left = createTxRefund(tx_er_for_refund_input, tx_state_lock_input, id_er_u1, id_refund_mulsig_left,
                                 state_lock_script, id_refund_receiver, lock_amount, to_satoshis(0.00000600), eps, tx_er_rel_timelock)

    sig_right = txRefundGetRightSignature(tx_refund, id_refund_mulsig_right, state_lock_script)
    tx_refund = signTxRefundStateInput(tx_refund, sig_left, sig_right)
    print_tx(tx_refund, 'tx refund')

    tx_pay = createTxPayAndSign(tx_state_lock_input, id_pay_right, state_lock_script, id_pay_receiver,
                                lock_amount, to_satoshis(0.00000600))
    print_tx(tx_pay, 'tx pay')
示例#22
0
def main():
    # always remember to setup the network
    setup('testnet')

    #
    # This script spends from a P2SH address containing a CSV+P2PKH script as
    # created from examples/create_p2sh_csv_p2pkh.py
    #
    # We assume that some 11.1 tBTC have been send to that address and that we know
    # the txid and the specific UTXO index (or vout).
    #

    # set values
    relative_blocks = 20
    txid = '76c102821b916a625bd3f0c3c6e35d5c308b7c23e78b8866b06a3a466041db0a'
    vout = 0

    seq = Sequence(TYPE_RELATIVE_TIMELOCK, relative_blocks)

    # create transaction input from tx id of UTXO (contained 11.1 tBTC)
    txin = TxInput(txid, vout, sequence=seq.for_input_sequence())

    # secret key needed to spend P2PKH that is wrapped by P2SH
    p2pkh_sk = PrivateKey(
        'cRvyLwCPLU88jsyj94L7iJjQX5C2f8koG4G2gevN4BeSGcEvfKe9')
    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_CHECKSEQUENCEVERIFY', 'OP_DROP', 'OP_DUP',
        'OP_HASH160',
        p2pkh_addr.to_hash160(), 'OP_EQUALVERIFY', 'OP_CHECKSIG'
    ])

    # to confirm that address is the same as the one that the funds were sent
    #addr = P2shAddress.from_script(redeem_script)
    #print(addr.to_address())

    # send/spend to any random address
    to_addr = P2pkhAddress('n4bkvTyU1dVdzsrhWBqBw8fEMbHjJvtmJR')
    txout = TxOutput(11, to_addr.to_script_pub_key())

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

    # create transaction from inputs/outputs
    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 -
    # note that the redeem script is passed to replace the scriptSig
    sig = p2pkh_sk.sign_input(tx, 0, 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, redeem_script.to_hex()])
    signed_tx = tx.serialize()

    # print raw signed transaction ready to be broadcasted
    print("\nRaw signed transaction:\n" + signed_tx)
    print("\nTxId:", tx.get_txid())
示例#23
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}')