Wie löse ich einen Basis-Tx ein?

Bei einem rohen Standard-Tx ( Wiki ):

01000000

01
26c07ece0bce7cda0ccd14d99e205f118cde27e83dd75da7b141fe487b5528fb
00000000
8b
48304502202b7e37831273d74c8b5b1956c23e79acd660635a8d1063d413c50b218eb6bc8a022100a10a3a7b5aaa0f07827207daf81f718f51eeac96695cf1ef9f2020f21a0de02f01410452684bce6797a0a50d028e9632be0c2a7e5031b710972c2a3285520fb29fcd4ecfb5fc2bf86a1e7578e4f8a305eeb341d1c6fc0173e5837e2d3c7b178aade078
ffffffff

02

b06c191e01000000
19
76a9143564a74f9ddb4372301c49154605573d7d1a88fe88ac

00e1f50500000000
19
76a914010966776006953d5567439e5e39f86a0d273bee88ac
00000000

und ein privater Schlüssel:

18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725

Wie konstruiert man eine neue Transaktion, um die Münze aus der zweiten Ausgabe einzulösen? Ich habe lange versucht, dies anhand des Diagramms von etotheipi herauszufinden , kann aber anscheinend nicht verstehen, wie eine ordnungsgemäße Transaktion erstellt werden soll. Eine Schritt-für-Schritt-Anleitung wäre wünschenswert.

in bitcoind, I used the resulting hex to do this signrawtransaction '0100000001eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2010000008a4730440220359f19e3d19dd707053641ff1efd0ca25159d0e0a8cbe13cbdcf38a9608c38ee02207383ebc663253a21101597ed897366e2a748ab29c18a8ca183d02910283e88cc01410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6ffffffff01605af405000000001976a914097072524438d003d23a2f23edb65aae1bb3e46988ac00000000' '[]' '[]' And it returned me 'false' ... I think there is a problem with the code ?
@Daniel, ich bin mir nicht sicher, aber das könnte daran liegen, dass Bitcoin signrawtransaction eine echte vorherige Ausgabetransaktion in der Blockchain erfordert, um die Mittel zu berechnen? Der Hash für die in dieser Frage angegebene Transaktion ist f2b3eb2deb76566e7324307cd47c35eeb88413f971d88519859b1834307ecfec, von dem blockexplorer.com sagt, dass er nicht existiert
@mulllhausen Wie wurde das gemacht, wenn die txid falsch ist?

Antworten (3)

In dieser Antwort werde ich die Schritte durchgehen, die zum Einlösen der zweiten Ausgabe der oben aufgeführten Transaktion erforderlich sind. Die Antwort beschränkt sich auf das Einlösen einer Ausgabe des bestimmten Typs, der in dieser Transaktion vorhanden ist (eine Ausgabe, die die Bereitstellung einer neuen Transaktion erfordert, die mit einem privaten Schlüssel signiert ist, dessen entsprechender öffentlicher Schlüssel mit dem Hash im Skript der betreffenden Ausgabe gehasht wird). Diese Antwort ist schon ziemlich lang, auch ohne Berücksichtigung anderer Ausgabetypen.

Kurze Zusammenfassung: Wir beginnen mit dem Aufbau einer neuen Transaktion mit einer scriptSig, die den scriptPubKey der Ausgabe enthält, die wir einlösen möchten. Der scriptPubKey dieser Transaktion enthält ein Skript, das an einen Hash eines öffentlichen Schlüssels (Bitcoin-Adresse) zahlt. Wir führen für diese Transaktion einen doppelten SHA256-Hash durch, wobei am Ende der 4-Byte-Hashcodetyp SIGHASH_ALL angehängt wird. Wir signieren diesen Hash mit dem oben angegebenen privaten Schlüssel. Die scriptSig dieser neuen Transaktion wird dann durch ein Skript ersetzt, das zuerst die DER-codierte Signatur plus den Ein-Byte-Hashcodetyp SIGHASH_ALL auf den Stack schiebt, gefolgt von dem entsprechenden öffentlichen Schlüssel des DER-codierten privaten Schlüssels.

