Скрипты биткоина. Описание


Скрипты биткоина. Выход каждой транзакции не просто указывает публичный ключ — он указывает и скрипт. Что такое скрипт и зачем он нужен? В этом разделе мы узнаем кое-что о сценарном языке биткоина и выясним, почему вместо простого публичного ключа нужно использовать именно скрипт.

Наиболее типичный вид транзакции биткоина — это высвобождение выхода предыдущей транзакции по корректному ключу. В этом случае мы хотим, чтобы на выходе говорилось - «это можно высвободить по подписи владельца такого-то адреса». Вспомним, что адрес — это хэш публичного ключа. Таким образом, простое указание адреса не покажет нам сам ключ, и не позволит нам проверить подпись. Вместо этого на выходе должно говориться:

«это можно высвободить по публичному ключу, хэш которого ведёт на такой-то адрес, с подписью владельца этого ключа». И, как мы увидим, для биткоина это самый типичный сценарий.

Рис. 3.4. Пример скрипта Pay-to-PubkeyHash, наиболее типичного скрипта выхода для биткоина

Но что происходит со скриптом? Кто им управляет, и как именно эта последовательность команд обеспечивает выполнение вышеуказанного требования? Секрет в том, что входы также содержат не подписи, а скрипты. Для валидации того, что транзакция высвобождает выход своей предшественницы правильно, мы совмещаем скрипт входа новой транзакции и скрипт выхода предыдущей. Мы их просто сцепляем, и, чтобы коины прошли, итоговый скрипт должен успешно работать.

Эти два скрипта называются scriptPubKey и scriptSig, поскольку в простейшем случае скрипт выхода просто указывает публичный ключ или адрес с его хэшем, а скрипт входа — подпись с этим ключом. Комбинированный скрипт продемонстрирован на рисунке 3.5.

Рис. 3.5. Для проверки корректности высвобождения выхода транзакцией, совмещаются транзакции входа и выхода

Здесь мы видим сцеплённые scriptPubKey и scriptSig. Отметим, что в <pubKeyHash?> имеется «?» - он используется для обозначения того, что потом будет осуществлена проверка соответствия хэшу ключа, указанного в скрипте высвобождения Сценарный язык биткоина. Сценарный язык был разработан специально для биткоина и называется просто "скриптом", или "сценарным языком биткоина".

У него много общего с языком Forth - старым, простым стековым языком программирования. Но для понимания скрипта биткоина необязательно владеть Forth. Целью создания было создать нечто простое и компактное, однако поддерживающее криптографические операции. Например, в нём есть специальные инструкции для вычисления хэш-функций, а также вычисления и подтверждения подписей.

Сценарный язык - стековый. Это значит, что любая инструкция исполняется строго однажды и линейным образом. В частности, в языке нет никаких петель, так что количество инструкций - это верхняя граница того, как долго он будет работать и сколько памяти потребует. Язык не соответствует требованию Тьюринга, и таким образом, не может вычислять произвольно сложные функции. Это сделано намеренно - скрипты исполняют майнеры, а подаются они случайными участниками сети. Нам не нужно давать им возможность выдать скрипт с бесконечной петлёй. При исполнении биткоин-скрипта может быть только два возможных исхода - либо он исполняется успешно и без ошибок, и тогда транзакция валидна, либо с ошибками - и тогда транзакция будет недействительна и не принимается в блокчейн.

Сценарный язык биткоина очень компактен - в нём есть место всего для 256 инструкций, так как каждая представлена лишь одним байтом. Из этих 256, 15 уже отключены, а 75 - зарезервированы. Коды последних пока не имеют заданного значения, но могут использоваться для инструкций, которые будут введены когда-нибудь потом. Многие из базовых инструкций встречаются в любом языке программирования - базовая арифметика и базовая логика типа if и then, выдача ошибок, невыдача ошибок и досрочное возвращение.

Наконец, там есть крипто-инструкции, среди которых хэш-функции, инструкции для подтверждения подписи, а также особая и важная инструкция CHECKMULTISIG, которая позволяет проверять несколько подписей одной командой. На рисунке 3.5 указаны некоторые из самых распространённых инструкций в сценарном языке биткоина.

CHECKMULTISIG требует указать n публичных ключей, а также пороговый параметр t. Чтобы эта инструкция исполнялась правильно, должно быть не менее t подписей от t из n валидных публичных ключей. Мы продемонстрируем примеры того, для чего нужны несколько подписей в следующем разделе, но уже сейчас должно быть понятно, что это весьма мощная базовая возможность. Можно коротко и компактно сказать, что для валидации транзакции необходимы подписи t из n по публичному ключу.

