1

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())

1 Answer 1

1

The modified transaction you're hashing (raw_tx_string) is missing the output script (scriptPubKey_out), which is why the signature then fails to verify.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.