Schritt-für-Schritt-Beschreibung:

Wir beginnen mit der Erstellung einer neuen Rohtransaktion, die wir hashen und signieren.

  1. Vier-Byte-Versionsfeld hinzufügen:01000000
  2. Ein-Byte-Variante, die die Anzahl der Eingänge angibt:01
  3. 32-Byte-Hash der Transaktion, von der wir eine Ausgabe einlösen möchten:eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2
  4. Vier-Byte-Feld, das den Ausgabeindex angibt, den wir aus der Transaktion mit dem obigen Hash einlösen möchten (Ausgabenummer 2 = Ausgabeindex 1):01000000
  5. Jetzt kommt die scriptSig. Diese wird zwecks Signierung der Transaktion temporär mit dem scriptPubKey der einzulösenden Ausgabe gefüllt. Zuerst schreiben wir eine Ein-Byte-Variante, die die Länge der scriptSig angibt (0x19 = 25 Bytes):19
  6. Dann schreiben wir die temporäre scriptSig, die wiederum der scriptPubKey der Ausgabe ist, die wir einlösen möchten:76a914010966776006953d5567439e5e39f86a0d273bee88ac
  7. Dann schreiben wir ein Vier-Byte-Feld, das die Sequenz bezeichnet. Diese ist aktuell immer auf 0xffffffff gesetzt:ffffffff
  8. Als nächstes kommt eine Ein-Byte-Variante, die die Anzahl der Ausgaben in unserer neuen Transaktion enthält. Wir werden dies in diesem Beispiel auf 1 setzen:01
  9. Wir schreiben dann ein 8-Byte-Feld (64-Bit-Integer), das den Betrag enthält, den wir von der angegebenen Ausgabe einlösen möchten. Ich werde dies auf den Gesamtbetrag setzen, der in der Ausgabe verfügbar ist, abzüglich einer Gebühr von 0,001 BTC (0,999 BTC oder 99900000 Satoshis):605af40500000000
  10. Dann beginnen wir mit dem Schreiben der Ausgabe unserer Transaktion. Wir beginnen mit einer Ein-Byte-Variante, die die Länge des Ausgabeskripts angibt (0x19 oder 25 Bytes):19
  11. Dann das eigentliche Ausgabeskript:76a914097072524438d003d23a2f23edb65aae1bb3e46988ac
  12. Dann schreiben wir das Vier-Byte-Feld "Sperrzeit":00000000
  13. Und zum Schluss schreiben wir einen vier Byte langen „Hash-Code-Typ“ (in unserem Fall 1):01000000

    Wir haben jetzt die folgenden rohen Transaktionsdaten:

    01000000
    01
    eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2
    01000000
    19
    76a914010966776006953d5567439e5e39f86a0d273bee88ac
    ffffffff
    01
    605af40500000000
    19
    76a914097072524438d003d23a2f23edb65aae1bb3e46988ac
    00000000
    01000000
    
  14. (Signierungsphase) Jetzt hashen wir diese gesamte Struktur doppelt mit SHA256, was den Hash ergibt9302bda273a887cb40c13e02a50b4071a31fd3aae3ae04021b0b843dd61ad18e

  15. Wir erstellen dann aus dem bereitgestellten privaten Schlüssel ein öffentliches/privates Schlüsselpaar. Wir signieren den Hash aus Schritt 14 mit dem privaten Schlüssel, was die folgende DER-codierte Signatur ergibt (diese Signatur wird in Ihrem Fall anders sein): 30460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc06An diese Signatur hängen wir den Ein-Byte-Hash-Codetyp an: 01. Der öffentliche Schlüssel lautet:0450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
  16. Wir konstruieren das endgültige scriptSig durch Verketten:

    • Ein-Byte-Skript-OPCODE, das die Länge der DER-codierten Signatur plus 1 enthält (die Länge des Ein-Byte-Hashcodetyps)
    • Die tatsächliche DER-codierte Signatur plus den Ein-Byte-Hashcodetyp
    • Ein-Byte-Skript OPCODE, das die Länge des öffentlichen Schlüssels enthält
    • Der eigentliche öffentliche Schlüssel
  17. Wir ersetzen dann das Ein-Byte-Variant-Längenfeld aus Schritt 5 durch die Länge der Daten aus Schritt 16. Die Länge beträgt 140 Bytes oder 0x8C-Bytes:8c

  18. Und wir ersetzen das temporäre scriptSig aus Schritt 6 durch die in Schritt 16 erstellte Datenstruktur. Dies wird zu:4930460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc0601410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
  19. Zum Schluss entfernen wir den 4-Byte-Hashcodetyp, den wir in Schritt 13 hinzugefügt haben, und erhalten am Ende den folgenden Bytestrom, der die letzte Transaktion darstellt:

    01000000
    01
    eccf7e3034189b851985d871f91384b8ee357cd47c3024736e5676eb2debb3f2
    01000000
    8c
    4930460221009e0339f72c793a89e664a8a932df073962a3f84eda0bd9e02084a6a9567f75aa022100bd9cbaca2e5ec195751efdfac164b76250b1e21302e51ca86dd7ebd7020cdc0601410450863ad64a87ae8a2fe83c1af1a8403cb53f53e486d8511dad8a04887e5b23522cd470243453a299fa9e77237716103abc11a1df38855ed6f2ee187e9c582ba6
    ffffffff
    01
    605af40500000000
    19
    76a914097072524438d003d23a2f23edb65aae1bb3e46988ac
    00000000
    

