bitcoin testnet transaction creation(in python)

import hashlib import random import requests

Secp256k1 curve parameters

P = 2256 - 232 - 977 N = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 A = 0 B = 7 Gx = 55066263022277343669578718895168534326250603453777594175500187360389116729240 Gy = 32670510020758816978083085130507043184471273380659243275938904335757337482424

SIGHASH_ALL = 0x01

Helper functions

def decode_base58(address, num_bytes=25): """Decode a Base58-encoded Bitcoin address to get the hash160.""" base58_chars = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" base58_map = {char: index for index, char in enumerate(base58_chars)}

num = 0
for char in address:
    num *= 58
    if char not in base58_map:
        raise ValueError(f"Invalid Base58 character: {char}")
    num += base58_map[char]

combined = num.to_bytes(num_bytes, byteorder="big")
checksum = combined[-4:]
payload = combined[:-4]

if hashlib.sha256(hashlib.sha256(payload).digest()).digest()[:4] != checksum:
    raise ValueError("Invalid checksum")

return payload[1:]  # Return hash160 (remove version byte)

ECC Classes

class Point: def init(self, x, y, a, b): self.x = x self.y = y self.a = a self.b = b

def __add__(self, other):
    if self.x is None:
        return other
    if other.x is None:
        return self
    if self.x == other.x and self.y != other.y:
        return self.__class__(None, None, self.a, self.b)
    if self.x == other.x:
        s = (3 * self.x**2 + self.a) * pow(2 * self.y, P - 2, P) % P
    else:
        s = (other.y - self.y) * pow(other.x - self.x, P - 2, P) % P
    x = (s**2 - self.x - other.x) % P
    y = (s * (self.x - x) - self.y) % P
    return self.__class__(x, y, self.a, self.b)

def __rmul__(self, coefficient):
    coef = coefficient % N
    current = self
    result = self.__class__(None, None, self.a, self.b)
    while coef:
        if coef & 1:
            result += current
        current += current
        coef >>= 1
    return result

def sec(self, compressed=True):
    """Returns the SEC format of the public key."""
    if compressed:
        prefix = b'\x02' if self.y % 2 == 0 else b'\x03'
        return prefix + self.x.to_bytes(32, 'big')
    else:
        return b'\x04' + self.x.to_bytes(32, 'big') + self.y.to_bytes(32, 'big')

G = Point(Gx, Gy, A, B)

class PrivateKey: def init(self, secret): self.secret = secret self.point = secret * G

def sign(self, z):
    k = random.randint(1, N - 1)
    r = (k * G).x % N
    k_inv = pow(k, N - 2, N)
    s = (z + r * self.secret) * k_inv % N
    if s > N / 2:
        s = N - s
    return Signature(r, s)

class Signature: def init(self, r, s): self.r = r self.s = s

def der(self):
    """Returns the DER-encoded signature."""
    r_bin = self.r.to_bytes(32, "big").lstrip(b"\x00")
    s_bin = self.s.to_bytes(32, "big").lstrip(b"\x00")
    result = bytes([2, len(r_bin)]) + r_bin + bytes([2, len(s_bin)]) + s_bin
    return bytes([0x30, len(result)]) + result

class Script: def init(self, commands): self.commands = commands

def serialize(self):
    """Serialize the script commands into a byte string."""
    result = b""
    for cmd in self.commands:
        if isinstance(cmd, int):
            result += cmd.to_bytes(1, "little")
        elif isinstance(cmd, bytes):
            result += cmd
    return result

def p2pkh_script(hash160): """Creates a Pay-to-PubKey-Hash (P2PKH) scriptPubKey.""" return Script([0x76, 0xa9, len(hash160), hash160, 0x88, 0xac])

class TxIn: def init(self, prev_tx, prev_index): self.prev_tx = prev_tx self.prev_index = prev_index self.script_sig = Script([]) # Initialize with an empty script

class TxOut: def init(self, amount, script_pubkey): self.amount = amount self.script_pubkey = script_pubkey

class Tx: def init(self, version, tx_ins, tx_outs, locktime, testnet=False): self.version = version self.tx_ins = tx_ins self.tx_outs = tx_outs self.locktime = locktime self.testnet = testnet

def sig_hash(self, index):
    """Compute the signature hash for the input at the given index."""
    tx_copy = self.serialize(index)
    tx_copy += SIGHASH_ALL.to_bytes(4, "little")
    return int(hashlib.sha256(hashlib.sha256(tx_copy).digest()).hexdigest(), 16)

