jimmysong / programmingbitcoin

Repository for the book
Other
1.72k stars 653 forks source link

Chapter 7, Exercise 4: Confused on the Solution #249

Open vvronskyFX opened 2 years ago

vvronskyFX commented 2 years ago

I'm working through this exercise and it's been some time. I want to move forwards to Ch 8 but I really want to get this solution to work.

First thing that stands out here is the the instruction to "Create a testnet transaction that sends 60% of a single UTXO to mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv The remaining amount minus fees should go back to your own change address. This should be a one-input, two-output transaction."

However, in the solution, the target_address is 'miKegze5FQNCnGw6PKyqUbYUeBa4x2hFeM'

Next is we need to include a fee in there but I don't see how I can set up a fee.

Next is the fact that we want 60% of the UTXO to be sent to the target address. I just put in a target_amount of 0.0002

All in all, i get a Hex code but when i run >>> print(tx_obj.sign_input(0, priv)) I get a FALSE output.

Here's the solution screenshot: image

Here's my code within Exercise 4: image

I couldn't find any solution online. Has anyone passed this exercise here?

vvronskyFX commented 2 years ago

How can we get fees in there? I've broadcasted the last transaction but it's having difficulty confirming. See this bitcoin testnet transaction: https://live.blockcypher.com/btc-testnet/tx/2946d9b34eb63575898fc881ec0e157154f9afd24ed3d371f83616f097c9043e/

No fees. Would be nice to get them in there. I'll play around with it and post updates here.

vvronskyFX commented 2 years ago

UPDATE:

I've been able to resolve the FALSE output. Let's look at the "priv" variable.

I changed priv = PrivateKey(secret=secret) to priv = PrivateKey(secret)

alexbarron commented 2 years ago

The fees are not explicitly set in a transaction. They must be implicitly set based on this formula: fee = input_amount - target amount - change_amount

Just reduce the target_amount or change_amount in your code to automatically include a fee. I calculated it by doing this:

input_amount = 0.0005690
target_amount = input_amount * 0.6
change_amount = input_amount * 0.36

This is a rather generous fee. Apparently I overpaid by 912%!

vvronskyFX commented 1 year ago

The fees are not explicitly set in a transaction. They must be implicitly set based on this formula: fee = input_amount - target amount - change_amount

Just reduce the target_amount or change_amount in your code to automatically include a fee. I calculated it by doing this:

input_amount = 0.0005690
target_amount = input_amount * 0.6
change_amount = input_amount * 0.36

This is a rather generous fee. Apparently I overpaid by 912%!

@alexbarron Thanks so much for sharing this! I'm just about wrapped up with Ch 12 and Ch 13. Once I wrap those up, I'll revisit Ch 4 and implement this again. Cheers!

asteryeyo commented 1 year ago

Hello all, I tried to run Example 4 but I was not able to broadcast the transaction on https://live.blockcypher.com/btc/pushtx/ gives me an error Error validating transaction: witness script detected in tx without witness data.

My code:

from ecc import PrivateKey from helper import decode_base58, SIGHASH_ALL from script import p2pkh_script, Script from tx import TxIn, TxOut, Tx prev_tx = bytes.fromhex('c4c34a8d9a705a1a7e4bd753314e25697f82622f5cbf25ea4dbb2b6f48ce719a') prev_index = 1 target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' change_address = 'mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG' input_amount = 0.0002 target_amount = input_amount 0.6 change_amount = input_amount 0.36

secret = 8675309

