0

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?

3

Signing transaction is a bit more complicated than just signing the hash of unsigned transaction

Look at the explanations here:

  • Thanks I tried to sign with the scriptSig filled with the scriptPub from the previous output, so what I am signing now looks like: 01000000 01 d2af3bdf99ca2b60b1fe6e50c53e7029779a0442ffc9ea79dff6cc1fda357757 00000000 19 76a9143ebad4eac79369b9c8fd6c3033386729a041f65d88ac ffffffff 01 0622690000000000 19 76a9149f9a7abd600c0caa03983a77c8c3df8e062cb2fa88ac 00000000 unfortunately still fails to validate. – Jakob Abfalter Jul 1 at 15:31
  • where is SIGHASH_ALL (4 bytes LE) at the end? – amaclin Jul 1 at 18:07
  • Shouldn't the SIGHASH_ALL only be included after the signature is added? According to your reference "Now comes the scriptSig. For the purpose of signing the transaction, this is temporarily filled with the scriptPubKey of the output we want to redeem." – Jakob Abfalter Jul 2 at 9:17
  • Look to the step #13 in the instructions above – amaclin Jul 2 at 9:21
  • 1
    It worked now!! Thanks a lot for your help! – Jakob Abfalter Jul 2 at 13:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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