Опубликован: 01.02.2018 | Уровень: для всех | Доступ: платный
Лекция 3:

Транзакции Биткоина

< Лекция 2 || Лекция 3: 123456 || Лекция 4 >

Скрипты Биткоина

Каждый вывод в транзакции не только описывает простой открытый ключ, но и объявляет скрипт. Для чего этот скрипт используется? Рассмотрим, что из себя представляет скриптовый язык Биткоина, и почему он используется вместо того, чтобы обозначить открытый ключ.

Скрипт в качестве адреса выхода

Рис. 3.8. Скрипт в качестве адреса выхода

В качестве примера возьмем наиболее распространенный скрипт Биткоина, который исполняет предыдущую транзакцию после ее подписания корректным открытым ключом.

У скрипта будут 4 инструкции, и что же происходит со скриптом? Кто его запускает? Как скрипт понимает, кто имеет право на расходование монет? Секрет в том, что адрес ввода - это тоже скрипт. Это такой вид скрипта, который соединяется со скриптом вывода, они сцеплены вместе и образуют единый скрипт, который должен успешно запуститься, чтобы получить Биткоины.

«Адреса» ввода – это тоже скрипты

Рис. 3.9. «Адреса» ввода – это тоже скрипты

Как правило, эти два скрипта называются scriptSig и scriptPublicKey, потому что, в самом простом случае, скрипт вывода объявляет открытый ключ, а скрипт ввода создает подпись с тем же самым открытым ключом.

Когда транзакция проходит верификацию, два скрипта соединяют вместе и запускают, и если получившийся скрипт запускается без ошибок, то транзакция признается действительной.

Скриптовый язык Биткоина («Скрипт»)

Рис. 3.10. Скриптовый язык Биткоина («Скрипт»)

У языка, используемого в Биткойн нет точного названия. Его называют просто "Скрипт" или "скриптовый язык Биткоина", так как он был создан специально для него. Наибольшее влияние на него оказал язык Forth, это старый и простой язык программирования, основанный на работе стеков, однако совсем не обязательно знать Forth, чтобы понимать скриптовый язык Биткоина.

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

Также это стековый язык программирования. На следующем рисунке будет показано, почему он так называется. В языке существует множество ограничений, которые очень важно помнить. В частности, у скриптового языка Биткоина нет циклов. Каждая инструкция выполняется только один раз линейным путем. Если посмотреть на скрипт, который состоит из некоторого числа инструкций, то можно точно сказать, сколько времени потребуется для его запуска и сколько памяти он займет.

Как следствие, по Тьюрингу этот язык считается неполным.

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

И так как это неполный язык по Тьюрингу, он также не подвержен проблеме остановкиМожно посмотреть на любой скрипт языка Биткоина и убедиться, что он уничтожится после конечного числа шагов, которые являются количеством инструкций, содержащихся в скрипте. Рассмотрим конкретный скрипт Биткоина и то, как именно он выполняется.

Пример исполнения скрипта Биткоина

Рис. 3.11. Пример исполнения скрипта Биткоина

На рис. 3.11 изображен скрипт, в котором отправитель просто задает открытый ключ получателя, а получатель монет, чтобы их получить, должен объявить подпись, используя тот же самый открытый ключ.

Итак, первые две инструкции в скрипте ввода – это просто инструкции для ввода данных в стек. В стек записывается подпись транзакции и открытый ключ получателя, который может ее проверить.

Исполнение инструкций для данных в стековых языках проводится очень легко. Если есть данные, то они последовательно заносятся в стек.

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

Теперь, когда два значения внесены в стек, запускается вторая часть скрипта. Эта часть называется scriptPubKey.

Дублирущая инструкция OP_DUP гласит: "Возьми значение из верхушки стека, выкинь его, а затем впиши две его копии обратно в стек." Таким образом открытый ключ получателя продублирован.

Следующая инструкция HASH160 говорит: "Возьми верхнее значение в стеке и вычисли из него криптографический хеш."

Верхнее значение из открытого ключа превратится в хеш этого ключа.

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

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

Запустим верифицированную обеими сторонами команду OP_EQUALVERIFY, в которой просто объявится, что те два значения, которые находятся на верху стека, равны.

Если же это не так, то будет выведена ошибка, и скрипт прекратит выполняться. Предположим, что значения равны, то есть получатель монет использовал корректный открытый ключ.

Пример запуска скрипта Биткоин

Рис. 3.12. Пример запуска скрипта Биткоин

Инструкция сравнения поглотит те два элемента данных, которые находились на верху стека. В стеке остались еще два элемента – подпись и открытый ключ.

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

Рассмотрим, что послужило вводом для функции подписывания?

Единственное, что можно подписать в Биткоине - это весь процесс транзакции. Инструкция checkSig подтверждает, что вся транзакция была успешно подписана.

Всего за один заход инструкция checkSig вынесет из стека два оставшихся элемента, и проверит действительность подписи. После выполнения всех инструкций в скрипте, в стеке больше нет данных, и не появилось ни одной ошибки, выводом скрипта будет простое "Да". Итак, у любого скрипта Биткоина существует два исхода: он может выполниться без ошибок, в таком случае транзакция будет действительной. Если при выполнении скрипта обнаружится ошибка, вся транзакция будет признана недействительной, и она не будет включена в блокчейн.