def serialize(self, index=None):
    """Serialize the transaction, correctly handling script lengths."""
    result = self.version.to_bytes(4, "little")
    result += len(self.tx_ins).to_bytes(1, "little")
    for i, tx_in in enumerate(self.tx_ins):
        result += tx_in.prev_tx[::-1]
        result += tx_in.prev_index.to_bytes(4, "little")
        if index is not None and i == index:
            # Placeholder script for signing (P2PKH template)
            placeholder = bytes([0x76, 0xa9, 0x14]) + bytes.fromhex("f53660b5be99b2900859421b3422f0d09d5a6378") + bytes([0x88, 0xac])
            result += len(placeholder).to_bytes(1, "little")
            result += placeholder
        else:
            # Use actual scriptSig for the final transaction
            serialized_script_sig = tx_in.script_sig.serialize()
            script_sig_len = len(serialized_script_sig)
            result += script_sig_len.to_bytes(1, "little")
            result += serialized_script_sig
        result += b"\xff\xff\xff\xff"  # Sequence
    result += len(self.tx_outs).to_bytes(1, "little")
    for tx_out in self.tx_outs:
        result += tx_out.amount.to_bytes(8, "little")
        serialized_script_pubkey = tx_out.script_pubkey.serialize()
        script_pubkey_len = len(serialized_script_pubkey)
        result += script_pubkey_len.to_bytes(1, "little")
        result += serialized_script_pubkey
    result += self.locktime.to_bytes(4, "little")
    return result

Main script to construct, sign, and broadcast the transaction

if name == "main": # Input details prev_tx = bytes.fromhex("5c70950fd191845187b5a30b1eb1b4b01e73e014aa0ded6c661e2a2fd1709776") prev_index = 0 tx_in = TxIn(prev_tx, prev_index)

# Change output
change_amount = int(0.00009269 * 100000000)  # 8000 satoshis
change_h160 = decode_base58("n416gdB748YSKXH6nbFnxGC9GLzNADa1zd")
change_script = p2pkh_script(change_h160)
change_output = TxOut(amount=change_amount, script_pubkey=change_script)

# Target output
target_amount = int(0.00020000 * 100000000)  # 10071 satoshis
target_h160 = decode_base58("mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv")
target_script = p2pkh_script(target_h160)
target_output = TxOut(amount=target_amount, script_pubkey=target_script)

# Create transaction object
tx_obj = Tx(1, [tx_in], [change_output, target_output], 0, True)

# Sign the transaction
private_key = PrivateKey(secret=492025)
z = tx_obj.sig_hash(0)
der = private_key.sign(z).der()
sig = der + SIGHASH_ALL.to_bytes(1, "big")
sec = private_key.point.sec()
# Correctly construct scriptSig with length prefixes
script_sig = Script([len(sig), sig, len(sec), sec])
tx_obj.tx_ins[0].script_sig = script_sig

# Serialize and print the transaction
serialized_tx = tx_obj.serialize().hex()
print(f"Serialized Transaction: {serialized_tx}")

# Broadcast the transaction to the testnet
url = "https://api.blockcypher.com/v1/btc/test3/txs/push"
headers = {'Content-Type': 'application/json'}
data = {"tx": serialized_tx}
response = requests.post(url, json=data, headers=headers)

if response.status_code == 201:
    print("Transaction successfully broadcasted.")
else:
    print(f"Failed to broadcast transaction: {response.text}")

output is Serialized Transaction: 0100000001769770d12f2a1e666ced0daa14e0731eb0b4b11e0ba3b587518491d10f95705c000000006a47304402205622ba47e3cb86ffdabcce2c511f2fdb49c416119f689d26195d240df2e40daa0220101db23ec825bf3c4e5ef4cc30e141b95af11928cf715e9530b54f9e9a334167012102b4f400c2f82e8dc5a819f967ae8efbc32510891ab44e758863fb268b6dec4efeffffffff0235240000000000001976a914f6a56ac5c00135b97a54f724cacecadda11b8f7988ac204e0000000000001976a914ad346f8eb57dee9a37981716e498120ae80e44f788ac00000000 Failed to broadcast transaction: {"error": "Error validating transaction: Transaction 5c70950fd191845187b5a30b1eb1b4b01e73e014aa0ded6c661e2a2fd1709776 referenced by input 0 of afb6c96dbb12712de8495a8a451554a50ee2e9a66710ef07c61c2f7e7cc326c5 has already been spent.."}

[Program finished]

ADDRESS private key is 492025 Private Key (WIF): 1cUEjftmpYAAX6et1S9YGosSbLJDPewtY52JA4VfUjgJGaLdkJmEL

here i am creating simple bitcoin testnet transaction but error occuring.



from Recent Questions - Bitcoin Stack Exchange https://ift.tt/H6tpznm
via IFTTT

Popular posts from this blog

Bitcoin Mining Could Be Strengthening The Ruble, Russian Central Bank Says

Crypto Exec Warns Tokenization Is Moving Faster Than Expected

Bitwise Clients Pour $69M Into Solana as Bulls Fight to Reclaim $200 Resistance Zone