В данной статье мы постарались детально рассмотреть изменения протокола Bitcoin, которые произошли в результате softfork-обновления Segregated Witness. Мы затронули вопросы, связанные с transaction malleability, сохранением обратной совместимости, увеличением пропускной способности, новыми форматами сериализации транзакций, новыми вариантами скриптов, форматом адресов Bech32 и его преимуществами, понятиями веса, размера и виртуального размера. Более того, ниже приведена самая важная статистика по адаптации обновления и представлены ответы на часто задаваемые вопросы по теме данного обновления.

Перед тем как переходить к детальному описанию всех изменений данного обновления, предлагаем познакомиться с главной идеей Segregated Witness. Дословно Segregated Witness переводится с английского, как «отделенный свидетель». В контесте Bitcoin подразумевается, что данные доказательства владения монетами будут храниться отдельно от основных данных транзакции, как обозначено на схеме.
image
Если рассматривать обновление протокола целиком, то оно включает в себя множество других улучшений. SegWit позволяет увеличить пропускную способность сети, отделить данные доказательств владения монетами от остальных данных транзакции, исправить недостатки формата транзакций, связанные с возможностью модификации данных в подписанных транзакциях (transaction malleability), и при этом сохранить обратную совместимость с предыдущими версиями протокола. А наибольшая ценность данного обновления состоит в том, что оно позволяет реализовать множество очень важных off-chain решений поверх протокола Bitcoin.

Проблема transaction malleability и ее решение


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

Очевидно, что вышеописанная ситуация может случиться только с транзакциями, которые еще не получили подтверждения. Без ее решения невозможно добиться надежной работы off-chain протоколов, которые предусматривают построение цепочек из неподтвержденных транзакций. Поскольку при составлении транзакции подписываются не все данные (например, нельзя подписать scriptSig), существует возможность проведения нескольких видов атак:

  1. Изменение формата подписи. В протоколе Bitcoin формат подписи утвержден не строго и зависит от реализации библиотеки OpenSSL, в которой для подписи тоже не определен строгий формат. Третья сторона может изменить перехваченную транзакцию, что повлечет за собой изменение хеш-значения.
  2. Воздействие непосредственно на scriptSig. Как было отмечено ранее, scriptSig содержит набор операций для проверки доказательств, что владельцем монет является определенный пользователь. Но кроме указанных операций, в него можно добавить и другие. Несколько безобидных, ни на что не влияющих операций приведут к изменению хеш-значения транзакции.

Таким образом, изменить хеш-значение транзакции можно, не имея доступа к личным ключам. Почему же изменение хеш-значения так нежелательно?

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

Выше были упомянуты off-chain протоколы. Для их реализации решение проблемы transaction malleability необходимо. В основе их работы лежит построение цепочек из неподтвержденных транзакций. Изменение хеш-значения первой транзакции повлечет за собой невалидность всей цепочки неподтвержденных.

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

Обратная совместимость при распространении блока по сети


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

С целью обратной совместимости правила работы протокола позволяют работать старым узлам с новыми блоками, но они будут получать блок только в базовой комплектации с максимальным размером 1 MB. Им недоступна структура witness. Новые же блоки получают полноценный блок с транзакциями и доказательствами. Ознакомиться с этим вопросом поможет следующий рисунок.

image

Слева представлена схема работы протокола Биткоин до активации Segregated Witness. Блок имел максимальный размер 1 MB, и он распространялся между различными узлами сети в одном виде.

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

Способы увеличения пропускной способности


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

Hardfork обновление. Самое банальное из обновлений и заключается в увеличении размера блока. Предполагается, что один блок будет вмещать больше транзакций, повышая пропускную способность. Однако такой блок не будут принимать узлы, работающие по старому протоколу, в правилах которого записано, что максимальный размер блока не может превышать 1 МВ. Такое изменение требует hardfork, который организационно более сложен, чем softfork.

