Как составить транзакцию с OP_RETURN в Python?

В настоящее время пытаюсь понять, как использовать Python для создания транзакции с OP_RETURN. Я попытался закодировать сообщение самостоятельно, и мне не повезло. Я нашел функцию OPReturn() в Интернете, но когда я пытаюсь ее использовать, я получаю сообщение об ошибке (из широковещательного API Blockchain.info):Exception: None Standard Script Output OP_RETURN 594f4c4f53574147

Код:

# coding: utf-8

from bitcoin import *
import binascii
from test import *


priv = sha256('brain wallet')

pub = privtopub(priv)

addr = pubtoaddr(pub)

inputs = unspent(addr)

message = "YOLOSWAG"
FullLen = format(len(message)+2,'x').rjust(2,'0')
MessageLen = format(len(message),'x').rjust(2,'0')
ID = binascii.hexlify(str(message))
snd = "6a"+MessageLen+ID

outputs = [{'value': 50000, 'address': addr}, {'value': 0, 'script': snd}]

fee = 10000

tx = mksend(inputs, outputs, addr, fee)

dt = deserialize(tx)
ins = dt['ins']

#print addr
#print ins


for ind, elm in enumerate(ins):
    print elm
    tx = sign(tx, ind, priv)

#print tx



print(pushtx(tx))
Обратите внимание, что этот код будет работать только с сообщениями размером 75 байт или меньше.
@NickODell, разве это не 40 байт? (EDIT: вы имеете в виду всего 75 байтов, я только что понял?)
Какая версия питона? Я почти уверен, что вы пытаетесь сделать это на Python 3.x, где поле структуры "q/Q" больше недоступно. Pybitcointools потребует Python 2.7 (на самом деле практически все биткойн-питоны версии 2.x из-за того, как он обрабатывает строки как байты без binascii и тому подобного.

Ответы (3)

Я разветвил библиотеку pybitcointools, чтобы вернуть правильно отформатированную OP_RETURNшестнадцатеричную строку или вставить ее OP_RETURNв необработанную шестнадцатеричную транзакцию.

Мою вилку можно найти здесь . Код выглядит следующим образом:

from bitcoin.pyspecials import safe_hexlify, from_string_to_bytes, from_int_to_byte, from_string_to_bytes

def mk_opreturn(msg, rawtx=None, json=0):
    def op_push(data):
        import struct
        if len(data) < 0x4c:
            return from_int_to_byte(len(data)) + from_string_to_bytes(data)
        elif len(data) < 0xff:
            return from_int_to_byte(76) + struct.pack('<B', len(data)) + from_string_to_bytes(data)
        elif len(data) < 0xffff:
            return from_int_to_byte(77) + struct.pack('<H', len(data)) + from_string_to_bytes(data)
        elif len(data) < 0xffffffff:
            return from_int_to_byte(78) + struct.pack('<I', len(data)) + from_string_to_bytes(data)
        else: raise Exception("Input data error. Rawtx must be hex chars" \
                            + "0xffffffff > len(data) > 0")

    orhex = safe_hexlify(b'\x6a' + op_push(msg))
    orjson = {'script' : orhex, 'value' : 0}
    if rawtx is not None:
        try:
            txo = deserialize(rawtx)
            if not 'outs' in txo.keys(): raise Exception("OP_Return cannot be the sole output!")
            txo['outs'].append(orjson)
            newrawtx = serialize(txo)
            return newrawtx
        except:
            raise Exception("Raw Tx Error!")
    return orhex if not json else orjson

Обратите внимание, что имя модуля было изменено на btc(из bitcoin) в моей вилке.

Чтобы запустить это, вы будете использовать os.chdir("c:/python/pybitcointools")(или любой другой каталог, в который он был загружен. Затем from bitcoin import *. Теперь давайте используем msg = 'The enemy of my enemy is my friend'и rawtx = "01000000016e3cd2b24fcf49259db29888ec5fe6521070041cb8c7bb2017537046f9e00f2b0000000000ffffffff0168d61100000000001976a91469bbbb16301e40b9fb67130e1aa53a2281d60af088ac00000000".

mk_opreturn(msg, rawtx)возвращает:

01000000016e3cd2b24fcf49259db29888ec5fe6521070041cb8c7bb2017537046f9e00f2b0000000000ffffffff0268d61100000000001976a91469bbbb16301e40b9fb67130e1aa53a2281d60af088ac0000000000000000246a2254686520656e656d79206f66206d7920656e656d79206973206d7920667269656e6400000000

Это необработанный Tx с OP_RETURNправильно вставленным. Запустите функцию без rawtxпараметра, и она вернет строку6a2254686520656e656d79206f66206d7920656e656d79206973206d7920667269656e64

Вы хотели ответить дважды? PS. Я отправил вам PR на github. :)
Да и нет :). Я чувствовал, что нужен отдельный ответ, потому что я пытаюсь ответить на вопрос «как легко использовать OP_RETURN с Python с помощью кода». Я чувствую, что этот ответ более автономен. Хороший улов на PR BTW

