финансирование и расходы на P2SH-транзакцию без мультиподписи/сегвита

Меня вдохновила эта тема:

Сценарий выкупа P2SH с одной подписью

Предположим, я хочу «скрывать» свой адрес как можно дольше. Итак, я хочу P2SH-транзакцию, которая показывает только сценарий погашения (хэш моего открытого ключа) в блокчейне до тех пор, пока он не будет потрачен. Я пытаюсь использовать аналог мультиподписи, но использую только публичный ключ в качестве сценария погашения. Финансовая передача будет хешировать160 открытый ключ и использовать его в качестве сценария выкупа. Это будет платеж на «адрес типа 3» с этим кодом в «tx_out pkscript».

A9: OP_HASH160
14: OP_Data14 (= decimal 20 and the redeem hash)
87: OP_EQUAL

Будет ли это в сценарии расходов?

<sig><pubkey><OP_CHECKSIG>

(вместо того, как это делается в мультиподписях: <sig><pubkey 1-n><OP_CHECKMULTISIG>)

Глядя, что происходит в стеке:

sig
pubkey
<OP_CHECKSIG>

<OP_HASH160>
redeem hash
<OP_Equal>

Чтобы это сработало, код <OP_HASH160>операции должен знать, что pubkey и the <OP_CHECKSIG>должны быть хешированы вместе (для сравнения с хэшем redeemscript, который следует за <OP_Equal>) ...

Я думаю, что тот же вопрос относится и к мультиподписи. Есть только два или более публичных ключа, за которыми следует <OP_CHECKMULTISIG>(вместо <OP_CHECKSIG>).

Ответы (1)

Теперь понятно, почему не было ответа - получается очень долго :-)

Так что отвечаю сам. Я использую биткойн-ядро (getinfo) версии 150100, на OpenBSD (ksh) и OSX (bash v3):

Я решил это в тестовой сети и получил tx для прохождения. Некоторая информация от @nick здесь:
потребляет ли OP_HASH160 верхний элемент стека?

Мне было интересно, верно ли это:

Чтобы это сработало, <OP_HASH160>код операции должен знать, что публичный ключ и ключ <OP_CHECKSIG>должны быть хешированы вместе.

Очевидно, что да. Вот и весь цикл... Сначала я пытаюсь взглянуть на стек со скриптами ввода и вывода (по ссылке выше):

sigscript:     <sig> <redeem script> 
pubkey script: OP_HASH160 <RedeemScriptHash> OP_EQUAL

Основываясь на приведенной выше ссылке и глядя на стек, он будет выполнять следующие шаги:

  1. Ввод SigScript (проталкивание данных в стек) STACK:

  2. Выполнение сценария публичного ключа a. это сначала поместит первый OPCODE сценария публичного ключа в стек и выполнит STACK: OP_HASH160

    б. эта команда использует верхний элемент стека и заменяет его хэшем STACK:

    в. следующие элементы сценария публичного ключа помещаются в стек STACK: OP_EQUAL

  3. OP_Equal проверяет два верхних элемента стека, если неверно --> недействительно

  4. Если true, скрипт заканчивается со значением «true» в верхней части стека STACK:

  5. проверьте, является ли сценарий P2SH (... хорошо, это P2SH...)

  6. очистите стек и снова запустите sigscript STACK:

  7. извлеките верхний элемент стека и запустите его как скрипт a. верхний элемент сценария выкупа — OP_CHECKSIG STACK: OP_CHECKSIG

    б. CHECKSIG проверит pubkey и sig и вернет true...

Чтобы проверить, правильно ли это, соберите транзакцию финансирования в testnet/regtest. При использовании coinbase tx (заминированный блок) требуется> 100 подтверждений! Начните с создания redeemscript и адреса для этого tx:

NEWADDRESS=$( bitcoin-cli -regtest getnewaddress )
echo $NEWADDRESS
PUBKEY=$( bitcoin-cli -regtest validateaddress $NEWADDRESS | awk -F '\"' '/pubkey/ { print $4 }' )
REDEEMSCRIPT=$( printf "21%sac" $PUBKEY )
# creating the hash of the REDEEMSCRIPT
printf $( echo $REDEEMSCRIPT | sed 's/[[:xdigit:]]\{2\}/\\x&/g' ) > tmp_fn.hex
openssl dgst -sha256 -binary <tmp_fn.hex >tmp_sha256.hex
REDEEMSCRIPTHASH=$( openssl dgst -ripemd160 <tmp_sha256.hex | cut -d " " -f2 )
# convert redeemscripthash to bitcoin address (testnet!), with "C4" Prefix
PRFX_REDEEMSCRIPT=$( printf "c4%s" $REDEEMSCRIPTHASH )
# double sha256 the hex value
printf $( echo $PRFX_REDEEMSCRIPT | sed 's/[[:xdigit:]]\{2\}/\\x&/g' ) > tmp_fn.hex
openssl dgst -sha256 -binary <tmp_fn.hex >tmp_sha256.hex
openssl dgst -sha256 <tmp_sha256.hex | cut -d " " -f2 >tmp_dsha256.txt
# checksum and append
result=$( cat tmp_dsha256.txt | cut -b 1-8 )
result=$( printf "%s%s" $PRFX_REDEEMSCRIPT $result | tr "[:lower:]" "[:upper:]" )
# and base58
base58str="123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
REDEEMSCRIPTADDR=$( dc -e "16i $result [3A ~r d0<x]dsxx +f" | while read -r n; do 
    j=$(( n + 1 ))
    echo $base58str | cut -b $j 
  done | tr -d '\n' ) 