SoftFork обновление. Segregated Witness позволяет нам решить эту проблему при помощи softfork. Как именно? Он позволяет нам разделить блок на две части, в первой из которых хранятся транзакции, а во второй – доказательства. При этом новые узлы сети получают обе части, а старые – только блок транзакций размером 1 MB. Старые узлы не могут получать блоки с доказательствами и, соответственно, не могут валидировать транзакции, которые получают, но это позволяет им участвовать в достижении консенсуса и не прибегать к hardfork, а постепенно переходить к новому ПО.

Новшества Segregated Witness


Рассмотрим, что входит в обновление Segregated Witness. Первым и самым важным новшеством Segregated Witness стал новый формат сериализации транзакций. Кроме уже известных полей, в новой транзакции присутствуют три новых: marker, flag, которые применяются для версирования и в данном случае они строго заданы, но в следующих протоколах они могут меняться, а также поле witness. Witness (witness data) – это фактически набор доказательств владения монетами, которые вынесены за пределы основной части транзакции. Структурно он выглядит, как набор входов, при этом каждый элемент witness data соответствует входу с определенным номером, что позволяет сопоставить доказательства с конкретными потраченными монетами.

Witness transaction id


Чтобы получить идентификатор транзакции (transaction id, txid), нужно привести саму транзакцию к одной последовательности данных по специальному формату сериализации, а потом получить хеш-значение от этой последовательности данных. С введением Segregated Witness появился и новый идентификатор, witness transaction id (wtxid), и новый формат сериализации, соответственно. Для старых транзакций, которые тратят средства, не используя Segregated Witness, wtxid будет таким же, как txid, потому что у них не будет новых полей, которые добавились в Segregated Witness.

image

Wtxid нужен, чтобы построить альтернативный Merkle tree для доказательств. Строится он точно так же, как и для обычных транзакций, только вместо хеша транзакции здесь применяется wtxid. Соответственно, wtxid попарно хешируются и дают в результате Merkle root.

Важно отметить, что Merkle root вставляется в coinbase транзакцию, а не в заголовок блока. Если бы root находился в заголовке блока, то изменилась бы структура блока. Узлы, которые поддерживают старый протокол, не могли бы работать с такими блоками. И все старания сохранить обратную совместимость упирались бы в эту несостыковку. Поэтому root вставляется в один из выходов coinbase транзакции. Когда все узлы перейдут на Segregated Witness, эта ситуация может измениться и будут рассматриваться новые подходы.

Witness programs для задания условий траты монет


Давайте рассмотрим, как строится скрипт Segregated Witness транзакции и как он позволяет старым узлам сети понимать, что транзакции Segregated Witness правильные, несмотря на то, что они не получают доказательств владения монетами.

Скрипт описывающий правила траты монет из транзакции нового формата состоит из двух частей. Первая часть – это witness version byte (байт определяющий версию witness program). Он может принимать значения от 0 до 16 (OP0-OP16), сейчас используется OP0. В будущем могут появляться новые версии протокола c поддержкой других версий witness program. Вторая часть – это witness program. Эта часть может иметь размер от 2 до 40 байт.

Witness program является результатом хеширования witness script. Сам witness script содержит полное описание условий траты монет. Witness data содержит доказательства владения монетами, которые должны удовлетворять условиям из witness script. Соответственно witness data всегда состоит из двух частей: witness script и доказательства владения монетами.

Стоит отметить, что witness program не содержит никаких операций (совпадения хеш-значений, проверки электронных подписей), а сам скрипт начинается с кода OP0, следовательно, он валиден для всех старых узлов. Причем узлы, которые не обновились до SegWit, не проверяют доказательства владения монетами для выходов нового формата, они такую трату считают правильной в любом случае. Строго говоря, старые узлы будут принимать транзакции нового формата даже если ее отправитель на самом деле не владеет соответствующими монетами. Именно поэтому SegWit требует, чтобы владельцы большинства майнинговой мощности Биткоина приняли это обновление. Еще одна особенность состоит в том, что scriptSig у транзакции, которая тратит монеты из выхода нового формата, будет пустым.

Новые варианты задания условий траты монет


