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