Объяснение того, как выглядит транзакция OP_RETURN

Как используется OP_RETURN и почему он вообще был введен?

Ответы (4)

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

Еще в 2013 году различные игроки в биткойн-экосистеме пытались включать в транзакции биты информации, чтобы воспользоваться преимуществами необратимости блокчейна. Представьте, например, что вы хотите написать контракт и поместить его в неизменяемое место, чтобы в любой момент в будущем можно было вернуться, чтобы убедиться, что он существует. Вы можете сделать это, используя блокчейн. Вы добавляете некоторые биты к значению scriptSig транзакции, которые не изменяют конечный результат запуска этого скрипта, но позволяют вам хранить информацию, такую ​​как «Настоящим я заявляю, что передаю актив A по адресу XYZ во время UNIX_TIMESTAMP». Были и еще более странные способы, которыми люди добавляли дополнительные биты, например, включение их в значение BTC вывода. Некоторым членам сообщества это не понравилось, так как они увидели, что эти лишние биты загрязняют блокчейн.

Чтобы достичь золотой середины в этих противоположных взглядах, основные разработчики сделали код операции OP_RETURN действительным кодом операции для использования в транзакции биткойнов, что позволяет использовать 80 произвольных байтов в транзакции, которую нельзя потратить. Хорошее объяснение этому можно найти здесь:

https://bitcoinfoundation.org/bitcoin/core-development-update-5/

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

https://github.com/bitcoin/bitcoin/pull/3737

Теперь, когда мы выяснили причину отказа OP_RETURN, давайте рассмотрим пример OP_RETURN. Я использовал API chain.com, чтобы найти транзакцию, которая имеет OP_RETURN в своем scriptSig. Хэш этого tx

8bae12b5f4c088d940733dcd1455efc6a3a69cf9340e17a981286d3778615684 

Убедитесь, что вы подключены к полностью загруженному узлу bitcoind, и выполните следующую команду:

$> bitcoind getrawtransaction 8bae12b5f4c088d940733dcd1455efc6a3a69cf9340e17a981286d3778615684 1

который даст вам этот вывод:

{
"hex" : "0100000001c858ba5f607d762fe5be1dfe97ddc121827895c2562c4348d69d02b91dbb408e010000008b4830450220446df4e6b875af246800c8c976de7cd6d7d95016c4a8f7bcdbba81679cbda242022100c1ccfacfeb5e83087894aa8d9e37b11f5c054a75d030d5bfd94d17c5bc953d4a0141045901f6367ea950a5665335065342b952c5d5d60607b3cdc6c69a03df1a6b915aa02eb5e07095a2548a98dcdd84d875c6a3e130bafadfd45e694a3474e71405a4ffffffff020000000000000000156a13636861726c6579206c6f766573206865696469400d0300000000001976a914b8268ce4d481413c4e848ff353cd16104291c45b88ac00000000",
"txid" : "8bae12b5f4c088d940733dcd1455efc6a3a69cf9340e17a981286d3778615684",
"version" : 1,
"locktime" : 0,
"vin" : [
    {
        "txid" : "8e40bb1db9029dd648432c56c295788221c1dd97fe1dbee52f767d605fba58c8",
        "vout" : 1,
        "scriptSig" : {
            "asm" : "30450220446df4e6b875af246800c8c976de7cd6d7d95016c4a8f7bcdbba81679cbda242022100c1ccfacfeb5e83087894aa8d9e37b11f5c054a75d030d5bfd94d17c5bc953d4a01 045901f6367ea950a5665335065342b952c5d5d60607b3cdc6c69a03df1a6b915aa02eb5e07095a2548a98dcdd84d875c6a3e130bafadfd45e694a3474e71405a4",
            "hex" : "4830450220446df4e6b875af246800c8c976de7cd6d7d95016c4a8f7bcdbba81679cbda242022100c1ccfacfeb5e83087894aa8d9e37b11f5c054a75d030d5bfd94d17c5bc953d4a0141045901f6367ea950a5665335065342b952c5d5d60607b3cdc6c69a03df1a6b915aa02eb5e07095a2548a98dcdd84d875c6a3e130bafadfd45e694a3474e71405a4"
        },
        "sequence" : 4294967295
    }
],
"vout" : [
    {
        "value" : 0.00000000,
        "n" : 0,
        "scriptPubKey" : {
            "asm" : "OP_RETURN 636861726c6579206c6f766573206865696469",
            "hex" : "6a13636861726c6579206c6f766573206865696469",
            "type" : "nulldata"
        }
    },
    {
        "value" : 0.00200000,
        "n" : 1,
        "scriptPubKey" : {
            "asm" : "OP_DUP OP_HASH160 b8268ce4d481413c4e848ff353cd16104291c45b OP_EQUALVERIFY OP_CHECKSIG",
            "hex" : "76a914b8268ce4d481413c4e848ff353cd16104291c45b88ac",
            "reqSigs" : 1,
            "type" : "pubkeyhash",
            "addresses" : [
                "1HnhWpkMHMjgt167kvgcPyurMmsCQ2WPgg"
            ]
        }
    }
],
"blockhash" : "000000000000000004c31376d7619bf0f0d65af6fb028d3b4a410ea39d22554c",
"confirmations" : 2655,
"time" : 1404107109,
"blocktime" : 1404107109
}