С введением SegWit было предложено два стандартных формата для scriptPubKey, которые стали альтернативой двум наиболее распространенным форматам задания правил траты монет еще до появления этого обновления. Рассмотрим их по порядку.

Pay to witness public key hash (P2WPKH) является аналогом стандартного pay to public key hash. В чем состоит его отличие? Как было отмечено раньше, scriptSig не заполняется и остается пустым. Все доказательства владения монетами переносятся в структуру witness data.

При этом в scriptPubKey вставляется скрипт, который был рассмотрен ранее, версия и хеш публичного ключа, который является witness program. Узел в сети отличает такой скрипт траты от других благодаря тому, что версия у него равна единице, а размер данных 20 байт. Другая версия и другой размер несут в себе другие правила траты.

image

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

Pay to witness script hash (P2WSH) – это аналог стандартного pay to script hash. В данном случае могут использоваться custom script для задания правил траты монет. Как узел сети отличает такой скрипт от предыдущего? В этом случае версия по-прежнему имеет значение единицы, а witness программа занимает 32 байта и является хеш-значением от witness script. Если на узел сети придет транзакция, содержащая какой-то скрипт, который будет иметь первую версию, но его размер будет отличаться от значений 20 или 32 байта, то узел отклонит эту транзакцию, потому что он не будет знать, как с ней работать.

Witness data здесь делится на две части. В первой содержится набор доказательств владения монетами, то есть набор подписей. Во второй части размещается witness script, содержимое которого как раз и задает правила траты монет, но в данном случае оно указывается в момент траты, а в момент отправки монет указывалось его хеш-значение.
image
В данном случае scriptPubKey содержит две части: номер witness версии равный нулю и хеш-значение witness script для случая мультиподписи 1-из-2. ScriptSig будет пустым, а witness data будет содержать электронную подпись и исходный witness script в открытом виде.

P2SH обертка


Новый формат скрипта отличается от старого. Соответственно, старые сервисы и кошельки не будут знать, как работать с таким форматом скрипта и как его составить. С целью обратной совместимости в Segregated Witness транзакциях при помощи P2SH используется специальная «обертка», которая позволяет сформировать транзакцию, обладающую свойствами Segregated Witness транзакции, но не отличающуюся от обычной P2SH для внешнего мира.

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

image

В данном случае scriptPubKey содержит операцию хеширования, хеш-значение redeem scrip и операцию сравнения (как для старой версии P2SH). ScriptSig тут будет содержать хеш-значение открытого ключа, а witness data будет содержать электронную подпись и открытый ключ.

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

Новый формат адресов Bech32


Стоит отдельно упомянуть Bech32 адреса которые считаются нативными SegWit адресами. Большую часть своей истории Биткоин использовал для адресов кодирование Base58 с добавлением контрольной суммы, которая является усеченным результатом двойного хеширования с помощью хеш-функции SHA-256. Они были частью оригинального ПО и область их действия была расширена в BIP13 для P2SH. Но как набор символов, так и алгоритм контрольной суммы имеют ограничения:
  • адрес в Base58 занимает больше памяти в QR-кодах, поскольку не может использовать режим буквенно-цифрового представления;
  • base58 является очень неудобным для надежной записи на бумагу, ввода с мобильной клавиатуры или чтения вслух;
  • двойное хеширование контрольной суммы является медленным;
  • декодирование base58 является сложным и сравнительно медленным.

image
В обновление SegWit входит новый класс выходов (witness programs) и два его случая: P2WPKH и P2WSH. Их функциональность косвенно доступна для старых узлов через использование P2SH, но оптимальнее и безопаснее будет использовать ее напрямую, для этого необходимо введение нового формата адресов.

Спецификация Bech32 адреса


Адрес Bech32 имеет длину, которая не превышает 90 символов, и содержит:

  1. Часть, удобную для чтения человеком. Сюда входят данные, которые может понадобиться передать или которые имеют какое-либо отношение к владельцу адреса, длина минимум 1 символ. Например, по умолчанию для адресов mainnet используются символы «bc», а для testnet символы «tb».
  2. Разделитель, который всегда равен «1». Если «1» разрешен внутри человекочитаемой части, то разделителем является последний из символов «1».
  3. Часть с данными имеет длину как минимум 6 символов и состоит только из буквенно-цифровых символов, исключая «1», «b», «i», и «o». В качестве основных данных тут используется версия witness program и данные самой witness program (от 2 до 40 байт).


