Was ist eine Schritt-für-Schritt-Anleitung zum Einfügen von Daten in OP_RETURN?

Ich bin https://bitcointalk.org/index.php?topic=453086.0 gefolgt, um eine Nachricht in OP_RETURN zu erstellen. Ich kann meine Rohtransaktion entschlüsseln, aber bei signrawtransaction gibt es sie

error: {"code":-22,"message":"TX-Decodierung fehlgeschlagen"}

Ich habe die Adresse validiert, gibt es etwas, das in diesem Tutorial fehlt.

Der beste Weg wäre, den resultierenden TX zu posten. Sind die Daten, die Sie einbetten, kleiner als 40 Byte?
Danke Matthieu, du hattest Recht mit der Größe. Aber ich musste noch mehr Schritte machen. Also war auf der Suche nach einem kompletten Step by Step.
Ich habe diese Meldung erhalten, als ich vergessen hatte, die ursprüngliche Skriptlänge durch die neue für meinen OP_RETURN-Hex-String zu ersetzen.

Antworten (3)

Ich habe ein kleines Demoprogramm geschrieben, das einen Datenausschnitt in ein OP_RETURN-Skript einfügt. Es erfordert eine Bitcoin-Instanz, die RPC-Verbindungen akzeptiert, obwohl es auch ohne diese implementiert werden könnte. Sie finden es hier auf github . Es wurde getestet, aber nur auf Testnet. Ich werde den Code durchgehen und erklären, was er tut.

Anfang

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

Dadurch wird die Protokollierung ausführlicher. Es ist praktisch, weil es zeigt, welche RPC-Aufrufe getätigt werden.

Verbinden Sie sich mit Bitcoin

rpc_user = "bitcoinrpc"
rpc_password = "87Y9A2gs25E9HDPGc9axqSqzxMR2MyTtrMkYc5KiZk2Z"

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

Beachten Sie, dass Ihr Passwort anders sein wird und dass Sie Port 8332 für Mainnet anstelle von Port 18332 verwenden.

Nicht ausgegebene Ausgaben auflisten

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

Der - Decimal("0.005")Teil ist so, dass wir eine Transaktionsgebühr zahlen.

Transaktion erstellen

# 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"

Dies sind zwei unterschiedliche Kodierungen eines Pay to Public Key Hash aus lauter Nullen. Die obere ist die Mainnet-Darstellung und die untere die Testnet-Darstellung.

# My change address
change_address = "mhZuYnuMCZLjZKeDMnY48xsR5qkjq7bAr9"

Denken Sie daran, dies ist meine Änderungsadresse. Wenn Sie es nicht ändern, schicken Sie mir Geld.

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

Und jetzt haben wir eine tatsächliche Transaktion. Es enthält jedoch keine unserer eigenen Daten, also müssen wir das beheben.

Ersetzen Sie die Dummy-Ausgabe durch unsere eigene Ausgabe

# 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"

Das ist ein kleiner Hack. Anstatt unsere eigene Ausgabe zu erstellen, erstellen wir eine Dummy-Ausgabe, suchen dann nach dem Muster, das sie erzeugt, und ersetzen sie. Es gibt wahrscheinlich einen besseren Weg, dies zu tun, aber das scheint am einfachsten zu sein.

# 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)

Als nächstes erstellen wir die Daten, die wir in die Blockchain einfügen möchten. Ich verwende die Zeichenfolge Melons., aber Sie könnten alles verwenden. (Über 40 Bytes ist jedoch kein Standard.) Ich habe das meiste davon in meiner anderen Antwort behandelt .

Dieser Code bricht, wenn die Daten länger als 75 Byte sind. Wenn Sie es für mehr als das brauchen, können Sie OP_PUSHDATA1 anstelle der Single-Byte-Pushdata verwenden, die ich hier verwende.

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

Dieser Teil unterscheidet sich ein wenig von meiner anderen Antwort, da wir auch die Länge des scriptPubKey angeben müssen. Dieser Code bricht bei Daten, die länger als 251 Bytes sind. Wenn Sie möchten, dass es länger an Daten arbeitet, codieren Sie eine Variante richtig.

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

Fehler bei der Überprüfung dieser sehr wackeligen Methode.

tx = tx.replace(oldScriptPubKey, newScriptPubKey)

Schließlich tauscht ein String-Replace das neue Skript gegen das alte aus.

Unterschreib es

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

Bitcoin übernimmt hier das wuchtige Heben.

Senden Sie es an das Netzwerk.

rpc.sendrawtransaction(tx)

Fertig! Warten Sie jetzt einfach, bis Ihre Transaktion in einen Block gelangt.

Ich habe den Code ausgeführt ( Ausgabe ) und eine Transaktion erstellt, die Sie hier im Block Explorer sehen können . Wenn Sie die Zeichenfolge neben OP_RETURN kopieren und in einen Hex-zu-ASCII-Konverter einfügen , erhalten Sie ...

Melons.

Fertig!

Andere Ressourcen

Ich fand diese Webseite hilfreich, während ich dies schrieb.

Schön, da es sich um eine OP_RETURN-Skriptsig handelt (wenn ich das richtig verstehe), bedeutet das, dass der TX vom Netzwerk entfernt / ungültig gemacht wird?
@Valmond scriptsigscriptPubKey, eigentlich. does that mean the tx will be removed / invalidated by the network?Nicht wirklich. Es wird in einigen Clients aus dem Ausgabesatz für nicht ausgegebene Transaktionen entfernt, aber viele Clients werden sich immer noch daran erinnern. (Das müssen sie, weil sie neuen Kunden beweisen müssen, dass es sich nur um eine OP_RETURN-Transaktion handelt.)
Beachten Sie, dass die von Ihnen erstellte Transaktion keine Standardtransaktion im Mainnet wäre, da die Ausgabe von op_return einen Wert > 0 hat. Sie wird standardmäßig auf Testnet weitergeleitet/gemined, da Testnet standardmäßig fast alle Transaktionen akzeptiert.
@DavidA.Harding Ich habe das getan, weil createrawtransaction keinen Wert von 0 akzeptieren würde. Können Sie eine Quelle für diese Behauptung angeben? Ich kann keine solche Prüfung in Solver oder IsStandard finden.
@NickODell oh, Mistkerl --- du scheinst Recht zu haben; Ich gebe Leuten seit einem Jahr schlechte Ratschläge. Es tut uns leid.
Ich habe ein paar Fragen. 1. Wie haben Sie die Dummy-Adressen so genau berechnet? 2. Wenn ich eine echte Adresse als Dummy ( getnewaddress) eingebe und dann txhex = createrawtransaction. Dann bekomme ich das Skript hex durch decodedtx = decoderawtransaction txhexund oldScriptHex = decodedtx.scriptPubKey.hex. Dann txhex.replace(oldScriptHex, newScriptHex)und dieser Ansatz dekodiert nicht mehr (Code -22; TX-Dekodierung fehlgeschlagen). warum? newScriptHexist in deiner und meiner Version identisch.
Derzeit können Sie createrawtransactionmit einem voutLike verwenden {"data": "your hex data"}und müssen sich nicht um das Ersetzen kümmern.

Sie können sich das Leben leichter machen, indem Sie eine unserer OP_RETURN-Bibliotheken verwenden:

Der Code zeigt Ihnen auch genau, wie es gemacht wird.

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

Akademisches Papier, das die verschiedenen Methoden der Dateneinfügung für die Blockchain von Bitcoin beschreibt.