Сценарий просто (так сказать) берет необработанную транзакцию и объединяет шестнадцатеричное число, которое представляет собой дополнительный вывод Tx. Итак, он ищет ffffffff ( последовательность ) и добавляет 6a hex encoding of your msg(до 20 байт)

Сообщение необходимо преобразовать в шестнадцатеричный формат (что делает код).

У меня код работает нормально, хотя я еще не пробовал вещать. На основании вашей цитируемой ошибки

Я получаю сообщение об ошибке (из широковещательного API Blockchain.info): Exception: None Standard Script Output OP_RETURN 594f4c4f53574147

Я должен сказать, что BCI реагирует на MessageLenчасть кода. Должен быть OP_PUSHDATA1( 0x4c) между OP_RETURN( 0x6a) и длиной сообщения 1 байт, 0x08.

Пытаться:6a4c08594f4c4f53574147

В качестве альтернативы попробуйте другой сервис для отправки необработанных Tx, например:

Разве моя линия ID = binascii.hexlify(str(message))уже не позаботилась об этом?
@rsmoz позволь мне взглянуть на тебя. Можете ли вы подтвердить URL-адрес скрипта и версию Python, на которой вы работаете?
2.7. Я собираюсь обновить код некоторыми изменениями, которые я сделал.
Добавил пуш-код, не помогло. Попробовал отправить tx Bitpay, сказал мне, что моя транзакция была пылью, что, как я помнил, означало, что транзакция была слишком маленькой. Увеличил его, затем использовал отправку Bitpay, и это сработало! blockchain.info/tx/…
@rsmoz хороший материал! Мне интересно знать, было ли это связано с ограничением пыли в 550 сатоши или кодом push-операции. Я отредактирую свой ответ, чтобы удалить бесполезные комментарии Binascii, которые я сделал
Хм, все еще есть некоторые проблемы. Теперь, когда у меня есть много входных данных, транзакция не собирается должным образом.
Я хотел добавить уточнение: при сборке 40-байтового OP_RETURN Txn код выглядит следующим образом: 2a6a28 40 byte data, где 2aговорится, что вставьте следующие 42 байта, 6aэто OP_RETURN и 28говорит, что вставьте 40 байтов. Это необходимый формат для Bitcoincore.

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

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

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

Чему соответствует регистрационный номер?
Он имеет формат: [оценочная высота]-[частичный txid] [оценочная высота] — это блок, в котором может появиться первая транзакция. При сохранении мы устанавливаем [оценочная высота] на 1+(текущая высота). При извлечении мы пробуем этот блок, затем немного позже и несколько раньше в случае реорганизации. [partial txid] содержит 2 соседних байта из txid: position=2*([partial txid] div 65536) ([partial txid] mod 256) — это байт в позиции ([partial txid] mod 65536) div 256) — это байт в позиции byte at (position+1) Вы не можете использовать txid для ссылки, так как большинство узлов не индексируются по txid.
@Gideon Greenspan - я пытался использовать ваш код, но получил эту ошибку:'OP_RETURN.py", line 456, in OP_RETURN_bitcoin_cmd if not len(port): TypeError: object of type 'int' has no len()'
Установите OP_RETURN_BITCOIN_PORT, используя целое число в строке, а не целое число.