Теперь посмотрите на список выходов этой транзакции, в частности на 1-й. Ссылаясь на страницу Биткойн Вики, посвященную Script , основанному на стеке языку программирования Биткойн, мы можем видеть здесь, что OP_RETURNкод операции представлен шестнадцатеричным значением 0x6a. За этим первым байтом следует байт, представляющий длину остальных байтов в scriptPubKey. В данном случае мы видим шестнадцатеричное значение Ox13, что означает наличие еще 19 байт. Эти байты составляют произвольные менее 40 байтов, которые вам разрешено отправлять в транзакции, отмеченной OP_RETURNкодом операции. Если вы вставите байты сообщения в декодер UTF8, вы увидите, что

636861726c6579206c6f766573206865696469

становится «Чарли любит Хайди». Ой! Это почти как цифровая версия романтической резьбы по дереву сердца пары. Теперь вы понимаете на уровне байтов, как OP_RETURNэто должно работать. Теперь вы можете написать программное обеспечение, которое ищет OP_RETURNкод операции в выходном файле scriptPubKey и использует его для проверки контракта или другого цифрового актива.

Важным аспектом OP_RETURN является то, что выходные данные, которые используют его стандартным образом, доказуемо неизрасходованы. Это означает, что узлы могут немедленно удалить такие выходные данные из своего кэша неизрасходованных выходных данных и, возможно, вообще забыть о них (хотя Bitcoin Core пока этого не делает). Это делает транзакции OP_RETURN намного менее затратными для сети, чем другие способы вставки данных в цепочку блоков.
К вашему сведению, если кто-то хочет декодировать это сообщение 636861726c6579206c6f766573206865696469в php, это шестнадцатеричное значение, поэтому используйтеhex2bin()
Почему это обходится сети дешевле, чем просто отправка 1 сатоши на произвольный адрес, содержащий 20 байт самой информации?
@NathanParker Поскольку с OP_RETURN узел знает, что индекс вывода транзакции нельзя потратить, и может просто игнорировать его. В то время как при отправке 1 сатоши узлу нужно будет хранить этот неизрасходованный вывод в памяти или в базе данных, ожидая, пока кто-нибудь когда-нибудь его потратит.
@almel В настоящее время команда для получения сведений о tx есть, bitcoin-cliа не bitcoind.
В *NIX эту xxdкоманду можно использовать. echo 636861726c6579206c6f766573206865696469 | xxd -p -rвозвращаетсяcharley loves heidi
Как возможно, что эта знаменитая транзакция содержит более 80 байт?
(он толкает 983 байта)
Вы говорите, что «не более одного вывода с OP_RETURN может быть включено в одну транзакцию» и предоставляете запрос на включение в качестве источника для этого. Где в этом обсуждении запроса на включение это упоминается?
Для тех, кто хочет декодировать сообщение с помощью JavaScript, однострочник в Node будетBuffer.from('636861726c6579206c6f766573206865696469', 'hex').toString('utf8');
Согласно вики сценария : it is usually considered non-standard (though valid) for a transaction to have more than one OP_RETURN output or an OP_RETURN output with more than one pushdata op.
Почему байты, которые я хочу сохранить в блокчейне, должны идти после OP_RETURN, а не до?
@theymos Так это просто соглашение / консенсус, из-за которого эти транзакции сжигают монеты, или есть другие технические причины?
@theymos twitter.com/lopp/status/947507679936774145?lang=ru Тут говорят монеты не сжигаются.
Могу ли я включить addressesзапись scriptPubKey, чтобы указать получателя сообщения?

