Чтобы сценарий погашения удовлетворял условиям сценария, что он должен оставить в стеке после выполнения?
Я смотрел презентацию Андреаса Антонопулоса о Advanced Bitcoin Scripting.
Из примеров Андреаса видно, что для того, чтобы сценарий погашения удовлетворял условиям сценария, он должен оставить в стеке значение ИСТИНА (и ничего больше) после его выполнения. Об этом тоже спрашивали здесь .
Поэтому существует суффикс VERIFY, так что некоторые коды операций (например, EQUAL, CHECKSIG, CHECKMULTISIG) имеют конкурирующие коды операций (например, EQUALVERIFY, CHECKSIGVERIFY, CHECKMULTISIGVERIFY). Вместо того, чтобы оставлять TRUE в стеке, эти коды операций VERIFY «продолжат выполнение сценария, если результат условного оператора - TRUE», но «не вернет это значение TRUE обратно в стек, он просто продолжит выполнение». Эти коды операций VERIFY могут использоваться для обеспечения того, чтобы при выполнении сценария погашения в стеке оставалось значение TRUE (и ничего больше), а не TRUE TRUE TRUE.
Однако на этом заседании клуба по обзору PR в Bitcoin Core Питер Уилле заявил (перефразируя):
Для CLEANSTACK у вас должен быть стек с единственным элементом, который должен быть ненулевым. Без CLEANSTACK непустой стек с несколькими элементами в порядке, пока верхний элемент не равен нулю.
У меня два вопроса:
Предположительно TRUE эквивалентно 1, а FALSE эквивалентно 0?
Любые коды операций, которые оцениваются как FALSE, приведут к немедленному отказу и прекращению выполнения? Таким образом, с не-CLEANSTACK вы никогда не увидите результирующий стек из TRUE FALSE TRUE, поскольку FALSE приведет к немедленному отказу, и вы не сможете оценить окончательный TRUE. Однако вы можете увидеть стек, скажем, TRUE 3 TRUE 5, и это пройдет без CLEANSTACK. (Это не сработает с CLEANSTACK, поскольку CLEANSTACK должен иметь единственный элемент в результирующем стеке).
Ответы
Спасибо harding за ответ на этот вопрос в IRC и sanket1729 за правки.
Предположительно TRUE эквивалентно 1, а FALSE эквивалентно 0?
ИСТИНА - любое ненулевое значение. Это часто используется в сценариях, включающих бывшие коды операций OP_NOPx, которые не выталкивают свои значения из стека после проверки, например, сценарий, который может быть потрачен майнером после определенной высоты, может использовать <locktime> OP_CLTV
:; в случае сбоя CLTV транзакция недействительна; если он проходит, то ненулевое значение, оставшееся в стеке, позволяет сценарию пройти.
Любые коды операций, которые оцениваются как FALSE, приведут к немедленному отказу и прекращению выполнения? Таким образом, с не-CLEANSTACK вы никогда не увидите результирующий стек из TRUE FALSE TRUE, поскольку FALSE приведет к немедленному отказу, и вы не сможете оценить окончательный TRUE. Однако вы можете увидеть стек, скажем, TRUE 3 TRUE 5, и это пройдет без CLEANSTACK. (Это не сработает с CLEANSTACK, поскольку CLEANSTACK должен иметь единственный элемент в результирующем стеке).
Все, что имеет значение без CLEANSTACK, - это верхнее значение в стеке в конце выполнения. Все, что находится ниже по стеку, не имеет значения.
CLEANSTACK - это правило стандартности для P2SH, но это правило консенсуса для Segwit v0 ( спецификация BIP141 ) и Tapscript, SegWit v1 ( спецификация BIP342 , правило 4, ii)
Слово «провал» здесь неоднозначно. Существуют разные способы выхода из строя разных кодов операций. Например, если OP_CHECKSIG не работает, он просто помещает 0 в стек. Но если OP_CHECKSIGVERIFY терпит неудачу, весь скрипт терпит неудачу. Вы можете поместить TRUE FALSE FALSE в стек, используя только OP_0 OP_0 OP_1.
Некоторые из кодов операций VERIFY, например EQUALVERIFY, CHECKSIGVERIFY, CHECKMULTISIGVERIFY, завершаются немедленно при сбое, но их эквиваленты без VERIFY - нет.
Все, что имеет значение, - это состояние стека в конце оценки скрипта. Например, вы можете сделать OP_CHECKSIG, а затем OP_IF OP_PUSHNUM1 OP_ELSE OP_PUSHNUM2 OP_ENDIF, например, если подпись прошла успешно, возьмите одну ветвь; если это не удается, возьмите другую ветку (хотя это не считается лучшей практикой и обычно не следует делать).
CLEANSTACK - это попытка предотвратить податливость, заставляя людей помещать кучу мусора в ваши данные scriptSig или свидетеля. Потому что вы можете просто поместить в стек кучу данных, которые никогда не будут использоваться и не помешают правильному выполнению скрипта. (Pre-segwit, это повлияло на гибкость txid и было применено в качестве правила политики стандартизации; с segwit это больше невозможно, поскольку это правило консенсуса)