I'm looking to get "hands on" with signing, however when I adapt Runeks' thorough answer at https://bitcoin.stackexchange.com/a/5241/89798 my code invariably fails reporting that I've used the wrong private key. Am I sourcing the private key wrongly, or mishandling it in some way? Where in my process below am I getting it wrong?
I'll start by noting Runeks' code as it stands executes correctly, that I'm using v0.13.2 bitcoind and bitcoin-cli in order to get the legacy transactions used in his answer, and I'm using regtest rather than mainnet.
My process:
- I use a script to reset the regtest network and generate 101 blocks so I've a single coinbase I can use:
CURDIR=`pwd`
cd /home/bitcoin14/.bitcoin
/usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf -regtest stop
sleep 1
rm -rf /home/bitcoin14/.bitcoin/regtest && /usr/local/bin/bitcoind -conf=/home/bitcoin14/.bitcoin/regtest.conf -regtest -daemon
sleep 2
/usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf -regtest generate 101 >/dev/null
cd $CURDIR
- I send the coins to a new address in order not to use that coinbase transaction
$ /usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf getnewaddress
mk5U6xEDnTmfNrHcCXkdKrXziYH1YMygVw
$ /usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf sendtoaddress mk5U6xEDnTmfNrHcCXkdKrXziYH1YMygVw 49.99
675eac8d9aebe4f84aa2bb18a9f02304d11cb8937ca103b6ccf00fdf0de69727
- I obtain the hex and vout of the above transaction as containing the coins whose move I wish to sign
$ /usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf gettransaction 675eac8d9aebe4f84aa2bb18a9f02304d11cb8937ca103b6ccf00fdf0de69727 | egrep 'vout|hex'
"vout": 1,
"vout": 1
"hex": "0100000001fe37d2309bb4b4f4de102ff08f08e049acaecd4c1ee195328404c02406e596c6000000004847304402206eef31e0114c8e31180da39c644fc518624e9c5f354f6c375bfffba8a3c0dc6d022021056d74ea16155036663b7aaab1e297715231747718e48ab94aefd05cded83d01feffffff0254330f00000000001976a91486d1e65bc7f89b24724f50fa5db3a7f102d9644d88acc0aff629010000001976a9143206b266d2998b1092fcd1737165c363c0e31b6c88ac65000000"
- I obtain a new address to which the coins will be redeemed
$ /usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf getnewaddress
n42ui4Tbd2mVPiRtAUr4RYW7KC7qUmXDTt
- I obtain the private key generated at "2" above
$ /usr/local/bin/bitcoin-cli -conf=/home/bitcoin14/.bitcoin/regtest.conf dumpprivkey mk5U6xEDnTmfNrHcCXkdKrXziYH1YMygVw
cPMjUqc3d4WhDG8Evn2G3RrVWMyetHtwiTZhpKW1T1QUrBhYGVnG
- I convert the private key into the hex equivalent as per https://bitcoin.stackexchange.com/a/52954/89798 (This on a different machine)
$ ./bitcoin-tool --input-type private-key-wif --input-format base58check --output-type private-key --output-format hex --network bitcoin --input cPMjUqc3d4WhDG8Evn2G3RrVWMyetHtwiTZhpKW1T1QUrBhYGVnG
3500dba7a3363e7127cd72273b0e475c5dbb1d378496b803edaf06f8eb3ee160
- I take the above and edit them into place in Runeks' code
HEX_TRANSACTION="0100000001fe37d2309bb4b4f4de102ff08f08e049acaecd4c1ee195328404c02406e596c6000000004847304402206eef31e0114c8e31180da39c644fc518624e9c5f354f6c375bfffba8a3c0dc6d022021056d74ea16155036663b7aaab1e297715231747718e48ab94aefd05cded83d01feffffff0254330f00000000001976a91486d1e65bc7f89b24724f50fa5db3a7f102d9644d88acc0aff629010000001976a9143206b266d2998b1092fcd1737165c363c0e31b6c88ac65000000"
...
OUTPUT_INDEX=1
...
SEND_TO_ADDRESS="n42ui4Tbd2mVPiRtAUr4RYW7KC7qUmXDTt"
...
PRIVATE_KEY=0x3500dba7a3363e7127cd72273b0e475c5dbb1d378496b803edaf06f8eb3ee160
- I run the code (again different machine to the above)
$ python2 sign3.py
Traceback (most recent call last):
File "sign3.py", line 144, in <module>
(OUTPUT_INDEX, hash_160_to_bc_address(tx_info['txOut'][OUTPUT_INDEX]['scriptPubKey'][3:-2], bytes[0]))
RuntimeError: The supplied private key cannot be used to redeem output index 1
You need to supply the private key for address mk5U6xEDnTmfNrHcCXkdKrXziYH1YMygVw
The error is clear: I have not supplied the correct private key. Where is my mistake? Thanks all!
Edit
It appears that bitcoind-0.13 provides a pubkeyhash based on a compressed public key, and that the code beneath acts on the uncompressed public key that the private key reveals. The two hashes being different, the later conditional fails.
k = ecdsa_ssl.KEY()
k.generate(('%064x' % PRIVATE_KEY).decode('hex'))
#here we retrieve the public key data generated from the supplied private key
pubkey_data = k.get_pubkey()
Investigations continue...