Если вы хотите записать OP_RETURN в блокчейн, не вникая во внутренности построения транзакций, простой способ — использовать наши библиотеки для PHP и Python:

https://github.com/coinspark/php-OP_RETURN

https://github.com/coinspark/python-OP_RETURN

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

Предполагая, что вы используете Bitcoin Core 0.11, вы можете изменить значение OP_RETURN_MAX_BYTESна 80, а не 40на то, что сейчас указано в коде.

OP_RETURNэто способ получить произвольные данные в блокчейн с меньшей нагрузкой на сеть

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

Цель этого ответа — объяснить, что объяснил https://bitcoin.stackexchange.com/a/29555/21282 , но с немного большим контекстом для новичков в биткойнах.

Как выглядит стандартная транзакция

Как видно из разборки JSON с https://bitcoin.stackexchange.com/a/29555/21282 , у каждой транзакции есть список выходов, и у каждого выхода есть скрипт.

На сегодняшний день наиболее распространенным скриптом является pay-to-pubkey-hash , который в основном говорит:

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

или, проще говоря, «заплатите X биткойнов на адрес Y».

Этот скрипт имеет формат:

OP_DUP OP_HASH160 <length-of-hash> <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

где pubKeyHash — 20 байт, а все остальные 5 полей — 1 байт.

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

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

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

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

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

Чтобы проверить, действительна ли транзакция, реализации Биткойн должны хранить полный список всех неизрасходованных выходных данных, когда-либо созданных, известный как набор UTXO .

Израсходованные выходные данные можно обрезать для экономии места, а неизрасходованные — нет.

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

Как OP_RETURNрешает эту проблему

Возврат OP — это еще один тип транзакции скрипта, отличный от стандартной транзакции pay-to-pubkey-hash.

Как упоминалось в: https://en.bitcoin.it/wiki/Script#Provably_Unspendable.2FPrunable_Outputs , транзакция имеет простую форму:

OP_RETURN <data>

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

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

Таким образом, майнер может майнить за плату за майнинг, но тогда реализации сразу же удаляют его из набора UTXO.

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

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

Если я «добавлю произвольные данные», не сделает ли это транзакцию недействительной и не принятой в блокчейне? Или это просто адрес получателя и я вместо собственного адреса ввожу какие-то произвольные данные?
@RonyTesler вы просто вводите произвольные данные вместо фактического адреса, которым вы управляете. Но поскольку адреса выглядят совершенно случайными по своей природе (они являются открытыми ключами), пиры не могут их различить, поэтому их необходимо добавить в цепочку. И поскольку у вас нет закрытого ключа, вы (или кто-либо другой) не можете требовать средства позже.

Если вы здесь пытаетесь преобразовать OP_RETURN в читаемые значения:

Примечание. Это javascript/машинопись.

export default class OpReturnConverter {

    // Input -> <Buffer 35 33 36 39...>
    // Output -> 53696d706c6520616e737765722120f09f988a
    public static convertBufferToHex(buffer: Buffer) {
        const str = buffer.toString('hex')
        return Buffer.from(str, 'hex').toString()
    }

    // Input -> 53696d706c6520616e737765722120f09f988a
    // Output -> Simple answer! 😊
    public static convertHexToString(hex: string) {
        return Buffer.from(hex, 'hex').toString()
    }

    // Input -> Simple answer! 😊
    // Output -> <Buffer 35 33 36 39...>
    public static convertStringToBuffer(message: string) {
        const hexBuffer = Buffer.from(message).toString('hex')
        return Buffer.from(hexBuffer)
    }

}

Полученные результаты

const string = 'Simple answer! 😊'
console.log('Original ->', string)

const buf = OpReturnConverter.convertStringToBuffer(string)
console.log('Buffer ->', buf)

const hex = OpReturnConverter.convertBufferToHex(buf)
console.log('Hex ->', hex)

const unhex = OpReturnConverter.convertHexToString(hex)
console.log('Unhex ->', unhex)