¿Cuál es una forma paso a paso de insertar datos en OP_RETURN?

Estaba siguiendo https://bitcointalk.org/index.php?topic=453086.0 para crear un mensaje en OP_RETURN. Puedo decodificar mi transacción sin procesar, pero en signrawtransaction da

error: {"código":-22,"mensaje":"Error en la decodificación de TX"}

Validé la dirección, ¿hay algo que falta en ese tutorial?

La mejor manera sería publicar el tx resultante. ¿Los datos que está incrustando ocupan menos de 40 bytes?
Gracias Matthieu, tenías razón sobre el tamaño. Pero aún tenía que hacer más pasos. Así estaba buscando un Paso a Paso completo.
Recibí este mensaje cuando olvidé reemplazar la longitud del script original con la nueva para mi cadena hexadecimal OP_RETURN.

Respuestas (3)

Escribí un pequeño programa de demostración que coloca un fragmento de datos en un script OP_RETURN. Requiere una instancia de bitcoin que acepte conexiones RPC, aunque podría implementarse sin eso. Puedes encontrarlo en github aquí . Ha sido probado, pero solo en testnet. Voy a revisar el código y explicar lo que está haciendo.

comienzo

[...]
logging.basicConfig()
logging.getLogger("BitcoinRPC").setLevel(logging.DEBUG)

Esto hace que el registro sea más detallado. Es útil porque muestra qué llamadas RPC se están realizando.

Conectarse a bitcoind

rpc_user = "bitcoinrpc"
rpc_password = "87Y9A2gs25E9HDPGc9axqSqzxMR2MyTtrMkYc5KiZk2Z"

rpc = AuthServiceProxy("http://%s:%s@127.0.0.1:18332/" % (rpc_user, rpc_password))

Tenga en cuenta que su contraseña será diferente y que utilizará el puerto 8332 para la red principal en lugar del puerto 18332.

Enumerar productos no gastados

first_unspent = rpc.listunspent()[0]
txid = first_unspent['txid']
vout = first_unspent['vout']
input_amount = first_unspent['amount']
SATOSHI = Decimal("0.00000001")
change_amount = input_amount - Decimal("0.005") - SATOSHI

La - Decimal("0.005")parte es para que paguemos una tarifa de transacción.

Crear transacción

# Marker address we're going to replace
# Produces a pattern that's easy to search for
mainnet = 0
if mainnet:
    dummy_address = "1111111111111111111114oLvT2"
else:
    dummy_address = "mfWxJ45yp2SFn7UciZyNpvDKrzbhyfKrY8"

Estas son dos codificaciones diferentes de un hash de clave de pago a público de todos ceros. La superior es la representación de la red principal y la inferior es la representación de la red de prueba.

# My change address
change_address = "mhZuYnuMCZLjZKeDMnY48xsR5qkjq7bAr9"

Recuerde, esta es mi dirección de cambio. Si no lo cambias, me estarás enviando dinero.

tx = rpc.createrawtransaction([{"txid": txid, "vout": vout}], \
                              {change_address: change_amount, \
                               dummy_address: SATOSHI})

Y ahora tenemos una transacción real. Sin embargo, no contiene ninguno de nuestros propios datos, por lo que tendremos que arreglarlo.

Reemplace la salida ficticia con nuestra propia salida

# Pattern to replace
# Represents length of script, then OP_DUP OP_HASH160,
# then length of hash, then 20 bytes of zeros, OP_EQUALVERIFY OP_CHECKSIG
oldScriptPubKey = "1976a914000000000000000000000000000000000000000088ac"

Esto es un poco un truco. En lugar de crear nuestra propia salida, creamos una salida ficticia, luego buscamos el patrón que crea y lo reemplazamos. Probablemente haya una mejor manera de hacer esto, pero esto parece más fácil.

# Data to insert
data = "Melons."
if len(data) > 75:
    raise Exception("Can't contain this much data-use OP_PUSHDATA1")

