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

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

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

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

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

En me souvenant des questions que les lecteurs m'ont posées à propos de 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 rien ne vous empêche d'en utiliser un autre, par exemple MySQL. Examinons maintenant 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 la transaction elle-même, un horodatage ainsi que les entrées et sorties. Les entrées TxIn stockent le hachage de la transaction dont la sortie est référencée, le numéro de cette sortie et le bytecode, et les sorties TxOut stockent une valeur ainsi que le bytecode.

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

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

La méthode AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) ajoute une entrée à la transaction.

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

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

La chaîne de fonction interne preByteHash(bytes []byte) est utilisée dans Build() et Check() pour rendre le hachage de transaction généré compatible avec les hachages de transaction générés à partir des applications JavaScript.

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

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

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

La méthode booléenne Check() compare le hachage résultant du champ de hachage de la transaction avec le hachage obtenu à la suite du hachage de cette transaction (en ignorant le champ de hachage).

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

La structure des 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 le type de données, le nœud l'utilise et distingue 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.
HeaderSize est la taille du bloc en octets.
PrevBlockHash est le hachage du bloc précédent et SelfBlockHash est le hachage du bloc actuel.
TxsHash est un hachage général de transactions.
MerkleRoot est la racine de l'arbre Merkle.

Plus loin dans les champs se trouvent 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.

Regardons ses méthodes :
Pour créer un bloc, utilisez la fonction block.NewBlock() : NewBlock(prevBlockHash string, height int) *Block, qui prend le hachage du bloc précédent et la hauteur définie pour le bloc créé dans la blockchain. Le type de bloc est également défini à partir de la constante du package types :

b.DataType = types.BLOCK_TYPE.

La méthode AddTx(tx *transaction.TX) ajoute une transaction à un 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 ToBytesHeader() []byte convertit l'en-tête de bloc (sans transactions) en tranche d'octets.

La méthode de chaîne ToJSON() convertit le bloc au format JSON dans une 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 une structure de bloc.

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

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

La méthode GetMerkleRoot() spécifie la racine de l'arborescence Merkle pour les transactions dans un bloc.

La méthode Sign(privk string) signe un 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 telle que spécifiée dans le champ correspondant de la structure du bloc.

La méthode ToGOBBytes() []byte encode un 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 méthode de chaîne GetHash() renvoie le hachage du bloc donné.

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

La méthode SetPublicKey(pubk string) écrit la clé publique du créateur du bloc dans le bloc.

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

Les fonctions du package blockchain sont chargées de l'enregistrement sur la blockchain : github.com/Rusldv/bcstartup/tree/master/blockchain

Pour ce faire, 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

}

La connexion à la base de données est créée une fois lorsque le package est initialisé 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(hash string) é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() (string, error) 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 blockchain pour le nœud avec la clé spécifiée par la constante BLOCK_HEIGHT.

La fonction GetTargetBlockHeight() (int, error) renvoie la hauteur de la blockchain pour un nœud donné, stockée dans la base de données.

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

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

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

La fonction GetBlockByHash(hash string) (*block.Block, error) crée un objet bloc vide, y charge un bloc à partir de la base de données, dont le hachage lui a été transmis, et renvoie un pointeur vers celui-ci.

La création d'un bloc Genesis est réalisée par la fonction d'erreur Genesis() du fichier Genesis.go du package blockchain.

Le prochain article parlera de la connexion des clients à un nœud à l'aide du mécanisme WebSocket.

Source: habr.com

Ajouter un commentaire