Finanzierung und Ausgabe eines "no-multisig/no segwit" P2SH tx

Inspiriert wurde ich von diesem Thread:

Einzelsignatur-P2SH-Einlösungsskript

Angenommen, ich möchte meine Adresse so lange wie möglich "verstecken". Also möchte ich einen P2SH-Tx, der nur ein Redescript (Hash meines Pubkeys) auf der Blockchain anzeigt, bis er ausgegeben wird. Ich versuche analog zu einem Multisig zu gehen, verwende aber nur den Pubkey als Redescript. Der Finanzierungs-Tx würde den öffentlichen Schlüssel hash160 und als Einlösungsskript verwenden. Dies wäre eine Zahlung an eine "Typ 3-Adresse", mit diesem Code im "tx_out pkscript".

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

Würde der Ausgaben-TX dies in seiner Skriptsig haben?

<sig><pubkey><OP_CHECKSIG>

(anstatt wie es bei Multisigs gemacht wird: <sig><pubkey 1-n><OP_CHECKMULTISIG>)

Schauen, was auf dem Stack passiert:

sig
pubkey
<OP_CHECKSIG>

<OP_HASH160>
redeem hash
<OP_Equal>

Damit dies funktioniert, <OP_HASH160>müsste der Opcode wissen, dass der Pubkey und der <OP_CHECKSIG>gemeinsam gehasht werden müssten (zu vergleichen mit dem Redeemscript-Hash, der für folgt <OP_Equal>) ...

Ich denke, die gleiche Frage gilt für Multisig. Es gibt nur zwei oder mehr Pubkeys gefolgt von <OP_CHECKMULTISIG>(statt <OP_CHECKSIG>).

Antworten (1)

Jetzt verstehe ich, warum keine Antwort kam - es wird echt lang :-)

Also beantworte ich sie selbst. Ich bin mit Bitcoin Core (getinfo) Version 150100, auf OpenBSD (ksh) und OSX (bash v3):

Ich habe es auf Testnet gelöst und den TX zum Durchlaufen gebracht. Einige Informationen von @nick hier:
Verbraucht OP_HASH160 das oberste Stapelelement?

Ich habe mich gefragt, ob das stimmt:

Damit dies funktioniert, <OP_HASH160>müsste der Opcode wissen, dass der Pubkey und der <OP_CHECKSIG>zusammen gehasht werden müssten

Offensichtlich tut es das. Hier ist der ganze Zyklus ... Zuerst versuche ich, einen Blick auf den Stack mit Ein- und Ausgabeskripten zu werfen (siehe Link oben):

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

Basierend auf dem obigen Link und mit Blick auf den Stack würde es die folgenden Schritte durchlaufen:

  1. Input SigScript (Push-Daten auf Stack) STACK:

  2. Pubkey-Skript ausführen a. Dies würde zuerst den ersten OPCODE des Pubkey-Skripts auf den Stapel schieben und STACK ausführen: OP_HASH160

    B. Dieser Befehl verbraucht das oberste Stack-Element und ersetzt es durch Hash STACK:

    C. Die nächsten Elemente des Pubkey-Skripts werden auf den Stack STACK: OP_EQUAL geschoben

  3. OP_Equal überprüft die obersten zwei Stack-Elemente, falls nicht wahr --> ungültig

  4. Wenn wahr, endet das Skript mit „true“ oben auf dem Stapel STACK:

  5. Überprüfen Sie, ob das Skript P2SH ist (... ok, es ist P2SH ...)

  6. Bereinigen Sie den Stack und führen Sie sigscript erneut aus STACK:

  7. pop top stack element, und führen Sie es als Skript aus a. Das oberste Element des Einlösungsskripts ist OP_CHECKSIG STACK: OP_CHECKSIG

    B. CHECKSIG würde Pubkey und Sig überprüfen und true zurückgeben ...

Um zu sehen, ob dies korrekt ist, stellen Sie eine Finanzierungsübertragung auf testnet/regtest zusammen. Bei Verwendung von Coinbase TX (abgebauter Block) sind >100 Bestätigungen erforderlich! Beginnen Sie mit der Erstellung eines Einlöseskripts und einer Adresse für diesen 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

Die Adresse des Einlösungsskripts würde im Testnetz mit einer „2“ beginnen. Erstellen Sie nun den Finanzierungstx. Suchen Sie nach einem UTXO, das wir verwenden können, und notieren Sie sich tx und 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"

An diesem Punkt wird die Finanzierungstransaktion gesendet. Jetzt brauchen wir eine neue Adresse, um die Gelder von der P2SH-Adresse zu erhalten:

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 )

Erstellen Sie die Rohübertragung, unterschreiben Sie sie und senden Sie sie (möglicherweise muss der Betrag aktualisiert werden):

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

An dieser Stelle konnte ich sehen, dass meine neu generierte RCVADDRESS den Wert (bitcoin-cli -regtest listunspent | grep -A5 -B5 $RCVADDRESS) enthielt:

... "Betrag": 7.76990000

Ich hatte eine kleinere Beobachtung, die mir noch nicht ganz klar ist: Der scriptsig wurde im finalen tx geändert. Es hatte die Signatur, und dahinter sollte das Erlösungsskript folgen. Dieses Einlöseskript wurde auf diese Weise "erweitert":

23210355ef94c6e097752f303d685e4011b9dba8c1cd1382f8fa68bf2de0d523f18fffac

Die 23 am Anfang wäre der Längenindikator für den folgenden Pubkey, aber dies würde "ac" enthalten ... Ich bin mir nicht sicher, warum Bitcoin Core es so erweitert.

Jetzt, wo ich es mit einfachem P2SH zum Laufen gebracht habe, kann ich SegWit-P2SH ausprobieren :-)

Nimm meine E-Mail: alistermaclin@mail.ru und frage irgendetwas :)