Script

為“無多重簽名/無隔離見證”的 P2SH 交易提供資金和支出

  • April 7, 2018

我受到這個執行緒的啟發:

單簽P2SH贖回腳本

假設我想盡可能“隱藏”我的地址。所以我想要一個 P2SH tx,它只在區塊鏈上顯示一個兌換腳本(我的公鑰的雜湊),直到用完為止。我嘗試模擬多重簽名,但僅使用公鑰作為兌換腳本。資金 tx 將散列 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 和<OP_CHECKSIG>需要一起散列(與 for 之後的redeemscript散列進行比較<OP_Equal>)……

我認為同樣的問題也適用於多重簽名。只有兩個或多個 pubkey 後跟<OP_CHECKMULTISIG>(而不是<OP_CHECKSIG>)。

現在我明白了,為什麼沒有答案 - 它真的很長:-)

所以我自己回答。我在 OpenBSD (ksh) 和 OSX (bash v3) 上使用比特幣核心 (getinfo) 版本 150100:

我在 testnet 上解決了它,並讓 tx 通過。來自@nick

的一些資訊:OP_HASH160 是否消耗棧頂元素?

我想知道,如果這是真的:

為此,<OP_HASH160>操作碼必須知道 pubkey 和<OP_CHECKSIG>需要一起散列

顯然是的。這是整個週期…首先我嘗試使用輸入和輸出腳本查看堆棧(根據上面的連結):

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

根據上面的連結並查看堆棧,它將通過以下步驟執行:

  1. 輸入 SigScript(將數據推送到堆棧)堆棧:
  2. 執行 pubkey 腳本 這將首先將 pubkey 腳本的第一個 OPCODE 推送到堆棧上並執行 STACK: OP_HASH160

灣。此命令消耗頂部堆棧元素,並替換為雜湊堆棧:

C。pubkey 腳本的下一個元素被推送到堆棧堆棧:OP_EQUAL 3. OP_Equal 驗證棧頂兩個元素,如果不正確 –> 無效 4. 如果為真,則腳本在堆棧堆棧頂部以“真”結尾: 5. 驗證腳本是否為 P2SH(…好吧,它是 P2SH …) 6. 清理堆棧,然後再次執行 sigscript STACK: 7. 彈出棧頂元素,並將其作為腳本執行。贖回腳本的頂部元素是 OP_CHECKSIG STACK: OP_CHECKSIG

灣。CHECKSIG 將驗證 pubkey 和 sig,並返回 true …

要查看這是否正確,請在 testnet/regtest 上收集資金交易。使用 coinbase tx(挖出的區塊)時,需要 >100 次確認!首先為此 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

贖回腳本的地址將在測試網上以“2”開頭。現在創建資金交易。搜尋一個我們可以使用的 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"

此時,發送資金交易。現在是支出 tx,我們需要一個新地址來接收來自 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 )

創建原始交易,簽名並發送(可能需要更新金額):

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

我有一個較小的觀察結果,但對我來說還不是很清楚:scriptsig 在最終的 tx 中發生了變化。它有簽名,後面應該跟著redeemscript。此兌換腳本以這種方式“擴展”:

23210355ef94c6e097752f303d685e4011b9dba8c1cd1382f8fa68bf2de0d523f18fffac

開頭的 23 將是以下公鑰的長度指示符,但這將包括“ac”……不確定,為什麼比特幣核心以這種方式擴展它。

現在我可以使用簡單的 P2SH,我可以嘗試 SegWit-P2SH :-)

引用自:https://bitcoin.stackexchange.com/questions/68235