Bitcoin
Raw Transaction – Unable to broadcast my raw tx (P2PKH) on testnet. For a failed CHECK(MULTI)SIG operation, the signature must be 0.
I’m trying to broadcast my trades on a test network without success so far. I always get the following error:
sendrawtransaction RPC error: "code":-26,"message":"mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)"
I’ve reviewed my code more than 10 times in the last 2 hours and I can’t find what’s the problem. Everything seems fine, but it clearly isn’t.
Can someone help me figure out what’s causing the problem?
This is my code for Python. I just removed the private_key_hex field, but everything else stayed the same. Also, I didn’t get any change. The difference between the total UTXO amount and the transferred value is the fee charged to the miner.
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("76a91488ac".format(hashed_pubkey_in))
scriptPubKey_in_s = len(scriptPubKey_in)
#TX_OUT_VARIABLES
amount = 56400
pub_address_out="mpkt3ZpTfZJDeN9p5LgkAHj3NmVMaND7vR"
hashed_pubkey_out = hashed_pubkey(pub_address_out)
scriptPubKey_out = bytes.fromhex("76a91488ac".format(hashed_pubkey_out))
scriptPubKey_out_s = 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_s') = scriptPubKey_in_s.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_s') = scriptPubKey_out_s.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_s")
+ rtx.tx_input("scriptPubKey_in")
+ rtx.tx_input("sequence")
+ rtx.tx_out_count
+ rtx.tx_output("amount")
+ rtx.tx_output("scriptPubKey_out_s")
+ rtx.lock_time
+ (1).to_bytes(4, byteorder="little")#SIGHASH_ALL type of sighash
)
#2 SHA256 TO RAW_TX
hashed_tx_to_sign = doublesha256(raw_tx_string)
sk = ecdsa.SigningKey.from_string(bytes.fromhex(private_key_hex), curve = ecdsa.SECP256k1)
vk = sk.verifying_key
public_key = vk.to_string().hex()
#COMPRESSING THE PUBLIC KEY
# Checking if the last byte is odd or even
if (ord(bytearray.fromhex(public_key(-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(:64)
public_key = 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_mod = signature + (1).to_bytes(1, byteorder="little") #SIGHASH_ALL type of sighash
signature_mod_s = len(signature_mod)
public_key_s = len(public_key)
sigscript = (
signature_mod_s.to_bytes(1, byteorder="little")
+ signature_mod
+ public_key_s.to_bytes(1, byteorder="little")
+ public_key
)
sigscript_s = len(sigscript)
real_tx = (
rtx.version
+ rtx.tx_in_count
+ rtx.tx_input("prev_tx_id")
+ rtx.tx_input("v_out")
+ sigscript_s.to_bytes(1, byteorder="little")
+ sigscript
+ rtx.tx_input("sequence")
+ rtx.tx_out_count
+ rtx.tx_output("amount")
+ rtx.tx_output("scriptPubKey_out_s")
+ rtx.tx_output("scriptPubKey_out")
+ rtx.lock_time
)
print(real_tx.hex())