Страница 16 из 27
Для инструкции CHECKMULTISIG требуется указать n открытых ключей и параметр t как пороговое значение.
Чтобы эта инструкция выполнялась корректно, должно быть не менее t подписей от t из n этих открытых ключей, которые действительны. В этой инструкции мы можем определить компактным образом, что t из n указанных открытых ключей должны дать правильные подписи, чтобы транзакция была действительной.
Позже мы рассмотрим несколько примеров того, как используются мультиподписи.
Кстати, существует ошибка в реализации мультиподписи, и она была там все время.
Инструкция CHECKMULTISIG выталкивает значение дополнительных данных из стека и игнорирует его.
Это всего лишь причуда языка биткойнов, и с этим приходится иметь дело, добавляя в стек дополнительную фиктивную переменную.
Ошибка была в первоначальной реализации, и затраты на ее исправление намного выше, чем причиненный ущерб, как мы увидим позже.
На данный момент эта ошибка считается просто особенностью биткойна.
Чтобы выполнить скрипт на стековом языке программирования, все, что нам понадобится, это стек, в который мы можем вносить данные и из которого можем извлекать данные.
Нам не нужна никакая дополнительная память или переменные.
Это делает скрипт простым в вычислении.
В скрипте существует два типа инструкций: инструкции данных и коды операций или опкоды.
Когда в скрипте появляется инструкция данных, эти данные просто вставляются в верхнюю часть стека.
С другой стороны, опкоды выполняют некоторую функцию, часто беря данные, находящиеся вверху стека, как входные данные.
Теперь давайте посмотрим, как выполняется Bitcoin скрипт.
Здесь мы показываем состояние стека после каждой инструкции.
Первые две инструкции в этом скрипте – это инструкции данных – подпись и публичный ключ этой подписи.
Они были указаны в элементе scriptSig или входном скрипте.
Как мы уже сказали, когда мы видим инструкцию данных, мы просто вносим данные в стек.
Дальше идет скрипт scriptPubKey.
Здесь сначала у нас есть команда дублирования OP_DUP, поэтому мы просто вносим копию публичного ключа в верхнюю часть стека.
Следующей инструкцией является OP_HASH160, в которой говорится, что нужно вытолкнуть из стека верхнее значение, вычислить его криптографический хеш и внести результат в верхнюю часть стека.
Когда эта команда завершит выполнение, мы заменим публичный ключ на вершине стека его хешем.
Здесь речь идет о публичном ключе текущего владельца биткойнов.
Затем мы вносим в стек хэш публичного ключа, который был указан в предыдущей транзакции как получатель монет и который должен использоваться для создания подписи, чтобы потратить полученные монеты.
Таким образом, на данный момент в верхней части стека есть два значения.
Существует хэш публичного ключа, который был указан в выходном скрипте, и хэш публичного ключа, который используется при трате монет и который указан во входном скрипте.
На этом этапе мы запускаем команду EQUALVERIFY, которая проверит, что эти два значения в верхней части стека равны.
Если это не так, произойдет ошибка, и скрипт прекратит выполнение.
В нашем примере мы будем считать, что они равны, то есть получатель монет использовал правильный публичный ключ.
Эта инструкция потребляет те два элемента данных, которые находятся в верхней части стека.
И теперь стек содержит два элемента – подпись и публичный ключ, который использовался для этой подписи.
Мы уже проверили, что этот публичный ключ является публичным ключом, который требуется, и теперь мы должны проверить, действительна ли подпись.
Это отличный пример того, как язык скриптов Bitcoin построен с учетом криптографии.
Несмотря на то, что это довольно простой язык с точки зрения логики, в нем есть некоторые довольно сильные инструкции, такие как инструкция «OP_CHECKSIG».
Эта инструкция выталкивает эти два значения из стека и выполняет всю проверку подписи за один раз.
Но чего это подпись?
Какой был вход функции подписи?
Оказывается, есть только одна вещь, которую вы можете подписать в биткойн – это целая транзакция.
Таким образом, инструкция «CHECKSIG» выталкивает из стека два значения, открытый ключ и подпись, и проверяет, является ли эта подпись валидной для всей транзакции, используя этот публичный ключ.
Теперь мы выполнили каждую инструкцию в скрипте, и в стеке ничего не осталось.
Если ошибок не было, выход этого скрипта будет просто true, указывая, что транзакция действительна.
Теоретически, скрипт позволяет нам в каком-то смысле указать произвольные условия, которые должны быть выполнены для того, чтобы потратить монеты.
Но на сегодняшний день эта гибкость практически не используется.
Если мы посмотрим на скрипты, которые на самом деле были использованы в истории Биткойна, подавляющее большинство, 99,9 %, – это точно такой же скрипт pay-to-public-key-hash, который мы использовали в нашем примере.
Как мы видели, этот скрипт pay-to-public-key-hash просто указывает один публичный ключ, вернее его хэш, и требует подписи для этого публичного ключа, чтобы потратить монеты.
Однако существуют несколько других инструкций, которые действительно полезны.
Иногда используется специальный тип скрипта под названием «Pay-to-Script-Hash», который обрабатывает мультиподписи MULTISIG и который мы обсудим позже.
Вообще говоря, не существует большого разнообразия используемых скриптов.
Это связано с тем, что узлы биткойнов по умолчанию имеют белый список стандартных скриптов, и они отказываются принимать скрипты, отсутствующие в списке.
Это не означает, что эти другие скрипты нельзя использовать вообще; это просто усложняет их использование.
На самом деле это различие – это очень тонкая вещь, к которой мы вернемся, когда мы будем говорить об одноранговой сети Bitcoin.
Далее рассмотрим несколько видов стандартных скриптов.
Proof of burn доказательство сжигания – это скрипт, в котором биткойны никогда не могут быть потрачены.
Отправка монет в скрипт с доказательством сжигания устанавливает, что они уничтожены, так как нет никакой возможности для их расходования.
Одно из использований доказательства сжигания заключается в том, чтобы загрузить альтернативу биткойну, заставив людей уничтожить биткойн, чтобы получить монеты в новой системе.
Мы обсудим это более подробно позже.
Доказательство сжигания довольно просто реализовать: опкод OP_RETURN выбрасывает ошибку и маркирует транзакцию как недействительную.
Таким образом, любая новая транзакция, которая попытается использовать выход с OP_RETURN, будет недействительной и не будет учитываться в блокчейне.
Независимо от того, какие значения вы ставите перед OP_RETURN, эта инструкция будет выполнена и скрипт вернет false.
Так как выбрасывается ошибка, данные в скрипте, которые появляются после OP_RETURN, не будут обрабатываться.
Таким образом, это также возможность помещать произвольные данные в скрипт и, следовательно, в цепочку блоков.
Если по какой-то причине вы хотите написать свое имя или хотите установить отметку времени и доказать, что знаете определенные данные в определенное время, тем самым, например, внести доказательство авторских прав на документ, вы можете создать транзакцию биткойнов с очень малой суммой и инструкцией OP_RETURN.
Вы можете уничтожить очень маленькую сумму валюты, но вы можете написать все, что захотите, в цепочку блоков, которая будет храниться всегда.
Теперь о скрипте Pay-to-script-hash.