1200wd / bitcoinlib

Bitcoin and other Cryptocurrencies Library for Python. Includes a fully functional wallet, Mnemonic key generation and management and connection with various service providers to receive and send blockchain and transaction information.
http://bitcoinlib.readthedocs.io/
GNU General Public License v3.0
596 stars 199 forks source link

Sending transaction in WSL2 Ubuntu + BTC Node on local network = TXID but nothing is sent #363

Closed bigsk1 closed 8 months ago

bigsk1 commented 8 months ago

Like to send OP_RETURN message data with transaction, using Conda python 3.10.4 on wsl2 ubuntu. Node running on server in local network

script to create a wallet

from bitcoinlib.wallets import Wallet

def create_wallet_and_save_details(wallet_name):
    try:
        # Create a new wallet
        wallet = Wallet.create(wallet_name)

        # Get the first key from the wallet
        key = wallet.get_key()

        # Get address, public key in hex, and private key in WIF format
        address = key.address
        private_key_wif = key.wif

        # Prepare data to save
        data_to_save = (
            f"Wallet Name: {wallet_name}\n"
            f"Address: {address}\n"
            f"Private Key: {private_key_wif}\n"
        )

        # Save to a .txt file
        file_name = f"{wallet_name}_details.txt"
        with open(file_name, 'w') as file:
            file.write(data_to_save)

        print(f"Wallet details saved to {file_name}")
    except Exception as e:
        print(f"Error occurred: {e}")

# Example usage
wallet_name = 'Wallet2'
create_wallet_and_save_details(wallet_name)

provides wallet name, public address and private address in wif format (xptbAxxxxxxxxxxxxxxxxxxx)

send small amount to wallet addy

created a script to send transaction with message, all secretes in envs, script runs fine

# export BITCOIN_NODE_HOST='your_node_ip'
# export BITCOIN_NODE_PORT='your_node_port'
# export BITCOIN_RPC_USERNAME='your_rpc_username'
# export BITCOIN_RPC_PASSWORD='your_rpc_password'
# export MY_BTC_PRIVATE_KEY='your_private_key_here'

# add the above first in your terminal or add to .bashrc

import os
import sys
from bitcoinlib.wallets import Wallet
from bitcoinlib.transactions import Transaction, Output
from bitcoinlib.encoding import varstr
from bitcoinlib.services.bitcoind import BitcoindClient

# Configuration (use environment variables for sensitive data)
private_key = os.getenv('MY_BTC_PRIVATE_KEY')  # Set your private key as an environment variable
wallet_name = 'Wallet2'
sender_address = '1eBhwdE.....'
recipient_address = '33SfCe6K.....'
amount_to_send_satoshis = int(0.0001 * 100000000)  # Convert 0.0001 BTC to satoshis
fee_satoshis = int(0.00014 * 100000000)  # Convert 0.00014 BTC to satoshis
message = 'test_message'

# Bitcoin node RPC configuration
node_host = os.getenv('BITCOIN_NODE_HOST')
node_port = os.getenv('BITCOIN_NODE_PORT')
rpc_username = os.getenv('BITCOIN_RPC_USERNAME')
rpc_password = os.getenv('BITCOIN_RPC_PASSWORD')

# Attempt to create a BitcoindClient instance with RPC credentials
try:
    client = BitcoindClient()
except Exception as e:
    print(f"Error connecting to Bitcoin node: {e}")
    sys.exit(1)

# Check if private key is available
if not private_key:
    print("Private key not set. Please set the MY_BTC_PRIVATE_KEY environment variable.")
    sys.exit(1)

# Load the existing wallet and update UTXOs
try:
    wallet = Wallet(wallet_name)
    wallet.utxos_update()
    utxos = wallet.utxos()
    if not utxos:
        print("No unspent transaction outputs available.")
        sys.exit(1)
except Exception as e:
    print(f"Error loading wallet or updating UTXOs: {e}")
    sys.exit(1)

# Prepare inputs and outputs for the transaction
try:
    inputs = [{'txid': utxo['txid'], 'output_n': utxo['output_n'], 'value': utxo['value']} for utxo in utxos]
    print("Inputs prepared for the transaction:", inputs)

    # Create standard transaction output and OP_RETURN output
    standard_output = Output(amount_to_send_satoshis, address=recipient_address)
    lock_script = b'j' + varstr(message.encode('utf-8'))
    op_return_output = Output(0, lock_script=lock_script)
    outputs = [standard_output, op_return_output]
    print("Outputs prepared for the transaction:", outputs)

except Exception as e:
    print(f"Error preparing inputs or outputs: {e}")
    sys.exit(1)

# Create and sign the transaction
try:
    tx = wallet.send(outputs)
    print(f"Transaction broadcasted. TXID: {tx.txid}")
except Exception as e:
    print(f"An error occurred during transaction creation or broadcast: {e}")

Getting a TXID from running but never is sent to blockchain, vsat is high to get into next block. Output from script below.

 Inputs prepared for the transaction: [{'txid': 'nnndjdjd3330df8b0528c61d58cc9138654ca..................', 'output_n': 1, 'value': 44263}, {'txid': 'aaaaaaaaaaaaaaa012bd3e04975fbb774d0636..............', 'output_n': 1, 'value': 20000}]