В имплементации мультисигнатурности, однако, есть исходный баг - она выдаёт дополнительную ценность данных из стека и игнорирует её. Это просто фишка биткоин-языка, и с ней нужно считаться, вводя в стек дополнительную переменную-пустышку. Баг был в исходном коде, и сейчас стоимость его исправления превышает то, какой ущерб он наносит. Таким образом сейчас его принято считать не багом, а фичей, которая никуда не денется.

Рис. 3.5. Список типичных инструкций скрипта и их функции

Выполнение скрипта. Для исполнения сценария в стековом языке всё, что нужно - это стек, куда и откуда можно соответственно вводить и получать данные. Нам не нужны дополнительные переменные или память - это как раз то, что делает его таким простым. Есть два типа инструкций: инструкции данных и операционные коды (опкоды). Когда в скрипте появляется инструкция данных, данные просто выводятся наверх стека. Опкоды же исполняют определённую функцию, обычно принятия данных входа сверху стека.

Теперь посмотрим, как исполняется скрипт биткоина из рисунка 3.5. На рис. 3.6 показано состояние стека после каждой инструкции. Первые две - это инструкции данных, а именно подпись и публичный ключ, который используется для генерирования подписи. Они указываются получателем в компоненте scriptSig или скрипте входа. Как уже говорилось, инструкция данных выводится наверх стека. Оставшаяся часть скрипта - это то, что указывается отправителем, т.е. компонент scriptPubKey.

Сначала нужно дублировать инструкцию, OP_DUB, поэтому мы выводим копию ключа наверх стека. Следующая инструкция OP_HASH160, которая выводит верхнее значение, вычисляет его криптографический хэш, а затем выводит результат наверх стека. Когда инструкция выполняется, ключ наверху стека будет заменён на свой хэш.

Рисунок 3.6. Исполнение биткоин-скрипта. Внизу указывается инструкция для скрипта. Инструкции данных помечаются угловыми скобками, а опкоды начинаются с OP_. Наверху показан стек сразу после исполнения инструкции. Затем нужно ещё раз переместить данные на стек. Вспомним, что эти данные указывались отправителем коинов, и находятся, таким образом, в хэше публичного ключа отправителя, использованного им для генерации подписи

В этот момент наверху стека находятся два значения - хэш публичного ключа от отправителя, и хэш публичного ключа, который использовался получателем для получения коинов.

В этот момент запускается команда EQUALVERIFY, которая проверяет равенство значений наверху стека. Если они не равны, выдаётся ошибка и сценарий перестаёт исполняться. Но в нашем случае они равны, то есть, у получателя правильный публичный ключ. Инструкция поглотит эти два пункта данных, и в стеке теперь два значения - подпись и публичный ключ для неё. Мы уже проверили, что этот ключ - правильный, и теперь должны проверить валидность подписи. Это отличное доказательство того, что язык биткоина создавался с учётом криптографии. Хотя он весьма прост в смысле логики, в нём есть довольно мощные инструкции вроде OP_CHECKSIG. Она выбрасывает эти два значения из стека и проводит верификацию всей подписи за одно действие.

Но что же обозначает эта подпись? Что является входом функции подписи? Оказывается, что подписать в мире биткоина можно только одну вещь - всю транзакцию. Поэтому инструкция CHECKSIG выкидывает два значения - ключ и подпись - из стека, и подтверждает, что это валидная подпись для всей транзакции по данному ключу. Теперь в сценарии исполнена каждая инструкция, и в стеке не осталось ничего. Если не было никаких ошибок, выход скрипта будет true, что означает валидность всей транзакции.

Теоретически скрипт позволяет в опрелённом смысле указать произвольные условия, которые должны выполняться для расхода денег. Но в наше время этот функционал едва ли частно используется. Ознакомившись со скриптами, которые реально использовались в прошлом, в большинстве случаев - 99,9% - скрипт будет один и тот же, а именно тот, что мы показали в нашем примере. Как мы увидели, он просто указывает один публичный ключ и требует подписи к нему для расхода коинов.