Python-Beispielcode:

Ich habe ein Beispiel-Python-Skript erstellt, das alle oben genannten Aufgaben erfüllt. Es ist absichtlich so ausführlich wie möglich und stark kommentiert, mit so wenigen Funktionen wie möglich, um der obigen Schritt-für-Schritt-Anleitung zu ähneln. Die Anzahl der Codezeilen kann leicht auf die Hälfte reduziert werden, aber ich entscheide mich dafür, es in diesem ausführlichen Format zu posten, da ich beurteile, dass es am einfachsten zu befolgen ist (dh kein Hin- und Herspringen durch Funktionen). Das Skript enthält 76 nicht leere Zeilen ohne Kommentar. Das Skript hängt von bitcointools (zum Serialisieren und Deserialisieren von Transaktionen und base58-Codierung/Decodierung) und ecdsa_ssl.py abaus meinem Fork von Jorics Brutus-Repository (zum Erstellen öffentlicher/privater EC-Schlüsselpaare und ECDSA-Signierung). Der einfachste Weg, das Skript zum Ausführen zu bringen, besteht darin, bitcointools in einen Ordner zu klonen und ecdsa_ssl.py von der obigen URL zusammen mit diesem Skript in denselben Ordner zu legen und das Skript von dort aus auszuführen. Sie sollten die Adresse in der SEND_TO_ADDRESSVariablen in diesem Skript durch die Adresse ersetzen, an die die Münzen gesendet werden sollen, es sei denn, Sie fühlen sich großzügig :).

#bitcointools
von deserialisieren import parse_Transaction, opcodes
aus BCDataStream importieren BCDataStream
aus base58 import bc_address_to_hash_160, b58decode, public_key_to_bc_address, hash_160_to_bc_address

ecdsa_ssl importieren

Importieren Sie Crypto.Hash.SHA256 als sha256
Importieren Sie Crypto.Random

