I am trying to build raw transactions from scratch to improve my understanding. For comparison I am using the hexoutput from https://coinb.in/ as I can choose Testnet on there.
I am trying to construct a P2PKH transaction without Segwit (for now) which should use this tx 577735da1fccf6df79eac9ff42049a7729703ec5506efeb1602bca99df3bafd2
(index 0) and send 6889990
satoshi to mv4rnyY3Su5gjcDNzbMLKBQkBicCtHUtFB
, the raw public key of the input address is 034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d
So for the unsigned transaction my library produces 0100000001d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757000000002221034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073dffffffff0106226900000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac00000000
which matches what is produced by coinb.
So to generate the signature for the sigscript I use the following code:
def sign_transaction(self, secrets):
"""
Sign all inputs of the transaction with
a secret key.
:param ECPrivKey[] secrets: a list of private keys corresponding to the inputs
:return: Transaction Signed version of the transaction ready to be published
"""
unsigned = bytes.fromhex(self.serialize_to_hex())
message = sha256(sha256(unsigned))
copy = deepcopy(self)
inputs = self.__inputs
for i in range(0, len(secrets)):
sk = secrets[i]
inp = inputs[i]
sig = SignatureFactory.gen_ecdsa_signature_bytes(message, sk)
copy.set_signature(sig)
sigscript = sig.get_asn1_encoded() + OP_SIGHASH_ALL
l = len(bytes.fromhex(sigscript))
script = compact_size_int(l) + sigscript + inp.get_sig_script()
copy.__inputs[i].set_sig_script(script)
return copy
Informally I use the hexoutput from the unsigned transaction, convert it to bytes, run two sha256 hash functions on it and append the SIGHASH ('01') byte
I validated the produced signature and it is valid so I feel like there is something wrong with the serialization. Here is my transaction after signing it:
0100000001d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757000000006a47304402207da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b022010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e376760121034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073dffffffff0106226900000000001976a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac00000000
{"version": "01000000", "flag": "", "inputLen": "01", "inputs": [{"prevOutHash": "d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757", "prevOutIx": "00000000", "sigScriptLen": "6a", "sigScript": "47304402207da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b022010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e376760121034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d", "sequence": "ffffffff"}], "outputLen": "01", "outputs": [{"value": "0622690000000000", "pubKeyScriptLength": "19", "pubKeyScript": "76a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac"}], "locktime": "00000000"}
In more detail the value of sigscript:
47 Script length
30 DER signature marker
44 Signature length
02 r value marker
20 r value length
7da5c1e2d7db828e415db1ae060d65e4a44de2b13b71c50be61d6c52da82425b r value
02 s value marker
2010da9abb70c7b6047b559c5c572f68e078d6ae78ba03dfd6aa1890e512e37676 s value
01 Opcode SIGHASH
21 pubkey length
034323ee9ac23504779b40c1b02578d27f70c12c22b7fc4f452dbbde681e45073d pubkey value
If I try to broadcast the transaction on https://live.blockcypher.com/btc-testnet/pushtx/ I get Error validating transaction: Error running script for input 0 referencing 577735da1fccf6df79eac9ff42049a7729703ec5506efeb1602bca99df3bafd2 at 0: Script was NOT verified successfully..
Does anybody have an idea what could be wrong? Also the r and s value of the signature I did not encode in little endian and I am not sure if maybe this could be the problem?