bitcoin-cli -regtest importaddress "$REDEEMSCRIPTADDR" p2sh 
bitcoin-cli -regtest importaddress "$REDEEMSCRIPTADDR" rescan
bitcoin-cli -regtest validateaddress "$REDEEMSCRIPTADDR"
bitcoin-cli -regtest listunspent

Адрес redeemscript будет начинаться с «2» в тестовой сети. Теперь создайте финансирование tx. Найдите UTXO, который мы можем использовать, и запишите tx и vout.

UTXO_TXID=d260e120647360dcfc8606e242c6389acece3ee585d5e0d76a26b87b08b322e0
UTXO_VOUT=0
VALUE=49.9997
RAW_TX=$( bitcoin-cli -regtest createrawtransaction '''[{"txid":"'$UTXO_TXID'","vout":'$UTXO_VOUT'}]''' '''{"'$REDEEMSCRIPTADDR'":'$VALUE'}''' )
bitcoin-cli -regtest decoderawtransaction $RAW_TX
SIGNED_TX=$( bitcoin-cli -regtest signrawtransaction $RAW_TX | awk -F '\"' '{ print $4 }' )
bitcoin-cli -regtest decoderawtransaction $SIGNED_TX
UTXO_TXID=$( bitcoin-cli -regtest sendrawtransaction $SIGNED_TX )
bitcoin-cli -regtest getrawmempool
bitcoin-cli -regtest generate 1

# verify new address has funds:
bitcoin-cli -regtest validateaddress "$REDEEMSCRIPTADDR"
bitcoin-cli -regtest getreceivedbyaddress "$REDEEMSCRIPTADDR"

В этот момент транзакция финансирования отправляется. Теперь о расходах, нам нужен новый адрес для получения средств с адреса P2SH:

RCVADDRESS=$( bitcoin-cli -regtest getnewaddress )
echo $RCVADDRESS

# verify that tx from $REDEEMSCRIPTADDR has funds
RAW_TX=$( bitcoin-cli -regtest getrawtransaction $UTXO_TXID )
bitcoin-cli -regtest decoderawtransaction $RAW_TX
# to send funds from $REDEEMSCRIPTADDR to a new address, need the privkey:
NEWADDRESS_PRIVKEY=$( bitcoin-cli -regtest dumpprivkey $NEWADDRESS )

создайте необработанный tx, подпишите его и отправьте (возможно, необходимо обновить сумму):

UTXO_VOUT=0
UTXO_OUTPUT_SCRIPT=$( bitcoin-cli -regtest validateaddress "$REDEEMSCRIPTADDR" | awk -F '\"' '/scriptPubKey/ { print $4 }' )
VALUE=7.7699
RAW_TX=$( bitcoin-cli -regtest createrawtransaction '''[{"txid":"'$UTXO_TXID'","vout":'$UTXO_VOUT'}]''' '''{"'$RCVADDRESS'":'$VALUE'}''' )
bitcoin-cli -regtest decoderawtransaction $RAW_TX
SIGNED_TX=$( bitcoin-cli -regtest signrawtransaction $RAW_TX '''[{"txid": "'$UTXO_TXID'","vout": '$UTXO_VOUT',"scriptPubKey": "'$UTXO_OUTPUT_SCRIPT'","redeemScript": "'$REDEEMSCRIPT'"}]''' '''["'$NEWADDRESS_PRIVKEY'"]''' | awk -F '\"' '{ print $4 }' )
UTXO_TXID=$( bitcoin-cli -regtest sendrawtransaction $SIGNED_TX )
bitcoin-cli -regtest getrawmempool
bitcoin-cli -regtest generate 1

В этот момент я мог видеть, что мой только что сгенерированный RCVADDRESS содержит значение (bitcoin-cli -regtest listunspent | grep -A5 -B5 $RCVADDRESS):

... "сумма": 7.76990000

У меня было одно небольшое наблюдение, которое мне пока не совсем ясно: в финальном tx был изменен scriptsig. У него была подпись, а за ним должен был следовать выкупной скрипт. Этот redeemscript был «расширен» следующим образом:

23210355ef94c6e097752f303d685e4011b9dba8c1cd1382f8fa68bf2de0d523f18ffac

23 в начале будет индикатором длины для следующего открытого ключа, но он будет включать «ac»... Не уверен, почему биткойн-ядро расширяет его таким образом.

Теперь, когда я научился работать с простым P2SH, я могу попробовать SegWit-P2SH :-)

берите мою почту: alistermaclin@mail.ru и спрашивайте что угодно :)