#transaktion, von der wir eine Ausgabe einlösen wollen
HEX_TRANSACTION="010000000126c07ece0bce7cda0ccd14d99e205f118cde27e83dd75da7b141fe487b5528fb000000008b48304502202b7e37831273d74c8b5b1956c23e79acd660635a8d1063d413c50b218eb6bc8a022100a10a3a7b5aaa0f07827207daf81f718f51eeac96695cf1ef9f2020f21a0de02f01410452684bce6797a0a50d028e9632be0c2a7e5031b710972c2a3285520fb29fcd4ecfb5fc2bf86a1e7578e4f8a305eeb341d1c6fc0173e5837e2d3c7b178aade078ffffffff02b06c191e010000001976a9143564a74f9ddb4372301c49154605573d7d1a88fe88ac00e1f505000000001976a914010966776006953d5567439e5e39f86a0d273bee88ac00000000"
#Ausgabe zum Einlösen. muss in HEX_TRANSACTION vorhanden sein
AUSGABE_INDEX=1
#Adresse an die wir die eingelösten Coins senden wollen.
#ERSETZEN SIE DURCH IHRE EIGENE ADRESSE, es sei denn, Sie sind großzügig
SEND_TO_ADDRESS="1L4xtXCdJNiYnyqE6UsB8KSJvqEuXjz6aK"
#Gebühr, die wir zahlen möchten (in BTC)
TX_GEBÜHR=0,001
#Konstante, die die Anzahl der Satoshis pro BTC definiert
MÜNZE = 100000000
#constant wird verwendet, um zu bestimmen, welcher Teil der Transaktion gehasht wird.
SIGHASH_ALL=1
#Privater Schlüssel, dessen öffentlicher Schlüssel mit dem Hash gehasht wird, der in scriptPubKey der Ausgabenummer *OUTPUT_INDEX* in der in HEX_TRANSACTION beschriebenen Transaktion enthalten ist
PRIVATE_KEY=0x18E14A7B6A307F426A94F8114701E7C8E774E7F9A47E2C2035DB29A206321725

def dsha256 (Daten):
   Rückgabe sha256.new(sha256.new(data).digest()).digest()

tx_data=HEX_TRANSACTION.decode('hex_codec')
tx_hash=dsha256(tx_data)

#hier verwenden wir bitcointools, um eine Transaktion zu parsen. Dies ermöglicht einen einfachen Zugriff auf die verschiedenen Felder der Transaktion, aus der wir eine Ausgabe einlösen möchten
stream = BCDataStream()
stream.write(tx_data)
tx_info = parse_Transaction(stream)

if len(tx_info['txOut']) < (OUTPUT_INDEX+1):
   heben Sie RuntimeError auf, "es gibt nur %d Ausgabe(n) in der Transaktion, von der Sie versuchen einzulösen. Sie möchten den Ausgabeindex %d einlösen" % (len(tx_info['txOut']), OUTPUT_INDEX)

#dieses Wörterbuch wird verwendet, um die Werte der verschiedenen Transaktionsfelder zu speichern
# Dies ist nützlich, da wir eine Transaktion zum Hashen und Signieren erstellen müssen
# und eine weitere, die die letzte Transaktion sein wird
tx_fields = {}

##Hier beginnen wir mit der Erstellung der Transaktion, die wir hashen und signieren
sign_tx = BCDataStream()
##Zuerst schreiben wir die Versionsnummer, die 1 ist
tx_fields['Version'] = 1
sign_tx.write_int32(tx_fields['Version'])
## dann schreiben wir die Anzahl der Transaktionseingaben, die eins ist
tx_fields['num_txin'] = 1
sign_tx.write_compact_size(tx_fields['num_txin'])

##dann schreiben wir die eigentlichen Transaktionsdaten
#'prevout_hash'
tx_fields['prevout_hash'] = tx_hash
sign_tx.write(tx_fields['prevout_hash']) #Hash der Transaktion, von der wir eine Ausgabe einlösen möchten
#'prevout_n'
tx_fields['output_index'] = OUTPUT_INDEX
sign_tx.write_uint32(tx_fields['output_index']) #welche Ausgabe der Transaktion mit der TX-ID 'prevout_hash' wollen wir einlösen?

