Найти тему
КриптоБобр

Язык Script и скрипты Биткоина

Важнейшей частью любой Биткоин транзакции являются условия траты монет, которые описываются в скриптах Биткоина. Без их выполнения пользователь не может перевести средства с одного адреса на другой. В прошлый раз мы рассказали о ScriptSig и ScriptPubKey, которые представляют из себя ключ и замок для не потраченных выходов. Говоря другими словами, они задают программу, определяющую условия траты для конкретного выхода. ScriptPubKey - это замок. Он запирает не потраченный выход до тех пор, пока ему не будет предоставлен подходящей ключ в виде соответствующего скрипта ScriptSig. Сегодня мы поговорим о том, как работают эти скрипты, и о языке программирования, который используется для их написания - Script.

Язык Script

Для начала поговорим о языке, на котором пишутся скрипты Биткоина. Язык Bitcoin Script или просто Script был предложен Сатоши Накамото в релизе Bitcoin Core 0.1.

Этот язык обладает следующими свойствами:

  • Стековый. При считывании из скрипта команды и данные будут помещаться в стек. Стек можно сравнить со стопкой тарелок. Первой тарелкой из стопки вы возьмете ту, которую положили в стопку последней(Last-in-First-Out). А чтобы взять вторую тарелку из стопки, вы сначала снимете первую(то есть ту, которую положили последней), а потом возьмёте вторую тарелку. То же самое происходит и в Биткоине при выполнении скриптов: сначала выполняются команды, находящиеся на вершине стека.
  • Обрабатывается слева направо. Полный скрипт состоит из двух частей: ScriptPubKey, являющийся замком для выхода транзакции, и ScriptSig, являющийся ключом для ScriptPubKey и предоставляющийся в момент траты не потраченного выхода. Выполнение всего скрипта начинается слева направо, начиная со ScriptSig.
Схема 1. Пример полного скрипта, определяющий условия траты монет.
Схема 1. Пример полного скрипта, определяющий условия траты монет.
  • Не полный по Тьюрингу. То есть с его помощью нельзя реализовать любую функцию или программу. В частности, в языке Script отсутствует возможность использования циклов. Это свойство было заложено в язык специально, чтобы обеспечить защиту от использования большого количества вычислительных мощностей и Denial-of-Service (DoS) атак. В данном случае простота языка и ограниченность его функционала не делает его ущербным. Наоборот, это повышает безопасность, в том числе упрощая работу разработчикам.

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

Скрипты в Биткоине состоят из опкодов и данных(подпись, открытый ключ, хэш-значения и др.). Как мы уже упоминали полный скрипт состоит из двух частей: sctipSig и scriptPubkey. Когда пользователь хочет потратить свои монеты, ему нужно предоставить sctipSig во входе транзакции, который соответствует scriptPubkey не потраченного выхода предыдущей транзакции.

Рассмотрим самый простой пример скрипта, когда пользователю для траты монет в scripSig необходимо предоставить подпись и открытый ключ, с помощью которого можно проверить эту подпись. Такой скрипт соответствует типу адреса Pay-to-Public-Key-Hash(P2PKH). Полный скрипт, включая scriptPubkey показан на схеме 2.

Схема 2. Полный скрипт для траты монет с адреса типа Pay-to-Public-Key-Hash(P2PKH)
Схема 2. Полный скрипт для траты монет с адреса типа Pay-to-Public-Key-Hash(P2PKH)

Так как язык Script стековый и обрабатывается опкоды слева направо, то первым шагом мы поместим самый левый элемент скрипта наверх стека: подпись (r,s) (Схема 3).

Схема 3.
Схема 3.

Далее мы помещаем на вершину стека открытый ключ pubKey, а подпись опускается ниже внутри стека (Схема 4).

Схема 4.
Схема 4.

На следующем шаге мы берём опкод OP_DUP (Схема 5). Данный опкод действует следующим образом: он берёт верхний элемент стека, дублирует его и помещает дубликат вместе с оригиналом последовательно в стек. Таким образом, на двух верхних позициях стека будут находится одинаковые элементы. А подпись опустится ещё на одну позицию ниже.

Схема 5.
Схема 5.

Следующим мы используем опкод OP_HASH160 (Схема 6), который дважды хэширует верхний элемент стека. Сначала используется хэш-функция SHA256, а потом к результату применяется RIPEMD-160. Результатом действия данного опкода будет 160 битное хэш-значение, которое помещается на вершину стека.

Схема 6.
Схема 6.

Далее мы помешаем хэш-значение открытого ключа из нашего скрипта в стек (Схема 7).

Схема 7.
Схема 7.

Опкод OP_EQUALVERIFY берёт два верхних элемента стека и сравнивает их (Схема 8). Если два взятых элемента равны и результат сравнения 1(TRUE), то скрипт проверяется дальше. В противном случае результат выполнения всего скрипта признается неверным и монеты не смогут быть потраченными. Помимо OP_EQUALVERIFY, существует также аналогичный опкод OP_EQUAL, отличающийся лишь тем, что после проверки помещает на вершину стека результат сравнения: 1(TRUE) или 0(FALSE).

Схема 8.
Схема 8.

Последним выполняется опкод OP_CHECKSIG. Он берёт два верхних элемента из стека и производит проверку подписи. Если первый элемент - это публичный ключ, а второй - подпись, которую можно проверить с помощью данного публичного ключа, то результат проверки будет 1(TRUE) в противном случае 0(FALSE).

Схема 9.
Схема 9.

Результат проверки помещается на вершину стека. Если результат равен 1(TRUE), то пользователь может потратить монеты, соответствующие проверяемому не потраченному выходу.

Схема 10.
Схема 10.

Выполнение скрипта признается неверным, если:

  • Стек по итогу выполнения скрипта оказывается пуст
  • На вершине стека по итогу выполнения скрипта оказалось значение 0(False)
  • В стеке по итогу выполнения скрипта осталось больше одного элемента

Так как транзакция может включать несколько входов, то она признаётся валидной, если скрипты для всех входов были проверены и выполнились верно.

Мы рассмотрели один из самых простых Биткоин скриптов, для того, чтобы Вы поняли общий принцип работы языка Script и скриптов Биткоина. В следующих статьях мы расскажем о других скриптах, в частности, реализующих возможность применения мультиподписи и временных блокировок(HTLC скрипты).

С подпиской рекламы не будет

Подключите Дзен Про за 159 ₽ в месяц