Comment j'ai conçu des blocs et des transactions sur ma blockchain Go

Afin de produire à terme une blockchain, et pas seulement une base de données, nous devons ajouter 3 éléments importants à notre projet:

  • Description de la structure des données et des méthodes de bloc
  • Description de la structure des données et des méthodes de transaction
  • Fonctions de blockchain qui enregistrent les blocs dans la base de données et les y trouvent par leur hachage ou leur hauteur (ou autre chose).

image

Ceci est le deuxième article sur la blockchain pour l'industrie, le premier ici .

Rappelant les questions que les lecteurs m'ont posées dans l'article précédent de cette série, il convient de noter: dans ce cas, la base de données LevelDB est utilisée pour stocker les données de la blockchain, mais elle n'interfère pas avec l'utilisation d'autres, disons le même MySQL. Et maintenant, nous allons comprendre la structure de ces données.

Commençons par les transactions: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Voici sa structure de données:

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 stocke le type de données (pour la transaction 2), le hachage de cette transaction, le type de transaction lui-même, l'horodatage, ainsi que les entrées et sorties. Les entrées TxIn stockent le hachage de la transaction à laquelle la sortie est référencée, le numéro de cette sortie et le bytecode, et les sorties TxOut stockent une certaine valeur ainsi que le bytecode.

Voyons maintenant quelles actions une transaction peut effectuer sur ses données, c'est-à-dire analysons les méthodes.

Pour créer une transaction, utilisez la fonction transaction.NewTransaction (txtype byte) * TX.

La méthode AddTxIn (thattxhash [] octet, txoutn int, code [] octet) (* TxIn, erreur) ajoute l'entrée à la transaction.

La méthode AddTxOut (value int, data [] byte) (* TxOut, error) ajoute la sortie à la transaction.

La méthode d'octets ToBytes () [] transforme une transaction en une tranche d'octets.

La fonction interne preByteHash (octets [] octets) est utilisée dans Build () et Check () pour la compatibilité du hachage de transaction créé avec les hachages de transaction générés à partir d'applications JavaScript.

La méthode Build () définit le hachage de transaction comme suit: tx.TxHash = preByteHash (tx.ToBytes ()).

La méthode ToJSON () d'une chaîne convertit une transaction en chaîne JSON.

La méthode d'erreur FromJSON (data [] byte) charge une transaction à partir du format JSON transmis sous forme de tranche d'octets.

La méthode booléenne Check () compare le hachage reçu du champ de hachage de la transaction avec le hachage obtenu à la suite du hachage de cette transaction (à l'exclusion du champ de hachage).

Les transactions sont ajoutées au bloc: github.com/Rusldv/bcstartup/blob/master/block/builder.go

La structure de données du bloc est plus volumineuse:

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 stocke un type de données, un nœud sur celui-ci et détache le bloc d'une transaction ou d'autres données. Pour un bloc, cette valeur est 1.

BlockHeight stocke la hauteur du bloc.
Horodatage horodatage.
Taille du bloc HeaderSize en octets.
PrevBlockHash hachage du bloc précédent et SelfBlockHash - le courant.
TxsHash est un hachage de transaction commun.
MerkleRoot - La racine de l'arbre Merkle.

Ensuite, dans les champs, la clé publique du créateur du bloc, la signature du créateur, la version du bloc, le nombre de transactions dans le bloc et ces transactions elles-mêmes.

Considérez ses méthodes:
La fonction block.NewBlock () est utilisée pour créer un bloc: NewBlock (chaîne prevBlockHash, height int) * Block, qui accepte le hachage du bloc précédent et la hauteur définie pour le bloc créé dans la blockchain. Le type de bloc de la constante du package types est également défini:
b.DataType = types.BLOCK_TYPE.


La méthode AddTx (tx * transaction.TX) ajoute une transaction au bloc.

La méthode Build () charge les valeurs dans les champs du bloc et génère et définit son hachage actuel.

La méthode d'octets ToBytesHeader () [] traduit l'en-tête de bloc (sans transactions) en une tranche d'octets.

La méthode ToJSON () de la chaîne traduit le bloc au format JSON dans la représentation sous forme de chaîne des données.

La méthode d'erreur FromJSON (data [] byte) charge les données de JSON dans la structure de bloc.

La méthode booléenne Check () génère un hachage de bloc et le compare à celui du champ de hachage de bloc.

La méthode de chaîne GetTxsHash () renvoie le hachage commun de toutes les transactions dans le bloc.

La méthode GetMerkleRoot () définit la racine de l'arborescence Merkle pour les transactions dans le bloc.

La méthode Sign (privk string) signe le bloc avec la clé privée du créateur du bloc.

La méthode SetHeight (height int) écrit la hauteur du bloc dans le champ de structure du bloc.

La méthode GetHeight () int renvoie la hauteur du bloc comme indiqué dans le champ correspondant de la structure du bloc.

La méthode d'octets ToGOBBytes () [] code le bloc au format GOB et le renvoie sous forme de tranche d'octets.

La méthode d'erreur FromGOBBytes (data [] byte) écrit des données de bloc dans la structure de bloc à partir de la tranche d'octets transmise au format GOB.

La chaîne de méthode GetHash () renvoie le hachage de ce bloc.

La chaîne de méthode GetPrevHash () renvoie le hachage du bloc précédent.

La méthode SetPublicKey (chaîne pubk) écrit la clé publique du créateur de bloc dans le bloc.

Ainsi, en utilisant les méthodes de l'objet Block, nous pouvons facilement le convertir en un format pour la transmission sur le réseau et l'enregistrer dans la base de données LevelDB.

Les fonctions du package blockchain sont responsables de l'enregistrement dans la blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

Pour cela, le bloc doit implémenter l'interface IBlock:

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

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

}

Une connexion à la base de données est créée une fois lors de l'initialisation du package dans la fonction init ():
db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB () est un wrapper pour db.Cloce () - appelé après avoir travaillé avec les fonctions du package pour fermer la connexion à la base de données.

La fonction d'erreur SetTargetBlockHash (chaîne de hachage) écrit le hachage du bloc actuel avec la clé spécifiée par la constante BLOCK_HASH dans la base de données.

La fonction GetTargetBlockHash () (chaîne, erreur) renvoie le hachage du bloc actuel stocké dans la base de données.

La fonction d'erreur SetTargetBlockHeight (height int) écrit dans la base de données la valeur de la hauteur de la chaîne de blocs pour le nœud avec la clé spécifiée par la constante BLOCK_HEIGHT.

La fonction GetTargetBlockHeight () (int, erreur) renvoie la hauteur de la chaîne de blocs pour un nœud donné stocké dans la base de données.

La fonction bool CheckBlock (bloc IBlock) vérifie l'exactitude du bloc avant d'ajouter ce bloc à la blockchain.

La fonction d'erreur AddBlock (block IBlock) ajoute un bloc à la blockchain.

Les fonctions de réception et de visualisation des blocs se trouvent dans le fichier explore.go du package blockchain:

la fonction GetBlockByHash (chaîne de hachage) (* block.Block, erreur) crée un objet bloc vide, charge un bloc de la base de données dont le hachage lui est transmis et lui renvoie un pointeur.

Le bloc genesis est créé par la fonction d'erreur Genesis () du fichier genesis.go du package blockchain.

Dans le prochain article, nous parlerons de la connexion à un nœud client à l'aide du mécanisme WebSocket.

All Articles