image

Зачем включать разделитель в адреса? Это позволяет однозначно отделить человекочитаемую часть от части с данными, избежав потенциальных столкновений с другими человекочитаемыми частями, которые используют префикс. Это также позволяет избегать ограничений в наборе символов для человекочитаемой части. Сепаратор равен 1, потому что использование не алфавитно-цифрового символа затруднит копирование адресов (без выбора двойного щелчка в нескольких приложениях). Поэтому был выбран буквенно-цифровой символ вне основного набора символов. Также использование системы счисления по основанию 32 сопровождается увеличением длины адреса на 15% по сравнению с системой счисления по основанию 58, но это не имеет значения при копировании адресов.

Контрольная сумма Bech32 адреса


Последние 6 символов адреса являются контрольной суммой. Контрольная сумма построена на основе БЧХ-кода, который гарантирует обнаружение любой ошибки, затрагивающей не более 4 символов, а шанс того, что контрольная сумма сойдется, когда допущено более 4 ошибок, один из 109.

Одним из преимуществ использования БЧХ-кодов является то, что они могут использоваться для исправления ошибок. Если в адресе было допущено до 4 ошибок, то они будут исправлены автоматически. А если допущено больше ошибок, то они будут обнаружены с высокой вероятностью, но уже без возможности их автоматического исправления.

Верхний и нижний регистр в адресе


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

ПО всегда выводит всю строку адреса Bech32 в нижнем регистре. Если требуется версия в верхнем регистре (например, в целях презентации или использования в QR-коде), то это доступно опционально. Более того, ПО не будет принимать адреса, в которых некоторые символы в верхнем регистре, а некоторые в нижнем. Для отображения нижний регистр обычно более предпочтителен, но для QR-кодов следует использовать верхний регистр, поскольку он позволяет буквенно-цифровое представление, которое кодируется на 45% компактнее, чем байтовое представление.

Понятия веса и размера блока


Еще одним важным изменением, которое внесло обновление Segregated Witness, является введение такого понятия, как вес транзакции и вес блока. До Segregated Witness обычно говорили только о размере транзакции и размере блока. При этом размер блока был ограничен 1 MB. После активации обновления существует два формата транзакций. Соответственно, дальше поддерживать нужно оба.

С целью решения этой проблемы было введено понятие веса транзакции и соответствующих весовых единиц (weight units). Размер основной части транзакции теперь учитывается с коэффициентом 3, а размер witness data с коэффициентом 1. Как можно догадаться, любые данные, которые включались в witness data требовали в 3 раза меньшей комиссии, чем основные данные транзакции. Подобный подход позволяет валидаторам определить более выгодную транзакцию в отношении занимаемого в блоке места и получаемым вознаграждением. Вес рассчитывается по специальной формуле.

block weight = base size * 3 + total size

block weight – вес блока (измеряется в весовых единицах)
base size – базовый размер блока (измеряется в байтах)
total size – итоговый размер блока (измеряется в байтах)

В этой формуле базовый размер транзакции значит, что размер транзакции при сериализации по старым правилам умножается на три и результат суммируется с размером транзакции, сериализованной по новым правилам. В результате получаем вес транзакции.

Вне зависимости от того, по новым или по старым правилам сериализована транзакция старого образца, размер она всегда будет иметь одинаковый, соответственно, вес будет ровно в 4 раза больше. А для Segregated Witness транзакции вес будет чуть меньше, потому что в размер транзакции не будут включаться данные доказательств владения монетами.

Вместе с весом было введено понятие виртуального размера, который вычисляется путем деления веса на четыре. Виртуальный размер (virtual size) используется, чтобы рассчитать комиссии для транзакций и чтобы валидаторы могли понять, насколько им выгодно включать определенную транзакцию в блок используя привычную цену записи, которая измеряется в единицах spb (satoshi per byte).