Инструкции скрипта Биткоина

Всего 256 кодов операций (15 не работают, 75 – в резерве):

  • Арифметические
  • Условные (If/then)
  • Условные (If/then)
  • Крипта!
    • Хеши
    • Проверка подписи
    • Проверка множественных подписей

Рассмотрим скриптовый язык Биткоина. Он очень маленький, в нем всего 256 инструкций, потому что каждой из них выделяется по одному байту памяти. Из них 15 инструкций нерабочие, и воспользоваться ими никак нельзя. Еще 75 находятся в резерве - в них пока нет особой необходимости. Но в будущем их могут сделать основными. Из основных же инструкций присутствуют такие, которые встречаются в любом языке программирования - основы арифметики, логики, конструкции "If-then". Вбрасывание и не-вбрасывание ошибок, ранние выходы.

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

OP_CHECKMULTISIG

  • Встроенная поддержка совместных подписей
  • Объявление n открытых ключей
  • Объявление числа T
  • Верификация требует T подписей

Предупреждение о баге: дополнительная единица данных выносится из стека и игнорируется

При помощи MULTISIG объявляется N открытых ключей и параметр T (т.н. "порог"). Чтобы эта инструкция сработала нормально, необходимо, чтобы было T подписей и T из N действительных открытых ключей.

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

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

Скрипты Биткоина на практике ( по состоянию на 2014 год)

  • Большинство узлов содержит стандартные скрипты
  • 99,9% скриптов проверки подписей – простые
  • примерно 0,01% скриптов проверки подписей – MULTISIG
  • примерно 0,01% - оплаты по хешу скрипта
  • остальное – ошибки и сжигающие протоколы

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

Есть еще несколько вещей, которые могут пригодиться. Кое-где используется MULTISIG, и еще существует особый тип скрипта, который называется Pay-to-Script-Hash, который будет рассмотрен далее. Других способов проявить креативность в использовании скриптов на текущий момент нет. Причина этого в том, что узлы Биткоина имеют стандартизированный список скриптов, и они отвергают те скрипты, которые воспринимаются ими как нестандартные. Это не значит, что эти скрипты совсем никак нельзя использовать, их просто сложнее применить и этот вопрос будет рассмотрен далее в контексте пиринговой сети Биткоина.

Существуют скрипты, которые называются "proof-of-burn" ("доказательство сжигания"). Этот скрипт называется так потому, что его нельзя исполнить. С помощью скрипта "доказательство сжигания" можно доказать, что монеты были уничтожены, и потратить их теперь невозможно. Такой скрипт очень просто внедрить. Нужно использовать код OP_RETURN, который вбросит ошибку, если он, конечно, вообще сработает, и тогда программа вылетит. Данные, идущие после OP_RETURN, невозможно просмотреть, так что это дает возможность вписать в скрипте какие-нибудь свои данные.

Существует два случая, для которых он используется.

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

О втором случае использования "доказательства сжигания" будет рассказано в лекции про альтернативные валюты.

Должны ли покупатели описывать скрипты?

- Я готов оплатить заказ!

- Хорошо! Мы используем MULTISIG, поэтому мы хотим, что вы добавили скрипт, подтверждающий оплату от 2 из 3 бухгалтеров. Не ошибитесь в деталях. Спасибо за использование Big Box!

= Отправитель монет должен точно описать свой скрипт.

Например, покупатель хочет заказать что-то в интернет-магазине. Он оформил заказ, готов его оплатить и спрашивает у продавца адрес, куда ему следует направить монеты. Продавец в ответ говорит: " Мы используем MULTISIG, поэтому мы хотим, что вы добавили скрипт, подтверждающий оплату от 2 из 3 бухгалтеров. Не ошибитесь в деталях. "

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

Использование хеша скрипта

Рис. 3.13. Использование хеша скрипта

На рис. 3.13 отправитель описывает очень простой скрипт, который хеширует верхнее значение в стеке и проверяет, соответствует ли он требуемому скрипту оплаты.

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

Как только это случится, начнется второй этап валидации.

Верхнее значение данных из стека будет переинтерпретировано в качестве инструкции, и будет исполнено во второй раз в виде скрипта. То есть будет проведено два этапа: во-первых - это традиционный скрипт, который проверил правильность хеша скрипта оплаты, а во-вторых, скрипт оплаты будет преобразован и запущен в виде скрипта. Именно здесь пройдет проверка актуальности подписи.

Это и называется оплата по хэшу скрипта (P2SH) в Биткоине , который выступает как альтернатива обычному режиму оплаты через открытый ключ. Механизм оплаты по хешу достаточно сложен и не был указан в оригинальной спецификации. Он был добавлен в биткоин позднее.

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

< Лекция 2 || Лекция 3: 123456 || Лекция 4 >
Александр Шабанов
Александр Шабанов
Россия, Москва, МГОУ, 2007
Максим Кучинский
Максим Кучинский
Россия