Я пытаюсь создать tx с 4 входами и подписать его через cmdline и openssl на машине с холодным хранилищем. Затем я хочу отправить его через биткойн qt (или blockchain.info). У меня уже работает подпись с одним входом и одним выходом (через строку unix cmd и OpenSSL). Теперь я хочу использовать несколько входов, с небольшой помощью от stackexchange здесь: Как подписать транзакцию с несколькими входами?
Я создал транзакцию с 4 входами и не могу заставить ее работать. Транзакция выглядит следующим образом и корректно декодируется в биткойн qt (decoderawtransaction) или с помощью https://blockchain.info/de/decode-tx :
0100000004b0772e6ef46c2d3c60418bb7d5c2c015d6b943e5fca07570eb82c26dc7c9d248010000006B483045022100D675D9F98E5B1F01BDB05E5389ACB453EFA14EF399361099736376611D9BF88E02206B8FEF37F2C2316D3629D6C43945AFA23B0EB0CA2C1163E33B28066B01A4E241012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff74fb6858c31a292d20c9744187032bddb7ddea02a3aa3ef523c8524a21481881010000006A47304402200F921996446FBAD78ECB6C95303ECD13145CA7E13E769B44742FA499325B347402202F8378D7D154F4F8D345525696F8E31DF8A96C05AA58B2F53012E3550CC90AE7012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffcc21e36eedb509c660681c1e949dd294bd4c11692439221004c2235d565b74bb000000006A47304402206B7C2D73EC787ADD99740DAB78F7252ED49A1BA42BA358A667BF118B8740BB0C0220366EF47DE6339C261946513C939A301ECF940A294036ED72A5FD893C5CAFEED8012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffffea919487e04ed509d6cb9c7297c277b9be3a68f3836c7d86df378714a75949e8000000006A47304402205B595472AA821D96DBFB6E531A663571A9DB14DDFCF8AC0B4330B6264955C15F02203FDF004B19996654490F00FA9BDFC175265CF95BA6DC86943B4B7C50EAF23616012103cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0ffffffff0120830c00000000001976a91418ec49b27624086a2b6f35f263d951d25dbe24b688ac00000000
Загрузка с помощью биткойн qt (senddrawtransaction) дает эту ошибку:
16: обязательное подтверждение флага сценария (подпись должна быть нулевой для неудачной операции CHECK(MULTI)SIG) (код -26)
Какие у меня есть варианты, чтобы определить следующие шаги, если что-то пойдет не так?
Это помогло мне запустить его для одной входной транзакции: Проверка биткойн trx в строке cmd Unix с помощью OpenSSL?
Теперь у меня есть четыре входа и сжатые публичные ключи. Я снова создал вышеуказанный tx в Electrum (те же 4 входа, тот же единственный выход), подписал его. Но не отправил. Затем я расшифровал сгенерированный Electrum и сгенерированный мной tx и построчно проверил, что нет различий в значениях (кроме строк подписи, они, конечно, различаются). После этого я создал текстовый файл с командами, который выдает публичный ключ, хэш (двойной sha256) и подпись для каждого ввода. Таким образом, я мог бы проверить подписи с помощью openssl следующим образом:
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
Когда я проверяю каждую подпись в транзакции, я всегда получаю сообщение об успехе от OpenSSL (полный файл прикреплен в конце ниже). Однако, когда я отправляю его через биткойн qt, я получаю вышеупомянутое сообщение об ошибке. Сообщение об ошибке исходит от «сети биткойнов»... Как я могу эмулировать это?
Чтобы подтвердить транзакцию, выполняется проверка входного SigScript для транзакций и предыдущего вывода PKScript для транзакций. Поэтому я дважды проверил сценарий вывода предыдущей транзакции (для каждого входа). Они все одинаковые:
OP_DUP OP_HASH160 c2df275d78e506e17691fd6f0c63c43d15c897fc OP_EQUALVERIFY OP_CHECKSIG
Мои действия по проверке будут выглядеть следующим образом: я удаляю SIG и PUBKEY из SigScript ввода tx в виртуальный стек, а затем запускаю PKScript для него шаг за шагом для всех входов. Вот пример для первого ввода (более или менее шаги эмуляции стека):
step action result
1 SIGSCRIPT SIGNATURE 3045022100D675D9F98E5B1F . . . B28066B01A4E241
2 SIGSCRIPT PUBKEY 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
3 OP_DUP PUBKEY 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
4 OP_HASH160 xxd -r -p <PUBKEY.txt >pubkey.hex
openssl dgst -binary -sha256 <pubkey.hex >pk_sha256.hex
openssl dgst -binary -ripemd160 <pk_sha256.hex >pkhash.hex
xxd -ps pkhash.hex
c2df275d78e506e17691fd6f0c63c43d15c897fc
5 PKSCRIPT PKH c2df275d78e506e17691fd6f0c63c43d15c897fc
6 OP_EQUALVERIFY YES !
Здесь я сгенерировал для всех 4 входов один и тот же PUBKEY_HASH, так что OP_Equalverify должен работать правильно. В стеке осталось:
1 Input SIGNATURE 3045022100D675D9F98E5B1F . . . B28066B01A4E241
2 Input PUBKEY 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
3 OP_CHECKSIG
Я не знаю, что происходит здесь, в сети, я хотел бы думать, что она декодирует транзакцию в свои элементы (для каждого входа), создает над ней хэш и делает что-то похожее на то, что я сделал (конечно, с другими библиотеками ): ПРОВЕРЬТЕ ПОДПИСЬ. Я сделал это так:
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
Есть ли способ получить более конкретное сообщение об ошибке при отправке «неправильной» транзакции? "mandatory-script-verify-flag-failed" и "(код -26)" не помогают мне в дальнейшей отладке...
Вот файл, который был сгенерирован в процессе транзакции и помогает проверить подпись для каждого входа:
##############################################
### Bitcoin prep file to verify signatures ###
##############################################
# Bitcoin (and here with openssl) works only on binary files. For each input, convert to binary.
# the pubkey for above example:
echo 3036301006072a8648ce3d020106052b8104000a032200 > pubkey.txt
echo 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0 >> pubkey.txt
xxd -r -p <pubkey.txt | openssl pkey -pubin -inform der >pubkey.pem
# TX_IN[0], double sha256 and signature:
echo afc7f91ceb9754ebb644d058334817babf8414d1ce75fd0683ad172e950348c9 > tx_hash.txt
echo 3045022100d675d9f98e5b1f01bdb05e5389acb453efa14ef399361099736376611d9bf88e02206b8fef37f2c2316d3629d6c43945afa23b0eb0ca2c1163e33b28066b01a4e241 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
# TX_IN[1], double sha256 and signature:
echo 11ded58d693d72a23b6191c20222b20ee4947bac63c34d1ccdac07461486a3b0 > tx_hash.txt
echo 304402200f921996446fbad78ecb6c95303ecd13145ca7e13e769b44742fa499325b347402202f8378d7d154f4f8d345525696f8e31df8a96c05aa58b2f53012e3550cc90ae7 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
# TX_IN[2], double sha256 and signature:
echo 12f904b9d0b37c368d24d132aaff2d2fe47fd9a5e3083a501e63410c6d4671ea > tx_hash.txt
echo 304402206b7c2d73ec787add99740dab78f7252ed49a1ba42ba358a667bf118b8740bb0c0220366ef47de6339c261946513c939a301ecf940a294036ed72a5fd893c5cafeed8 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
# TX_IN[3], double sha256 and signature:
echo 183b7652c2785d57483c5f70575e027f513743aad01100828d9eb4aeb48ea4ed > tx_hash.txt
echo 304402205b595472aa821d96dbfb6e531a663571a9db14ddfcf8ac0b4330b6264955c15f02203fdf004b19996654490f00fa9bdfc175265cf95ba6dc86943b4b7c50eaf23616 > tx_sig.txt
xxd -r -p <tx_hash.txt >tx_hash.hex
xxd -r -p <tx_sig.txt >tx_sig.hex
openssl pkeyutl <tx_hash.hex -verify -pubin -inkey pubkey.pem -sigfile tx_sig.hex
Весь код для этого примера создания/подписи находится здесь: https://github.com/pebwindkraft/trx_cl_suite Три команды для создания, подписи и декодирования trx:
./tcls_create.sh -v -f svn_4inputs.txt 820000 13GnHB51piDBf1avocPL7tSKLugK4F7U2B 33
./tcls_sign.sh -v -f tmp_c_urtx.txt -w Kxyz...your_priv_key_in_WIF_format...abc -p 03cc5debc62369bd861900b167bc6add5f1a6249bdab4146d5ce698879988dced0
./tcls_tx2txt.sh -vv -r 0100000004b0772e6ef46c2d3c60...b6f35f263d951d25dbe24b688ac00000000
Я нашел одну ошибку в этих сценариях оболочки, хотя я не уверен, что она единственная. После исправления он теперь генерирует те же sha256d неподписанных txs, что и другой инструмент, который я пробовал (до этого его не было).
Если вы посмотрите здесь , вы увидите, что scriptSig txin правильно устанавливается на scriptPubKey UTXO, который должен быть подписан, однако для scriptPubKeys, которые должны быть пустыми, скрипт ничего не испускает - он должен испускать пустой string, как это делает предложение else:
if [ $i -eq $j ] ; then
printf ${TX_IN_ScriptBytes_hex[$i]} >> $utxhex_tmp_fn
printf ${TX_IN_Sig_Script[$i]} >> $utxhex_tmp_fn
else
printf 00 >> $utxhex_tmp_fn
fi
Как я уже сказал, я не проверял остальные скрипты, но, надеюсь, это поможет вам на шаг приблизиться.
Йонас Шнелли
пебвиндкрафт
пебвиндкрафт