virtual size = weight units / 4

Поскольку вес транзакции для не Segregated Witness будет в 4 раза больше, чем размер, то виртуальный размер транзакции будет равен обычному размеру. Соответственно, для старых транзакций подсчет комиссии не изменится. Для новых транзакций он будет чуть меньше, потому что подписи выносятся в отдельную структуру. Таким образом, за них можно платить меньшие комиссии, но иметь тот же приоритет у майнеров при включении в блок. При этом, максимальный размер блока без witness data (base size) остался 1 MB, а максимальный вес блока равен 4 MB.

Здесь может возникнуть логичный вопрос: «каким будет фактический размер блока вместе с witness data?». Абсолютно точно ответить на него невозможно. Очевидно, что это значение будет находиться в пределах от 1 MB до 4 MB. Но можно сделать более точную теоретическую оценку. Получится около 1.8 MB. Откуда это значение? Типичный блок с транзакциями на текущий момент состоит примерно на 60% из открытых данных. Если посчитать вес блока размером 1 MB, состоящего на 40% из данных доказательств владения монетами, то получим следующие данные.

400000 байт * 4 = 1600000 условных единиц веса
600000 байт * 1 = 600000 условных единиц веса
1600000 + 600000 = 2200000 условных единиц веса
4000000 / 2200000 = 1.81 MB

То есть, можно предполагать, что эффективный размера блока будет около 1.8 MB. Но очевидно, что на практике это значение будет полностью зависеть от состава транзакций в этом блоке.

Статистика адаптации обновления


По состоянию на июль 2018 года количество SegWit транзакций преодолело отметку 35% от общего количества в сети Биткоин. При этом основные сервисы для работы с Биткоином и цифровые кошельки реализовали поддержку Segregated Witness совсем недавно (например, Electrum и Bitxfy).

image
Диаграмма взята из материалов исследования BitMex Research

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

image
По данным аналитики BitMex Research

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

И не будем забывать, что Segregated Witness дало возможность развитию off-chain решений поверх протокола Bitcoin. Конечно же, адаптация lightning network – это на много более сложная задача по сравнению с SegWit, тем не менее, работа в этом отношении идет полным ходом и уже есть значительные достижения.

Часто задаваемые вопросы


— Правильно ли утверждать, что для Segregated Witness транзакции не будет работать RBF (replace-by-fee)?

Нет, replace by fee будет работать для Segregated Witness транзакций, потому что он основан не на том, какие у вас правила траты, а на том, что вы используете одни монеты и указываете sequence number входа транзакции. Если вы увеличиваете значение на входе, используя те же монеты, и указываете корректные доказательства того, что вы владеете этими монетами, то вы точно так же можете заменить предыдущую транзакцию.

— Как можно изменить хеш неподтвержденной транзакции?

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

— Как в транзакции хранятся witness data?

Как было отмечено, в Segregated Witness транзакции ввели новый формат сериализации. Кроме того, что у нас есть набор входов и выходов, добавляются и другие байты, где хранятся доказательства. Соответственно, там и хранятся эти данные. Максимально просто можно это представить так: есть просто набор данных, где написано, что существует два входа транзакции (байты первого входа и байты второго входа), два выхода, а после них еще два набора Witness data, которые точно так же записаны в виде байтов. Фактически данные доказательств владения монетами перенесены в другое место при сериализации.

— Почему бы не использовать существующий набор символов, например RFC3548 или z-base-32 для Bech32 адресов?

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

Комментарии (1)


  1. mspain
    01.08.2018 14:54
    -1

    Сегвит таки случился? %(( весь смак биткоина по сравнению с остальными щиткоинами в том что он первый взлетел и набрал массу. Все эти тысячи брошенных кошельков на сумму в мегабаксы, которые в теории можно сбрутфорсить :) а тут приходят всякие и суют свои ручонки в святое. Делали бы очередной 100501й щиткоин :(