Bitcoin: встроенная система сценариев и цифровые контракты
Про Bitcoin на Хабре писали уже достаточно, однако лишь в общих чертах. Для непосвященных, на мой взгляд, полезными будут топики: раз и два.
В этом же посте затронут весьма узкий аспект — встроенная система сценариев, предназначенная для проверки валидности транзакций, а также некоторые её возможности. На родном языке такой информации мне не попадалось, потому вношу свою лепту.
Немного о сценариях
Для проверки транзакций Bitcoin имеется встроенный стек-ориентированный язык сценариев, чем-то похожий на Forth. По понятным причинам он не является Тьюринг-полным и в нём нет циклов. С другой стороны, он очень прост.
По существу, сценарий — это последовательность инструкций внутри транзакции, которая описывает, как лицо, желающее потратить биткоины, должно получить к ним доступ. Сценарий типичного перевода средств на адрес A налагает 2 требования на лицо, желающее впоследствии воспользоваться этими средствами:
- предоставить в следующей транзакции открытый ключ, хэш которого равен A,
- предоставить подпись, доказывающую владение указанным выше открытым ключом.
Сценарии достаточно гибки по части указания различных условий дальнейшего распоряжения средствами. Например, можно потребовать два ключа/подписи или комбинацию нескольких подписей. В общем случае лицо(лица), отправляющее средства, указывает в транзакции сценарий их последующей траты (scriptPubKey). Лицо(лица), желающее воспользоваться полученными средствами, в следующей транзакции указывает входные данные для сценария (scriptSig). Если у транзакции сумма входящих средств больше или равна сумме исходящих средств, а комбинированный (scriptSig + scriptPubKey) сценарий выполняется без сбоя и в результате его работы на верхушке стека оказывается истинное (ненулевое) значение, транзакция считается валидной и майнеры могут включать её в цепочку блоков.
scriptPubKey:
OP_DUP OP_HASH160 {addr} OP_EQUALVERIFY OP_CHECKSIG
scriptSig:
{sig} {pubKey}
Трассировка по шагам:
№ Стек Сценарий 0 EMPTY {sig} {pubKey} OP_DUP OP_HASH160 {addr} OP_EQUALVERIFY OP_CHECKSIG 1 {sig} {pubKey} OP_DUP OP_HASH160 {addr} OP_EQUALVERIFY OP_CHECKSIG 2 {sig} {pubKey} OP_DUP OP_HASH160 {addr} OP_EQUALVERIFY OP_CHECKSIG 3 {sig} {pubKey} {pubKey} OP_HASH160 {addr} OP_EQUALVERIFY OP_CHECKSIG 4 {sig} {pubKey} {hash} {addr} OP_EQUALVERIFY OP_CHECKSIG 5 {sig} {pubKey} {hash} {addr} OP_EQUALVERIFY OP_CHECKSIG 5 {sig} {pubKey} OP_CHECKSIG 6 TRUE EMPTY
Подробнее про сценарии можно почитать здесь.
Временная блокировка, мультиверсионность и прочая магия
Помимо сценариев в Bitcoin-транзакциях есть еще несколько интересных штук: транзакция может быть отложенной на некоторое время или до какого-то конкретного блока, может менять в процессе согласования свою версию. У обычных транзакций интервал блокировки равен нулю, а версия — максимально возможная.
Кроме того, имеется возможность задавать режим хеширования транзакции при проверке подписи:
- SIGHASH_ALL — режим по умолчанию, по сути означает «я вношу свою часть если каждый вносит свою и получатели денег такие-то каждый на соответствующую сумму»;
- SIGHASH_NONE — означает «я вношу свою часть если каждый вносит свою, а кто получатель мне все равно»;
- SIGHASH_SINGLE — почти то же самое, по сути «я вношу свою часть если каждый вносит свою, но один из получателей такой-то на такую-то сумму».
Есть еще модификатор SIGHASH_ANYONECANPAY, который, будучи добавленным к любому из перечисленных режимов, по сути уберет слова «если каждый вносит свою» из описаний этих самых режимов.
Контракты
И вот на таком хитром базисе можно строить распределенные контракты — метод достижения договорённости между сторонами посредством использования цепочки блоков. Контракты не делают чего-то такого, что не было бы возможно раньше, однако они позволяют решать некоторые распространенные проблемы таким образом, что не требуется взаимного доверия сторон или его уровень сведен к минимуму. Такой подход позволяет избавиться от услуг доверенного посредника (который может прихватить ваши денежки и быть таков) при совершении сделок и разрешении спорных ситуаций. В качестве примера рассмотрим следующую жизненную ситуацию.
Сделка с протекцией и разрешение конфликта
Покупатель желает приобрести товар у продавца, которого он не знает и которому не доверяет. В случае нормально прошедшей сделки покупатель не хотел бы посвящать в детали постороннее лицо. Однако в случае проблем покупатель хотел бы, чтобы независимый арбитр решил, кто получит деньги. В качестве доказательства последний может запросить у продавца, скажем, квитанцию об отправке товара почтой.
Другими словами, Покупатель хотел бы заблокировать некую сумму, распоряжаться которой можно было бы с согласия хотя бы двух лиц из трех. Для этого он:
- Договаривается с Продавцом об Арбитре.
- Запрашивает у Продавца и Арбитра их открытые ключи K1 и K2 соответственно и создает новый ключ K3 для себя.
- Посылает продавцу ключ Арбитра K2. Продавец проверяет подлинность K2 запросив подпись случайного числа.
- Создает транзакцию T1 на сумму заказа такую, что потратить ее исходящие средства можно только по предоставлении хотя бы 2 подписей, и публикует ее в сети.
- Покупатель и Продавец ставят свои подписи под ней — сделка завершилась успешно или Продавец возвратил средства клиенту не дожидаясь решения Арбитра.
- Покупатель и Арбитр ставят свои подписи — сделка не произошла, Арбитр вернул средства Покупателю.
- Арбитр и Продавец ставят свои подписи — сделка признана Арбитром состоявшейся, несмотря на возражения Покупателя, средства переданы продавцу.
Подробнее о контрактах можно почитать здесь и здесь. Если тема будет интересной, опишу еще несколько типовых контрактов.
7 марта 2012 в 17:06
Источник: web.archive.org/web/20140911154857/http://habrahabr.ru/post/139291