Outputs prepared for the transaction: [<Output(value=10000, address=3aaaaa2mFfCe6KqYZ1Kaaaaaaaa, type=p2sh)>, <Output(value=0, address=, type=nulldata)>]
Transaction broadcasted. TXID: fcbffffff7b1de19adbd4fa77e228d723832c9fffffffffffffffb

I can run curl commands from host to node and get blockchain data so is connecting over RPC

I can get wallet details running a script, but I can not actually send a transaction even though I get a TXID. Public Address in block explorer never shows a transaction being sent, local mem pool never shows the TXID found.

On node (umbrel) ~/umbrel/app-data/bitcoin/data/app/bitcoin-config.json has rpcallowip=192.168.x.xx, but I guess it's no longer supported and I am connecting via RPC ok anyway.

import os
import sys
from bitcoinlib.wallets import Wallet
from bitcoinlib.transactions import Transaction, Output
from bitcoinlib.services.bitcoind import BitcoindClient

# Configuration for your Bitcoin node RPC using environment variables
rpc_user = os.getenv('BITCOIN_RPC_USER')
rpc_password = os.getenv('BITCOIN_RPC_PASSWORD')
rpc_host = os.getenv('BITCOIN_RPC_HOST')
rpc_port = os.getenv('BITCOIN_RPC_PORT')

# Configuration for your wallet
wallet_name = 'Wallet2'

# Attempt to create a BitcoindClient instance 
try:
    client = BitcoindClient()
except Exception as e:
    print(f"Error connecting to Bitcoin node: {e}")
    sys.exit(1)

try:
    wallet = Wallet(wallet_name)
    wallet.scan()

In ~/.bitcoinlib/bitcoin.conf shows

[rpc]
rpcconnect=192.168.x.xx
rpcport=8332
rpcuser=umbrel
rpcpassword=XXXXXXXXXXXXXXXXXXXXXXXXXX
txindex=1
server=1

I have added my node to providers and still no luck in getting transaction sent. Any Ideas? bitcoinlib.log shows nothing related to the transaction.

bigsk1 commented 8 months ago

I figured it out.... for anyone trying to figure this out also will add what I used below so the search engines pick it up.

# export BITCOIN_NODE_HOST='your_node_ip'
# export BITCOIN_NODE_PORT='your_node_port'
# export BITCOIN_RPC_USERNAME='your_rpc_username'
# export BITCOIN_RPC_PASSWORD='your_rpc_password'
# export MY_BTC_PRIVATE_KEY='your_private_key_here'

# add the above first in your terminal or add to .bashrc

import os
import sys
import json
import requests
from requests.auth import HTTPBasicAuth
from bitcoinlib.wallets import Wallet
from bitcoinlib.transactions import Output
from bitcoinlib.encoding import varstr

# Configuration (use environment variables for sensitive data)
private_key = os.getenv('MY_BTC_PRIVATE_KEY')
wallet_name = 'YOUR_WALLETS_NAME'
sender_address = 'YOUR_BTC_ADDRESS'
recipient_address = 'BTC_ADDRESS_YOUR_SENDING_TO'
amount_to_send_satoshis = int(0.0001 * 100000000)
fee_satoshis = int(0.00014 * 100000000)
message = 'YOUR_MESSAGE'

# RPC configuration
rpc_user = os.getenv('BITCOIN_RPC_USERNAME')
rpc_password = os.getenv('BITCOIN_RPC_PASSWORD')
rpc_url = f"http://{os.getenv('BITCOIN_NODE_HOST')}:{os.getenv('BITCOIN_NODE_PORT')}"

# Load the existing wallet and update UTXOs
try:
    wallet = Wallet(wallet_name)
    wallet.utxos_update()
    utxos = wallet.utxos()
    if not utxos:
        print("No unspent transaction outputs available.")
        sys.exit(1)
except Exception as e:
    print(f"Error loading wallet or updating UTXOs: {e}")
    sys.exit(1)

# Prepare inputs and outputs for the transaction
try:
    inputs = [{'txid': utxo['txid'], 'output_n': utxo['output_n'], 'value': utxo['value']} for utxo in utxos]
    print("Inputs prepared for the transaction:", inputs)

    standard_output = Output(amount_to_send_satoshis, address=recipient_address)
    lock_script = b'j' + varstr(message.encode('utf-8'))
    op_return_output = Output(0, lock_script=lock_script)
    outputs = [standard_output, op_return_output]
    print("Outputs prepared for the transaction:", outputs)

except Exception as e:
    print(f"Error preparing inputs or outputs: {e}")
    sys.exit(1)

# Create and sign the transaction
try:
    tx = wallet.send(outputs, fee=fee_satoshis)
    print("\nTransaction created.")
    print(f"TXID: {tx.txid}\n")
    raw_tx_hex = tx.raw_hex()
    print(f"Raw Transaction Hex: {raw_tx_hex}")

    # Broadcast the transaction via RPC
    headers = {'content-type': 'application/json'}
    payload = {
        "method": "sendrawtransaction",
        "params": [raw_tx_hex],
        "jsonrpc": "2.0",
        "id": 0,
    }

    response = requests.post(rpc_url, json=payload, headers=headers, auth=HTTPBasicAuth(rpc_user, rpc_password))
    response_json = response.json()

    if 'error' in response_json and response_json['error']:
        print("Error broadcasting transaction:", response_json['error'])
    else:
        txid = response_json['result']
        print("Transaction broadcasted successfully. TXID:", txid)

except Exception as e:
    print(f"\nAn error occurred during transaction creation or broadcast: {e}")