##Als nächstes kommt der Teil der Transaktionseingabe. Hier platzieren wir das Skript der *Ausgabe*, die wir einlösen möchten
tx_fields['scriptSigHash'] = tx_info['txOut'][OUTPUT_INDEX]['scriptPubKey']
#schreibe zuerst die Größe
sign_tx.write_compact_size(len(tx_fields['scriptSigHash']))
#dann die Daten
sign_tx.write(tx_fields['scriptSigHash'])

#'Reihenfolge'
tx_fields['sequenz'] = 0xffffffff
sign_tx.write_uint32(tx_fields['sequenz'])

##dann schreiben wir die Anzahl der Transaktionsausgaben. In diesem Beispiel verwenden wir nur eine einzige Ausgabe
tx_fields['num_txout'] = 1
sign_tx.write_compact_size(tx_fields['num_txout'])
##dann schreiben wir die eigentlichen Transaktionsausgabedaten
#wir lösen alles von der ursprünglichen Ausgabe abzüglich TX_FEE ein
tx_fields['value'] = tx_info['txOut'][OUTPUT_INDEX]['value']-(TX_FEE*COIN)
sign_tx.write_int64(tx_fields['Wert'])
##Hier geht unser scriptPubKey hin (ein Skript, das an eine Adresse auszahlt)
#Wir wollen das folgende Skript:
#"OP_DUP OP_HASH160 OP_EQUALVERIFY OP_CHECKSIG"
address_hash = bc_address_to_hash_160(SEND_TO_ADDRESS)
#chr(20) ist die Länge des address_hash (20 Byte oder 160 Bit)
scriptPubKey = chr(opcodes.OP_DUP) + chr(opcodes.OP_HASH160) + \
   chr(20) + address_hash + chr(opcodes.OP_EQUALVERIFY) + chr(opcodes.OP_CHECKSIG)
#schreiben Sie zuerst die Länge dieses Datenpakets
tx_fields['scriptPubKey'] = scriptPubKey
sign_tx.write_compact_size(len(tx_fields['scriptPubKey']))
#dann die Daten
sign_tx.write(tx_fields['scriptPubKey'])

#Sperrzeit schreiben (0)
tx_fields['Sperrzeit'] = 0
sign_tx.write_uint32(tx_fields['locktime'])
#und Hashcodetyp (1)
tx_fields['hash_type'] = SIGHASH_ALL
sign_tx.write_int32(tx_fields['hash_type'])

#dann erhalten wir den Hash der signaturlosen Transaktion (den Hash, den wir mit unserem privaten Schlüssel signieren)
hash_scriptless = dsha256(sign_tx.input)

## Jetzt beginnen wir mit dem ECDSA-Zeug.
## Wir erstellen einen privaten Schlüssel aus den bereitgestellten privaten Schlüsseldaten und signieren hash_scriptless damit
## prüfen wir auch, ob der entsprechende öffentliche Schlüssel des privaten Schlüssels die angegebene Ausgabe tatsächlich einlösen kann

k = ecdsa_ssl.KEY()
k.generate(('%064x' % PRIVATE_KEY).decode('hex'))

#hier rufen wir die öffentlichen Schlüsseldaten ab, die aus dem bereitgestellten privaten Schlüssel generiert wurden
pubkey_data = k.get_pubkey()
#dann erstellen wir eine Signatur über den Hash der signaturlosen Transaktion
sig_data=k.sign(hash_scriptless)
#ein Ein-Byte-Hash-Typ wird an das Ende der Signatur angehängt (https://en.bitcoin.it/wiki/OP_CHECKSIG)
sig_data = sig_data + chr(SIGHASH_ALL)