newScriptPubKey = "6a" + hexlify(chr(len(data))) + hexlify(data)

A continuación, creamos los datos que queremos poner en la cadena de bloques. Estoy usando la cadena Melons., pero podrías usar cualquier cosa. (Sin embargo, más de 40 bytes no es estándar). Cubrí la mayor parte de esto en mi otra respuesta .

Este código se romperá si los datos tienen más de 75 bytes. Si lo necesita para más que eso, puede usar OP_PUSHDATA1 en lugar de los datos push de un solo byte que estoy usando aquí.

#Append int of length to start
newScriptPubKey = hexlify(chr(len(unhexlify(newScriptPubKey)))) + newScriptPubKey

Esta parte es un poco diferente a mi otra respuesta, porque también debemos incluir la longitud de scriptPubKey. Este código se romperá con datos de más de 251 bytes. Si desea que funcione con datos más largos que eso, codifique una variante correctamente.

if oldScriptPubKey not in tx:
    raise Exception("Something broke!")

Comprobación de errores para este método muy destartalado.

tx = tx.replace(oldScriptPubKey, newScriptPubKey)

Finalmente, un reemplazo de cadena cambia el nuevo script por el antiguo.

Firmarlo

tx = rpc.signrawtransaction(tx)['hex']

Bitcoin maneja el levantamiento agitado aquí.

Transmítelo a la red.

rpc.sendrawtransaction(tx)

¡Hecho! Ahora solo espere a que su transacción entre en un bloque.

Ejecuté el código ( salida ) y produje una transacción, que puede ver en Block Explorer aquí . Si copia la cadena junto a OP_RETURN y la pega en un convertidor hexadecimal a ASCII , obtiene...

Melons.

¡Hecho!

Otros recursos

Encontré esta página web útil mientras escribía esto.

Bien, ya que es un scriptsig OP_RETURN (si lo entiendo correctamente), ¿eso significa que la red eliminará/invalidará el tx?
@Valmond scriptsigscriptPubKey, en realidad. does that mean the tx will be removed / invalidated by the network?Realmente no. Se eliminará del conjunto de salida de transacciones no gastadas en algunos clientes, pero muchos clientes aún lo recordarán. (Deben hacerlo, porque necesitan demostrar a los nuevos clientes que es solo una transacción OP_RETURN).
Tenga en cuenta que la transacción que produjo no sería una transacción estándar en la red principal porque la salida op_return tiene un valor> 0. Se retransmite/mina de forma predeterminada en la red de prueba porque la red de prueba acepta casi todas las transacciones como estándar.
@ DavidA.Harding Hice eso porque createrawtransaction no aceptaría un valor de 0. ¿Puede proporcionar una fuente para ese reclamo? No puedo encontrar ningún cheque como ese en Solver o IsStandard.
@NickODell oh, cabrón --- pareces tener razón; He estado dando malos consejos a la gente durante un año. Lo siento.
Tengo algunas preguntas. 1. ¿Cómo calculaste las direcciones ficticias con tanta precisión? 2. Si ingreso una dirección real como ficticia ( getnewaddress) y luego txhex = createrawtransaction. Luego obtengo el script hexadecimal por decodedtx = decoderawtransaction txhexy oldScriptHex = decodedtx.scriptPubKey.hex. Luego txhex.replace(oldScriptHex, newScriptHex), este enfoque ya no decodifica (código -22; la decodificación de TX falló). ¿por qué? newScriptHexes idéntica en su versión y la mía.
Actualmente puede usar createrawtransactioncon un me voutgusta {"data": "your hex data"}y no tiene que lidiar con el reemplazo.

Puede facilitarle la vida utilizando una de nuestras bibliotecas OP_RETURN:

El código también le mostrará exactamente cómo se hace.

http://digitalcommons.augustana.edu/cscfaculty/1/

Artículo académico que describe los diferentes métodos de inserción de datos para la cadena de bloques de Bitcoin.