Есть и другие инструкции, имеющие некоторую пользу. Иногда используется MULTISIG, так как включает особый скрипт под названием Pay-to-Script-Hash, который мы вскоре обсудим. Но помимо этого, есть и другие случаи, в которых используются скрипты - это происходит потому, что узлы биткоина по умолчанию имеют белый список стандартных скриптов и отказыаются принимать те скрипты, которые в них отсутствуют. Это не означает, что такие скрипты вовсе не могут использоваться, это просто усложняет их применение. Такое разделение - достаточно тонкий момент, и мы к нему вскоре вернёмся, когда будем говорить о р2р-сети биткоина.

Сжигание. Proof-of-burn - это скрипт, после использования которого высвобождение средств невозможно. Отправление коинов на скрипт сжигания означает, что они уничтожены, и потратить их нет никакой возможности. Одно из возможных применений этого скрипта - это создание альтернативы биткоину, которая требует уничтожения биткоина для получения коинов в новой системе. Подробней это будет обсуждаться в лекции 10. Само сжигание работает очень просто: опкод OP_RETURN возвращает ошибку. Неважно, какие суммы были введены перед опкодом, эта инструкция всё равно будет исполнена, в каковом случае скрипт вернёт значение false.

Поскольку выдана ошибка, данные скрипта, идущие после OP_RETURN не будут обрабатываться. Это возможность вводить в скрипт произвольные данные, которые таким образом попадут в блокчейн. Если по какой-то причине вы желаете написать своё имя или пометить время и доказать, что в определённый момент вы что-то знали, вы можете создать очень маленькую транзакцию, уничтожить оченьм малое количество денег, но написать, что хотите, в блокчейне, и это останется в нём навеки.

Pay-to-script-hash. Одно из последствий того, как работает скрипт, это то, что отправитель должен чётко указать сам скрипт - но зачастую это довольно странный способ. Например, вы что-то покупаете в интернете и намерены сделать заказ. Вы говорите: "Ладно, я сейчас буду платить. Скажите, куда отправить деньги". А теперь предположим, что компания, где вы делаете покупку, использует адреса MULTISIG. Поскольку тот, кто отправляет деньги, должен уточнить, продавец скажет: "О, ну мы тут чем-то странным заняты. Мы пользуемся MULTISIG. Отправьте деньги на какой-то сложный скрипт".

Вы им ответите: "Не знаю я, как это делается. Это слишком сложно. Я, как покупатель, хочу, чтобы всё было просто". Для решения этой проблемы в биткоине есть довольно умный хак: вместо того, чтобы заставлять отправителя указывать весь скрипт, ему даётся возможность указать только хэш этого скрипта, который понадобится для высвобождения коинов. Поэтому ему нужно будет указать очень простой скрипт, который хэшируется наверху стека, и проверить его совпадение с требуемым скриптом высвобождения.

Получатель должен будет указать значение данных. После этого происходит специальный второй шаг валидации - верхние данные сверху стека реинтерпретируются как инструкции и затем исполняются во второй раз в качестве скрипта. Как мы видим, здесь всё происходит в два этапа: сначала обычный скрипт проверяет правильность хэша скрипта высвобождения, а затем скрипт высвобождения десериализируется и выполняется как основной. Именно в этот момент и происходит настоящая сверка подпией.

Это называется pay-to-script-hash (обычно сокращается до P2SH). Это альтернатива обычному методу работы, при котором оплата происходит по публичному ключу. Получение поддержки для P2SH было достаточно сложным, поскольку его не было в изначальной проектной спецификации биткоина - но он решает пару важных проблем. Во-первых, это облегчает жизнь отправителю, а получатель должен просто указать хэш, на который отправляют деньги. В нашем примере Алисе не надо беспокоиться, если Боб использует MULTISIG.

Ей достаточно послать ему P2SH-адрес, а дальше уже Боб должен указать желаемый скрипт, по которому он будет получать свои коины. P2SH также увеличивает производительность - майнерам приходится отслеживать набор выходных скриптов, по которым ещё не проходило высвобождение, а на P2SH-выходах выходные скрипты имеют малые размеры, так как указывают лишь хэш. Вся сложность переводится на скрипты вводов.

 



Дата добавления: 2023-05-18; просмотров: 263;


Поиск по сайту:

Воспользовавшись поиском можно найти нужную информацию на сайте.

Поделитесь с друзьями:

Считаете данную информацию полезной, тогда расскажите друзьям в соц. сетях.
Poznayka.org - Познайка.Орг - 2016-2024 год. Материал предоставляется для ознакомительных и учебных целей.
Генерация страницы за: 0.012 сек.