Пошаговый пример для погашения необходимого выхода P2SH

Я следил за BIP16 при создании транзакции P2SH. Я хочу создать простой (одна подпись) P2SH. Я получаю сообщение об ошибке при попытке передать tx. Ошибка16: mandatory-script-verify-flag-failed (Signature must be zero for failed CHECK(MULTI)SIG operation)

Чтобы было ясно, я не пытаюсь использовать мультиподпись. То, что я делаю, лучше всего можно описать как P2SH-P2PK, хотя я не встречал этого термина. Это единственный пример, приведенный в BIP16, так что это должно работать.

Вот что я пробовал (тестнет):

private key: BB2AC60BC518C0E239D5AF9D8D051A6BDFD0D931268DCA70C59E5992 
public key: 039f53e45f8f18b8ed294378bda342eff69b2053debf27fbede7d2d6bd84be6235 
(compressed)

redeemScript: [{pubKeySize,pubKey}] [OP_CHECKSIG]
21039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235AC 

redeemScriptHash: RIPEMD160(SHA256(redeemScript))  
323D0E8A083E98010299109337850D05DD6157F7

p2shAddress: Base58Check(0xC4 + redeemScriptHash) (C4 for testnet)
2MwprvB9tUMtX4vK8zJK8K329fNu79CJgR7

Вышеупомянутый адрес имеет два UTOX в тестовой сети:

UTXO1: e434a13cac79dc3d26e7279bff05c0f071a2df03e2ba6ca13c88f0e82dca9998:0
UTXO2: 9b4943e7ab5f4512e42c94254eb6aab4c6823ce06d4ff816b7ce4fda155a2571:0

Теперь я хочу потратить оба UTXO и сохранить следующие результаты:

Out1: 2MwprvB9tUMtX4vK8zJK8K329fNu79CJgR7 34000000 Satoshis
Out2: 2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF 100000000 Satoshis   

Я создал tx следующим образом:

  1. Создавать неподписанные транзакции со всеми пустыми scriptSigs

  2. Для каждого ввода для подписи установите для его scriptSig значение redeemScript: 21039F53E45F8F18B8ED294378BDA342EFF69B2053DEBF27FBEDE7D2D6BD84BE6235AC, оставив остальные scriptSig пустыми.

  3. Сериализуйте новый tx и добавьте байты SIGHASHALL (0x01) в 4 байта с прямым порядком байтов.

  4. Удвойте Sha256 выше и подпишите полученное значение. Добавьте один байт 0x01 в подпись, чтобы указать SIGHASH_ALL. Пусть sigбудет полученное значение.

  5. Установите scriptSig как:

    [0x00] [{sigSize, sig}] [{pubKeySize, pubKey}] [OP_CHECKSIG]

Я предполагаю, что будет использоваться следующий scriptPubKey:

[OP_HASH160] [{scriptHashSize, scriptHash}] [OP_EQUAL]

Ниже приведены kзначения rи sдля подписи каждого входа:

Вход 1:

k = 98790447509501799195296257240616657470656053786701275200434341714298778299820  
r = 96398386359095408146340664941016369169423137684113382189227162443480418477689
s = 62903510511574365450545635776206168644738316078298063260649088246548574249129

Вход 2:

k = 109372172176680138721552873719725202562296645126925021083510279924852033069204  
r = 105162394984132461723584277789901247831150698039237112243693144757926439529504
s = 62903510511574365450545635776206168644738316078298063260649088246548574249129

После этого я получаю следующую ошибку в bitcoind для отправки tx:

error code: -26
error message:
16: mandatory-script-verify-flag-failed 
(Signature must be zero for failed CHECK(MULTI)SIG operation)

Что я делаю неправильно?

РЕДАКТИРОВАТЬ: благодаря ответу arubi я обнаружил две проблемы с вышеуказанными шагами. Во-первых, я ошибался, не redeemScriptкодируя данные стека. Второе, что я делал неправильно , это вставлял [0x00]. scriptSigПосле исправления шаг 5 должен быть:

  1. Установите redeemScriptкак[{pubKeySize, pubKey}] [OP_CHECKSIG]

  2. Установите scriptSigкак[{sigSize, sig}] [{redeemScriptSize, redeemScript}]

Ответы (1)

Проблема в том, что scriptsig содержит фактический redeemScript вместо сериализованного скрипта в качестве push-уведомления. Вторая ошибка, redeemscript содержит постороннее 0x00значение, которого быть не должно, так как это простой файл CHECKSIG.

Стоит отметить, что 0x00значение, оставленное в стеке, не делает транзакцию недействительной, скорее, оно не будет перехвачено локальной политикой перед ретрансляцией, поскольку оно не соответствует cleanstackправилу.
Если какой-то узел добудет tx с ведущим 0x00, будет считаться действительным?
Да, я думаю, что это будет правильно, поскольку тот, OP_CHECKSIGкоторый выполняется последним, поместит значение, которое оценивается как True ( 0x01в данном случае), на вершину стека. Стек будет таким: 0x01 0x00 Заставить весь скрипт оценить как True.