Глоссарий / Протокол и обновления
Аннекс Taproot
- Что такое аннекс Taproot?
- Аннекс Taproot представляет собой зарезервированный элемент свидетеля (witness), помеченный байтом 0x50, который правила консенсуса фиксируют в подписи, но в остальном игнорируют при валидации.
Определено в BIP-341.
BIP-341 зарезервировал это поле для будущих мягких форков и не придал ему никакого значения, поэтому сегодня ни один узел не читает его содержимое. Функция IsWitnessStandard в Bitcoin Core отклоняет трату Taproot, несущую аннекс с меткой 0x50, поэтому транзакция не будет ретранслирована, а BIP-341 предупреждает, что это может привести к безвозвратной потере средств. У кошельков нет причин прикреплять аннекс, поэтому ничто из того, что вы делаете при покупке или хранении биткоина, от него не зависит.
Как это работает
Аннекс Taproot определяется по позиции, а не по именованному полю в формате транзакции. Если вход Taproot несет не менее двух элементов свидетеля и первый байт последнего элемента равен 0x50, этот элемент является аннексом и удаляется из стека свидетеля до того, как будет рассмотрено что-либо еще. Только после этого узел решает, с чем имеет дело: один оставшийся элемент означает трату по ключевому пути, два или более означают трату по пути скрипта.
BIP-341 выбрал 0x50 намеренно. Версии листа идут парами четных и нечетных значений, которые не должны быть спутаны с первым байтом свидетеля P2WPKH или P2WSH, а 0x50 был непарным остатком, поэтому он занимал наименьшее число будущих версий скрипта. Правило работает и в обратную сторону: версия листа не может быть 0x50, потому что блок управления, начинающийся с этого байта, был бы неотличим от аннекса.
Аннекс не влияет на валидацию. BIP-341 говорит, что поле "is always covered by the signature and contributes to transaction weight, but is otherwise ignored during taproot validation" (всегда покрывается подписью и учитывается в весе транзакции, но в остальном игнорируется при валидации Taproot). Каждое сообщение подписи Taproot несет однобайтовое поле spend_type, равное (ext_flag * 2) + annex_present, а когда аннекс присутствует, сообщение также несет sha_annex, 32-байтовый SHA256 от префикса длины аннекса и самого аннекса, включая байт 0x50. Отсутствие подписывается так же твердо, как присутствие, поэтому никто не может прикрепить аннекс к вашей транзакции в мемпуле или удалить его. BIP-341 определяет размер сообщения подписи в 174 байта, минус 49 для ANYONECANPAY, минус 32 для NONE, плюс 32 при наличии аннекса, с верхним пределом 206.
Где это встречается
В обычном использовании аннекс Taproot не встречается, и это и есть работающий замысел. Политика ретрансляции Bitcoin Core в src/policy/policy.cpp проверяет каждый вход версии свидетеля 1 с программой длиной 32 байта и возвращает false, когда свидетель содержит два или более элементов и последний начинается с константы ANNEX_TAG, определенной как 0x50 в src/script/script.h. Комментарий рядом с этой проверкой исчерпывает всю политику: "Annexes are nonstandard as long as no semantics are defined for them". Транзакция, несущая аннекс, действительна по консенсусу и не может быть доставлена на практике: узел с настройками по умолчанию отбрасывает ее, а не передает дальше.
По-настоящему аннекс появляется в одном месте: в каждой подписи Taproot, которую вы когда-либо делали, чей spend_type несет нулевой бит, говорящий, что аннекса здесь нет. Именно это обязательство позволило бы использовать будущий мягкий форк: BIP-341 называет его предполагаемой задачей помечать стоимость валидации дорогих новых опкодов без того, чтобы узел получал выход, который тратится.
Аннекс Taproot vs OP_RETURN
OP_RETURN представляет собой отведенный в биткоине слот для публикации байтов, которые никто не потратит, а аннекс Taproot вовсе не является слотом для публикации. Оба описываются как место для данных, которые консенсус игнорирует, и ведут они себя противоположным образом. Данные OP_RETURN живут в выходе, являются частью транзакции, которую валидирует каждый узел, и объявляют одно согласованное значение: здесь нечего тратить. Байты аннекса живут в свидетеле, удаляются до чтения стека и несут предупреждение самой спецификации: "users SHOULD NOT include annex in transactions, or it may lead to PERMANENT FUND LOSS".
Это предупреждение не украшение. Мягкий форк может только добавлять правила, поэтому байты, игнорируемые сегодня, могут быть отклонены завтра, а ваша подпись покрывает аннекс, поэтому вы не можете удалить его из уже подписанной транзакции. Тот, кто подписывает траты заранее на годы вперед, как это делает хранилище или канал Lightning, зафиксировал бы поле, значение которого еще никто не написал.