priv = PrivateKey(secret) tx_ins = [] tx_ins.append(TxIn(prev_tx, prev_index)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = int(target_amount100000000) tx_outs.append(TxOut(target_satoshis, script_pubkey)) h160 = decode_base58(change_address) script_pubkey = p2pkh_script(h160) change_satoshis = int(change_amount100000000) tx_outs.append(TxOut(change_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) print(tx_obj.sign_input(0, priv)) print(tx_obj.serialize().hex()) print(secret)


I created secret as from ecc import PrivateKey from helper import hash256, little_endian_to_int secret = little_endian_to_int(hash256(b'Hashir secret')) private_key = PrivateKey(secret) print(private_key.point.address(testnet=True)) print(secret)

Notes: I sent some coins 0.0006 to my address mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG I use the prev transaction from here: https://live.blockcypher.com/btc-testnet/address/mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG/ but I am unable to broadcast the transaction

marteaga76 commented 1 year ago

@asteryeyo @vvronskyFX FYI, I was getting a similar error and finally got to the bottom of it. In my case the issue was that in Chapter 4 Exercise 9 where you are asked to create an address the book does not specify compressed vs. uncompressed format. I chose uncompressed, which led to pain, as in the Chapter 7, the Tx.sign_input method assumes compressed when creating the script_sig.

def sign_input(self, input_index, private_key):
    # get the signature hash (z)
    # get der signature of z from private key
    # append the SIGHASH_ALL to der (use SIGHASH_ALL.to_bytes(1, 'big'))
    # calculate the sec
    # initialize a new script with [sig, sec] as the cmds
    # change input's script_sig to new script
    # return whether sig is valid using self.verify_input
    #raise NotImplementedErro
    z=self.sig_hash(input_index)
    sig=private_key.sign(z).der()
    sig+=SIGHASH_ALL.to_bytes(1, 'big')
    sec = private_key.point.sec(compressed=False)  #<-- this fixed it for me
    script=Script([sig, sec])
    self.tx_ins[input_index].script_sig=script
    return self.verify_input(input_index)
MolekoManyanye commented 10 months ago

I'm working through this exercise and it's been some time. I want to move forwards to Ch 8 but I really want to get this solution to work.

First thing that stands out here is the the instruction to "Create a testnet transaction that sends 60% of a single UTXO to mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv The remaining amount minus fees should go back to your own change address. This should be a one-input, two-output transaction."

However, in the solution, the target_address is 'miKegze5FQNCnGw6PKyqUbYUeBa4x2hFeM'

Next is we need to include a fee in there but I don't see how I can set up a fee.

Next is the fact that we want 60% of the UTXO to be sent to the target address. I just put in a target_amount of 0.0002

All in all, i get a Hex code but when i run >>> print(tx_obj.sign_input(0, priv)) I get a FALSE output.

Here's the solution screenshot: image

Here's my code within Exercise 4: image

I couldn't find any solution online. Has anyone passed this exercise here?

response regarding the fees: i constructed my transaction with zero fees and after all the signing , i calculated the serialized txn hash . i then set my fees to 1*transaction length, that is paying 1 Satoshi per byte

MolekoManyanye commented 10 months ago

i meant the serialized txn length not length of its hash

MolekoManyanye commented 10 months ago

Hello all, I tried to run Example 4 but I was not able to broadcast the transaction on https://live.blockcypher.com/btc/pushtx/ gives me an error Error validating transaction: witness script detected in tx without witness data.

My code:

from ecc import PrivateKey from helper import decode_base58, SIGHASH_ALL from script import p2pkh_script, Script from tx import TxIn, TxOut, Tx prev_tx = bytes.fromhex('c4c34a8d9a705a1a7e4bd753314e25697f82622f5cbf25ea4dbb2b6f48ce719a') prev_index = 1 target_address = 'mwJn1YPMq7y5F8J3LkC5Hxg9PHyZ5K4cFv' change_address = 'mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG' input_amount = 0.0002 target_amount = input_amount 0.6 change_amount = input_amount 0.36 #secret = 8675309 priv = PrivateKey(secret) tx_ins = [] tx_ins.append(TxIn(prev_tx, prev_index)) tx_outs = [] h160 = decode_base58(target_address) script_pubkey = p2pkh_script(h160) target_satoshis = int(target_amount_100000000) tx_outs.append(TxOut(target_satoshis, script_pubkey)) h160 = decode_base58(change_address) script_pubkey = p2pkh_script(h160) change_satoshis = int(change_amount_100000000) tx_outs.append(TxOut(change_satoshis, script_pubkey)) tx_obj = Tx(1, tx_ins, tx_outs, 0, testnet=True) print(tx_obj.sign_input(0, priv)) print(tx_obj.serialize().hex()) print(secret)

I created secret as from ecc import PrivateKey from helper import hash256, little_endian_to_int secret = little_endian_to_int(hash256(b'Hashir secret')) private_key = PrivateKey(secret) print(private_key.point.address(testnet=True)) print(secret)

Notes: I sent some coins 0.0006 to my address mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG I use the prev transaction from here: https://live.blockcypher.com/btc-testnet/address/mtjfgktYZdoEt8XgU5gM7BRx4yrHsqY1yG/ but I am unable to broadcast the transaction

some one apparently has 345 tBTC. Looks like you have the wrong index. prev_index has to be a 0 not 1