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

Future of Bitcoin encryption and security in a QC era

Possible rollback due to lazy reveal in BRC20?

A way to recover scammed Bitcoin investment