I am trying to broadcast my transaction on the test network with no success so far. I get always this error:
sendrawtransaction RPC error: {"code":-26,"message":"mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)"}
I have reviewed my code at least 10 times the last two hours and can´t find what is wrong with it. It looks like everything is okay but obviously not.
Could someone spot the cause of the issue?
This is the raw transaction in hex:
010000000119385e43e5d69ce6dd8aa465cdfc897c80782d1b44fcc07239bf17e000fdf7db000000006a47304402207fd3680d14fe8de7ef71d35d9af0c60b2f878532cdd912fd3b293ae30c8bd3a902203de1b6330657487d4fe115a90916d55fbea0445433eb206b04073594ef5bcdd1012102ce96cbb4508b6555c0968a90cc2e24e511e7431e78e69a04144f5017390c9612ffffffff0150dc0000000000001976a914655b68715774105f48b475dc2a15026ade9e013e88ac00000000
And here the same hex deconstructed:
version: 01000000
tx in count: 01
prev_tx_id (flipped): 19385e43e5d69ce6dd8aa465cdfc897c80782d1b44fcc07239bf17e000fdf7db
v_out: 00000000
sigscript size: 6a
sigscript: 47304402207fd3680d14fe8de7ef71d35d9af0c60b2f878532cdd912fd3b293ae30c8bd3a902203de1b6330657487d4fe115a90916d55fbea0445433eb206b04073594ef5bcdd1012102ce96cbb4508b6555c0968a90cc2e24e511e7431e78e69a04144f5017390c9612
sequence: ffffffff
tx_out_count: 01
amount: 50dc000000000000
scriptPubKey_out_size: 19
scriptPubKey_out: 76a914655b68715774105f48b475dc2a15026ade9e013e88ac
lock time: 00000000
This is my code on Python. I just removed the private_key_hex field, anything else remains untouched. Also, notice that I got no change, the difference between the full UTXO amount and the value sent is the fee for the miners.
import base58
import hashlib
import ecdsa
def hash160(x): # Both accepts & returns bytes
return hashlib.new('ripemd160', hashlib.sha256(x).digest()).digest()
def doublesha256(x):
return hashlib.sha256(hashlib.sha256(x).digest()).digest()
def flip(string):
flipped = "".join(reversed([string[i:i+2] for i in range(0, len(string), 2)]))
return flipped
def hashed_pubkey(pubkey):
return base58.b58decode_check(pubkey)[1:].hex()
private_key_hex = ''
pub_address_in = 'mpfmNgZAkSdhDoP5UJKhh6wahfGboXhFmj'
hashed_pubkey_in = hashed_pubkey(pub_address_in)
version = 1
tx_input_count = 1
tx_output_count = 1
#TX_IN_VARIABLES
prev_tx_id = 'dbf7fd00e017bf3972c0fc441b2d78807c89fccd65a48adde69cd6e5435e3819'
v_out = 0
scriptPubKey_in = bytes.fromhex("76a914{}88ac".format(hashed_pubkey_in))
scriptPubKey_in_size = len(scriptPubKey_in)
#TX_OUT_VARIABLES
amount = 56400
pub_address_out = 'mpkt3ZpTfZJDeN9p5LgkAHj3NmVMaND7vR'
hashed_pubkey_out = hashed_pubkey(pub_address_out)
scriptPubKey_out = bytes.fromhex("76a914{}88ac".format(hashed_pubkey_out))
scriptPubKey_out_size = len(scriptPubKey_out)
class raw_tx:
version = (version).to_bytes(4, byteorder='little')
tx_in_count = (tx_input_count).to_bytes(1, byteorder = 'little')
tx_input = {}
tx_out_count = (tx_output_count).to_bytes(1, byteorder = 'little')
tx_output = {}
lock_time = (0).to_bytes(4, byteorder = 'little')
rtx = raw_tx()
#TX_IN
rtx.tx_input['prev_tx_id'] = bytes.fromhex(flip(prev_tx_id))
rtx.tx_input['v_out'] = (v_out).to_bytes(4, byteorder = 'little')
rtx.tx_input['scriptPubKey_in_size'] = scriptPubKey_in_size.to_bytes(1, byteorder = 'little')
rtx.tx_input['scriptPubKey_in'] = scriptPubKey_in
rtx.tx_input['sequence'] = bytes.fromhex('ffffffff')
#TX_OUT
rtx.tx_output['amount'] = amount.to_bytes(8, byteorder = 'little')
rtx.tx_output['scriptPubKey_out_size'] = scriptPubKey_out_size.to_bytes(1, byteorder = 'little')
rtx.tx_output['scriptPubKey_out'] = scriptPubKey_out
raw_tx_string = (
rtx.version
+ rtx.tx_in_count
+ rtx.tx_input["prev_tx_id"]
+ rtx.tx_input["v_out"]
+ rtx.tx_input["scriptPubKey_in_size"]
+ rtx.tx_input["scriptPubKey_in"]
+ rtx.tx_input["sequence"]
+ rtx.tx_out_count
+ rtx.tx_output["amount"]
+ rtx.tx_output["scriptPubKey_out_size"]
+ rtx.lock_time
+ (1).to_bytes(4, byteorder = 'little')#SIGHASH_ALL type of sighash
)
#DOUBLE SHA256 OF RAW_TX
hashed_tx_to_sign = doublesha256(raw_tx_string)
#GETTING PUBLIC KEY IN BYTES FORMAT
sk = ecdsa.SigningKey.from_string(bytes.fromhex(private_key_hex), curve = ecdsa.SECP256k1)
vk = sk.verifying_key
public_key = vk.to_string()
public_key_hex = public_key.hex()
#COMPRESSING THE PUBLIC KEY
# Checking if the last byte is odd or even
if (ord(bytearray.fromhex(public_key_hex[-2:])) % 2 == 0):
public_key_compressed = '02'
else:
public_key_compressed = '03'
# Add bytes 0x02 to the X of the key if even or 0x03 if odd
public_key_compressed += public_key_hex[:64]
public_key_compressed = bytes.fromhex(public_key_compressed)
#SIGNING RAW_TX HASHED
signature = sk.sign_digest(hashed_tx_to_sign, sigencode = ecdsa.util.sigencode_der_canonize)
#CREATING SCRIPTSIG
signature_SIGHASH_ALL_byte = signature + (1).to_bytes(1, byteorder = 'little') #SIGHASH_ALL type of sighash
signature_SIGHASH_ALL_byte_size = len(signature_SIGHASH_ALL_byte)
public_key_compressed_size = len(public_key_compressed)
scriptSig = (
signature_SIGHASH_ALL_byte_size.to_bytes(1, byteorder = 'little')
+ signature_SIGHASH_ALL_byte
+ public_key_compressed_size.to_bytes(1, byteorder = 'little')
+ public_key_compressed
)
scriptSig_size = len(scriptSig)
real_tx = (
rtx.version
+ rtx.tx_in_count
+ rtx.tx_input["prev_tx_id"]
+ rtx.tx_input["v_out"]
+ scriptSig_size.to_bytes(1, byteorder = 'little')
+ scriptSig
+ rtx.tx_input["sequence"]
+ rtx.tx_out_count
+ rtx.tx_output["amount"]
+ rtx.tx_output["scriptPubKey_out_size"]
+ rtx.tx_output["scriptPubKey_out"]
+ rtx.lock_time
)
print(real_tx.hex())