karask / python-bitcoin-utils

Library to interact with the Bitcoin network. Ideal for low-level learning and experimenting.
MIT License
271 stars 102 forks source link

How to sign P2SH-P2WPKH input? #8

Closed qwerty-w closed 4 years ago

qwerty-w commented 4 years ago

Hi, I have a question about your library. How can I sign a P2SH-P2WPKH transaction? Code i am trying to use is below.

from bitcoinutils import script, keys, transactions, setup
from bitcoinutils.utils import to_satoshis

setup.setup('testnet')

priv = keys.PrivateKey('cMibua6X82JUQ84ocvDQYzBajZMiXr3kCdup6zjK3umTKaj6iRvi')
pub = priv.get_public_key()
redeem_script = pub.get_segwit_address().to_script_pub_key()

p2sh_addr = keys.P2shAddress.from_script(redeem_script)
to_addr = keys.P2pkhAddress('mjzV9HvsYj7LfA8egPkqCV7qLr1Ld9RSU5')

inp = transactions.TxInput('30045a84ec5bfc50de81c3db1287cb01a80e96c71a09855ac344d2a531410fce', 1)
out = transactions.TxOutput(to_satoshis(0.0001), to_addr.to_script_pub_key())

tx = transactions.Transaction([inp], [out])

sig = priv.sign_input(tx, 0, redeem_script)
inp.script_sig = script.Script([sig, redeem_script.to_hex()])

print(tx.serialize())

But I get an error when broadcast a transaction - "witness P2SH has extra data or nonminimal push". I started to study bitcoin recently and do not quite understand how everything works, I will be glad if you help me. Thank you in advance.

qwerty-w commented 4 years ago

It's a pity that I didn't get an answer, here's the solution:

from bitcoinutils.script import Script
from bitcoinutils import keys, transactions, setup
from bitcoinutils.utils import to_satoshis

setup.setup('testnet')

priv = keys.PrivateKey('cMibua6X82JUQ84ocvDQYzBajZMiXr3kCdup6zjK3umTKaj6iRvi')
pub = priv.get_public_key()
redeem_script = pub.get_segwit_address().to_script_pub_key()

p2sh_addr = keys.P2shAddress.from_script(redeem_script)
to_addr = keys.P2pkhAddress('mjzV9HvsYj7LfA8egPkqCV7qLr1Ld9RSU5')

inp = transactions.TxInput('30045a84ec5bfc50de81c3db1287cb01a80e96c71a09855ac344d2a531410fce', 1)
out = transactions.TxOutput(to_satoshis(0.0001), to_addr.to_script_pub_key())

tx = transactions.Transaction([inp], [out], has_segwit=True)

script_pub_key = pub.get_address().to_script_pub_key()
sig = priv.sign_segwit_input(tx, 0, script_pub_key, amount=to_satoshis(0.0008))
script_sig = Script([sig, pub.to_hex()])

inp.script_sig = Script([redeem_script.to_hex()])
tx.witnesses.append(script_sig)

print(tx.serialize())
karask commented 4 years ago

Hi @qwerty-w ! I am away and intended to look into it on Monday.

I am glad you found the solution. The specific transaction needed some deeper knowledge on how to construct it, so good job!

I am working on a bitcoin textbook (based on my lecture notes of years of bitcoin programming) in which I will include a lot of examples based on this library (with a lot of explanations). I will link it here as well to help people use the library.

qwerty-w commented 4 years ago

Привет @ qwerty-w ! Я уезжаю и собираюсь разобраться в этом в понедельник.

Я рад, что вы нашли решение. Конкретная транзакция требует более глубоких знаний о том, как ее построить, так что отличная работа!

Я работаю над учебником по биткойнам (на основе моих конспектов лекций, посвященных многолетнему программированию биткойнов), в который я буду включать множество примеров, основанных на этой библиотеке (с большим количеством объяснений). Я также свяжу его здесь, чтобы помочь людям использовать библиотеку.

Thanks, and also taking this opportunity to thank you for this library. I was looking for a good library with P2WPKH Bech32 addresses supported until I came across your creation. I wish you continued success.