#Überprüfen wir, ob der bereitgestellte private Schlüssel die betreffende Ausgabe tatsächlich einlösen kann
if (bc_address_to_hash_160(public_key_to_bc_address(pubkey_data)) != tx_info['txOut'][OUTPUT_INDEX]['scriptPubKey'][3:-2]):
   Bytes = b58decode (SEND_TO_ADDRESS, 25)
   raise RuntimeError, "Der bereitgestellte private Schlüssel kann nicht verwendet werden, um den Ausgabeindex %d einzulösen\nSie müssen den privaten Schlüssel für die Adresse %s angeben" % \
                           (OUTPUT_INDEX, hash_160_to_bc_address(tx_info['txOut'][OUTPUT_INDEX]['scriptPubKey'][3:-2], bytes[0]))

## Jetzt beginnen wir mit der Erstellung der endgültigen Transaktion. dies ist ein Duplikat der signaturlosen Transaktion,
## mit dem scriptSig, das mit einem Skript ausgefüllt ist, das die Signatur plus den Ein-Byte-Hashcodetyp und den öffentlichen Schlüssel von oben auf den Stack überträgt

final_tx = BCDataStream()
final_tx.write_int32(tx_fields['Version'])
final_tx.write_compact_size(tx_fields['num_txin'])
final_tx.write(tx_fields['prevout_hash'])
final_tx.write_uint32(tx_fields['output_index'])

##Jetzt müssen wir die eigentliche scriptSig schreiben.
## dieser besteht aus den DER-codierten Werten r und s aus der Signatur, einem Ein-Byte-Hashcodetyp und dem öffentlichen Schlüssel in unkomprimierter Form
## müssen wir auch die Länge dieser beiden Datenstücke voranstellen (codiert als ein einzelnes Byte
## mit der Länge), vor jedem Datenstück. Diese Länge ist ein Skript-Opcode, der dies mitteilt
## Bitcoin-Skriptinterpreter, um die x folgenden Bytes auf den Stack zu schieben

scriptSig = chr(len(sig_data)) + sig_data + chr(len(pubkey_data)) + pubkey_data
#schreiben Sie zuerst die Länge dieser Daten
final_tx.write_compact_size(len(scriptSig))
#dann die Daten
final_tx.write(scriptSig)

##und dann schreiben wir einfach dieselben Daten nach der scriptSig, die in der signaturlosen Transaktion enthalten ist,
# Weglassen des Vier-Byte-Hash-Code-Typs (da dieser in dem einzelnen Byte nach den Signaturdaten codiert ist)

final_tx.write_uint32(tx_fields['sequenz'])
final_tx.write_compact_size(tx_fields['num_txout'])
final_tx.write_int64(tx_fields['Wert'])
final_tx.write_compact_size(len(tx_fields['scriptPubKey']))
final_tx.write(tx_fields['scriptPubKey'])
final_tx.write_uint32(tx_fields['locktime'])

