Wie ich Blöcke und Transaktionen in meiner Go-Blockchain entworfen habe

Um am Ende eine Blockchain und nicht nur eine Datenbank zu erhalten, müssen wir unserem Projekt drei wichtige Elemente hinzufügen:

  • Beschreibung der Blockdatenstruktur und -methoden
  • Beschreibung der Datenstruktur und Transaktionsmethoden
  • Blockchain-Funktionen, die Blöcke in einer Datenbank speichern und sie dort anhand ihres Hashs oder ihrer Höhe (oder etwas anderem) finden.

Wie ich Blöcke und Transaktionen in meiner Go-Blockchain entworfen habe

Dies ist der zweite Artikel über Blockchain für die Industrie, der erste hier.

Wenn ich mich an die Fragen erinnere, die mir die Leser zum vorherigen Artikel dieser Reihe gestellt haben, sollte darauf hingewiesen werden: In diesem Fall wird die LevelDB-Datenbank zum Speichern von Blockchain-Daten verwendet, aber nichts hindert Sie daran, ein anderes, beispielsweise MySQL, zu verwenden. Schauen wir uns nun die Struktur dieser Daten an.

Beginnen wir mit den Transaktionen: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Hier ist seine Datenstruktur:

type TX struct {
	DataType byte		
	TxHash string 
	TxType byte	
	Timestamp int64		
	INs []TxIn
	OUTs []TxOut
}

type TxIn struct {
	ThatTxHash string
	TxOutN int
	ByteCode string
}

type TxOut struct {
	Value int
	ByteCode string
}

TX speichert den Datentyp (für Transaktion 2), den Hash dieser Transaktion, den Typ der Transaktion selbst, einen Zeitstempel sowie Ein- und Ausgaben. TxIn-Eingaben speichern den Hash der Transaktion, auf deren Ausgabe verwiesen wird, die Nummer dieser Ausgabe und den Bytecode, und TxOut-Ausgaben speichern einen Wert und auch den Bytecode.

Sehen wir uns nun an, welche Aktionen eine Transaktion mit ihren Daten durchführen kann, d. h. Schauen wir uns die Methoden an.

Um eine Transaktion zu erstellen, verwenden Sie die Funktion „transaction.NewTransaction(txtype byte) *TX“.

Die Methode AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) fügt der Transaktion eine Eingabe hinzu.

Die Methode AddTxOut(value int, data []byte) (*TxOut, error) fügt der Transaktion eine Ausgabe hinzu.

Die ToBytes() []Byte-Methode wandelt die Transaktion in ein Byte-Slice um.

Die interne Funktion preByteHash(bytes []byte) string wird in Build() und Check() verwendet, um den generierten Transaktions-Hash kompatibel mit Transaktions-Hashes zu machen, die von JavaScript-Anwendungen generiert wurden.

Die Build()-Methode legt den Transaktions-Hash wie folgt fest: tx.TxHash = preByteHash(tx.ToBytes()).

Die String-Methode ToJSON() konvertiert eine Transaktion in einen JSON-String.

Die Fehlermethode FromJSON(data []byte) lädt eine Transaktion aus dem JSON-Format, das als Byte-Slice übergeben wird.

Die Bool-Methode Check() vergleicht den resultierenden Hash aus dem Transaktions-Hash-Feld mit dem Hash, der als Ergebnis des Hashings dieser Transaktion erhalten wird (wobei das Hash-Feld ignoriert wird).

Dem Block werden Transaktionen hinzugefügt: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Die Blockdatenstruktur ist umfangreicher:

type Block struct {
	DataType byte				
	BlockHeight int					
        Timestamp int64				 
        HeaderSize int					
        PrevBlockHash string				 
        SelfBlockHash string			
	TxsHash string			
	MerkleRoot string
	CreatorPublicKey string			
	CreatorSig string
	Version int
	TxsN int
	Txs []transaction.TX
}

DataType speichert den Datentyp, der Knoten verwendet ihn und unterscheidet den Block von einer Transaktion oder anderen Daten. Für einen Block ist dieser Wert 1.

BlockHeight speichert die Höhe des Blocks.
Zeitstempel.
HeaderSize ist die Blockgröße in Bytes.
PrevBlockHash ist der Hash des vorherigen Blocks und SelfBlockHash ist der Hash des aktuellen Blocks.
TxsHash ist ein allgemeiner Hash von Transaktionen.
MerkleRoot ist die Wurzel des Merkle-Baums.

Darüber hinaus finden sich in den Feldern der öffentliche Schlüssel des Erstellers des Blocks, die Signatur des Erstellers, die Version des Blocks, die Anzahl der Transaktionen im Block und diese Transaktionen selbst.

Schauen wir uns seine Methoden an:
Um einen Block zu erstellen, verwenden Sie die Funktion block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, die den Hash des vorherigen Blocks und die für den erstellten Block in der Blockchain festgelegte Höhe übernimmt. Der Blocktyp wird auch über die Typenpaketkonstante festgelegt:

b.DataType = types.BLOCK_TYPE.

Die Methode AddTx(tx *transaction.TX) fügt eine Transaktion zu einem Block hinzu.

Die Build()-Methode lädt Werte in die Felder des Blocks und generiert und legt seinen aktuellen Hash fest.

Die ToBytesHeader() []Byte-Methode wandelt den Blockheader (ohne Transaktionen) in ein Byte-Slice um.

Die String-Methode ToJSON() konvertiert den Block in eine String-Darstellung der Daten in das JSON-Format.

Die Fehlermethode FromJSON(data []byte) lädt Daten aus JSON in eine Blockstruktur.

Die Bool-Methode Check() generiert einen Block-Hash und vergleicht ihn mit dem im Block-Hash-Feld angegebenen Wert.

Die String-Methode GetTxsHash() gibt den Gesamt-Hash aller Transaktionen im Block zurück.

Die Methode GetMerkleRoot() gibt die Wurzel des Merkle-Baums für Transaktionen in einem Block an.

Die Methode Sign(privk string) signiert einen Block mit dem privaten Schlüssel des Blockerstellers.

Die Methode SetHeight(height int) schreibt die Höhe des Blocks in das Blockstrukturfeld.

Die Methode GetHeight() int gibt die Höhe des Blocks zurück, wie sie im entsprechenden Feld der Blockstruktur angegeben ist.

Die ToGOBBytes() []Byte-Methode kodiert einen Block im GOB-Format und gibt ihn als Byte-Slice zurück.

Die Fehlermethode FromGOBBytes(data []byte) schreibt Blockdaten aus dem übergebenen Byte-Slice im GOB-Format in die Blockstruktur.

Die String-Methode GetHash() gibt den Hash des angegebenen Blocks zurück.

Die String-Methode GetPrevHash() gibt den Hash des vorherigen Blocks zurück.

Die Methode SetPublicKey(pubk string) schreibt den öffentlichen Schlüssel des Blockerstellers in den Block.

Mithilfe der Methoden des Block-Objekts können wir es daher problemlos in ein Format für die Übertragung über das Netzwerk und das Speichern in der LevelDB-Datenbank konvertieren.

Für die Speicherung in der Blockchain sind die Funktionen des Blockchain-Pakets verantwortlich: github.com/Rusldv/bcstartup/tree/master/blockchain

Dazu muss der Block die IBlock-Schnittstelle implementieren:

type IGOBBytes interface {
	ToGOBBytes() []byte
	FromGOBBytes(data []byte) error
}

type IBlock interface {
	IGOBBytes
	GetHash() string
	GetPrevHash() string
	GetHeight() int
	Check() bool

}

Die Datenbankverbindung wird einmalig erstellt, wenn das Paket in der Funktion init() initialisiert wird:

db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB() ist ein Wrapper für db.Cloce() – wird aufgerufen, nachdem mit den Paketfunktionen gearbeitet wurde, um die Verbindung zur Datenbank zu schließen.

Die Fehlerfunktion SetTargetBlockHash(hash string) schreibt den Hash des aktuellen Blocks mit dem durch die BLOCK_HASH-Konstante angegebenen Schlüssel in die Datenbank.

Die Funktion GetTargetBlockHash() (string, error) gibt den Hash des aktuellen Blocks zurück, der in der Datenbank gespeichert ist.

Die Fehlerfunktion SetTargetBlockHeight(height int) schreibt den Wert der Blockchain-Höhe für den Knoten mit dem durch die BLOCK_HEIGHT-Konstante angegebenen Schlüssel in die Datenbank.

Die Funktion GetTargetBlockHeight() (int, error) gibt die Höhe der Blockchain für einen bestimmten Knoten zurück, die in der Datenbank gespeichert ist.

Die Bool-Funktion CheckBlock(block IBlock) prüft einen Block auf Korrektheit, bevor er diesen Block zur Blockchain hinzufügt.

Die Fehlerfunktion AddBlock(block IBlock) fügt der Blockchain einen Block hinzu.

Die Funktionen zum Abrufen und Anzeigen von Blöcken befinden sich in der Datei explore.go des Blockchain-Pakets:

Die Funktion GetBlockByHash(hash string) (*block.Block, error) erstellt ein leeres Blockobjekt, lädt einen Block aus der Datenbank hinein, dessen Hash an sie übergeben wurde, und gibt einen Zeiger darauf zurück.

Die Erstellung eines Genesis-Blocks erfolgt durch die Fehlerfunktion Genesis() aus der Datei genesis.go des Blockchain-Pakets.

Im nächsten Artikel geht es um die Verbindung zu einem Clientknoten mithilfe des WebSocket-Mechanismus.

Source: habr.com

Kommentar hinzufügen