# gibt die letzte Transaktion im Hex-Format aus (kann als Argument für senddrawtransaction von bitcoind verwendet werden)
print final_tx.input.encode('hex')
Sind Sie sicher, dass Schritt 11 richtig ist? Es zeigt nur die Ursprungsadresse. Sollte das nicht ein Skript wie "OP_DUP OP_HASH160 destination_address_in_hash_160_format OP_EQUALVERIFY OP_CHECKSIG" sein? Wobei OP_DUP durch "76" usw. ersetzt wird, wie hier beschrieben .
Ich stecke bei Schritt 15 fest... Irgendeine Idee, was ich falsch mache? bitcoin.stackexchange.com/questions/10784/…
In Bezug auf meinen ersten Kommentar ist mir gerade aufgefallen, dass die Adresse tatsächlich in 76 a9 und 88 ac verpackt ist. Es schickt also alles zurück zum Ursprung.
Nein, es schickt es nicht zurück, es schickt es an 1runeksijzfVxyrpiyCY2LCBvYsSiFsCm.
@SjorsProvoost Wie erwähnt, löst das Skript die Ausgabenummer OUTPUT_INDEX aus der im Hexadezimalformat beschriebenen Transaktion in HEX_TRANSACTION ein und sendet sie an die in SEND_TO_ADDRESS enthaltene Adresse.
Verzeihen Sie meinen Mangel an Wissen, aber ist es normal, dass das Skript jedes Mal, wenn es ausgeführt wird, andere Ergebnisse liefert? Ich wusste nicht, dass beim Erstellen einer Überweisung eine Zufallszahlengenerierung erforderlich ist (?)
@Daniel Ja. ECDSA-Signaturen erfordern eine Zufallszahl. Schlimme Dinge passieren, wenn es nicht zufällig ist.
Wenn Sie eine Transaktion mit mehreren Eingaben einlösen möchten, wie generieren Sie den Hash, den Sie für jede Eingabe signieren müssen? Ist es für alle derselbe Hash?
@runeks > "[...] ersetzen Sie die Adresse in der SEND_TO_ADDRESS-Variablen [...] es sei denn, Sie fühlen sich großzügig :)" Nur für die Aufzeichnungen, es scheint, dass sich mehrere Seelen großzügig fühlten, nachdem sie Ihre Antwort gelesen hatten. Es ist erstaunlich, wie stark Bitcoin ist.
Was k.generate(('%064x' % PRIVATE_KEY).decode('hex'))tut? Soll ich etwas aus dem privaten Schlüssel generieren und damit signieren, oder signiere ich einfach mit dem privaten Schlüssel?
Der "Generate"-Schritt generiert ein privates Schlüsselobjekt aus den Hex-Daten in PRIVATE_KEY. Im Wesentlichen werden also nur 32 Bytes hexadezimal codierter Daten in einen privaten Schlüssel geparst.
Ergänzend zu der eleganten Lösung von Runeks: Bei mehreren Eingaben (was ziemlich häufig vorkommt) konstruieren wir zwei verschiedene tx, die sich von Schritt 1-13 wiederholen. Im ersten tx behalten wir Eingang 2 als 00 und im zweiten tx behalten wir Eingang 1 als 00. Dann signieren wir beide tx und ersetzen sie in den beiden Eingängen, wodurch 2 Eingänge und Ausgänge mit Vorzeichen tx generiert werden.
Punkt 3 ist in Little Endian
Gavins bitcointools sind seit mindestens November 2017 tot. Runeks hat einen indirekten Fork unter github.com/runeksvendsen/bitcointools , der wie erforderlich zu funktionieren scheint.
@blockwala was meinst du mit '00' in einer bestimmten Eingabe? Ersetzen Sie einfach die Skriptsignatur oder ersetzen Sie die gesamte Eingabestruktur (vorheriger TX-Hash, vorheriger Ausgabeindex, Skriptlänge und Skriptsignatur und -sequenz)?

Dieser Kern , der teilweise auf der Antwort von Runeks basiert, zeigt, wie man 0,01 Bitcoins in Ruby überträgt. Es ruft Informationen aus der vorherigen Transaktion von Blockchain.info ab, sodass Sie ihm nur Ihren privaten Schlüssel und Ihre Adresse zuführen müssen (letzteres ist redundant, aber nützlich für die Demonstration). Ich habe viele Kommentare hinzugefügt, um die Schritte zu erklären.

Sobald Sie die Transaktions-ID, den vout, den scriptPubKey dieser Transaktion und den WIF-codierten privaten Schlüssel kennen, der dem gehashten öffentlichen Schlüssel entspricht, um die Adresse zu erhalten, können Sie eine Rohtransaktion erstellen und signieren, ohne online zu sein.

Ich habe eine PHP-Bibliothek geschrieben, um mit Rohtransaktionen umzugehen (neben anderen Bitcoin-Funktionen). So würden Sie eine reguläre Transaktion einlösen: https://github.com/Bit-Wasp/bitcoin-lib-php Es ist ein Update erforderlich, um P2SH-Signaturen zu unterstützen, aber eine reguläre Transaktion wird problemlos eingelöst.