Pour qu'un véritable blockchain soit créé, et pas simplement une base de données, nous devons ajouter trois éléments importants à notre projet :
- Description de la structure des données et des méthodes du bloc
- Description de la structure des données et des méthodes de transaction
- Fonctions de blockchain qui conservent les blocs dans la base de données et les trouvent par leur hachage ou leur hauteur (ou de toute autre maniÚre).

Ceci est le deuxiĂšme article sur la blockchain pour l'industrie, le premier .
En se remĂ©morant les questions que les lecteurs m'ont posĂ©es concernant l'article prĂ©cĂ©dent de cette sĂ©rie, il convient de noter : pour le stockage des donnĂ©es de blockchain, nous utilisons dans ce cas une base de donnĂ©es LevelDB, mais rien ne nous empĂȘche d'utiliser n'importe quelle autre, disons MySQL. Passons maintenant Ă la structure de ces donnĂ©es.
Commençons par les transactions :
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
}Dans TX, sont stockĂ©s le type de donnĂ©es (pour la transaction 2), le hachage de cette transaction, le type de la transaction elle-mĂȘme, l'horodatage, ainsi que les entrĂ©es et sorties. Les entrĂ©es TxIn stockent le hachage de la transaction Ă laquelle elles font rĂ©fĂ©rence, le numĂ©ro de cette sortie et le bytecode, tandis que les sorties TxOut stockent une valeur et Ă©galement un bytecode.
Regardons maintenant quelles actions une transaction peut effectuer sur ses données, c'est-à -dire examinons les méthodes.
La fonction transaction.NewTransaction(txtype byte) *TX sert à créer une transaction.
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 un tableau de bytes.
La fonction interne preByteHash(bytes []byte) string est utilisée dans Build() et Check() pour garantir la compatibilité du hachage de la transaction créée avec les hachages des transactions générés par les applications en JavaScript.
La méthode Build() définit le hachage de la transaction comme suit : tx.TxHash = preByteHash(tx.ToBytes()).
La méthode ToJSON() string convertit la transaction en une chaßne JSON.
La méthode FromJSON(data []byte) error charge la transaction à partir du format JSON, transmis sous forme de tranche de bytes.
La méthode Check() bool compare le hachage obtenu du champ de hachage de la transaction avec le hachage obtenu suite au hachage de cette transaction (sans tenir compte du champ de hachage).
Les transactions sont ajoutées au bloc :
La structure de données du bloc est plus complexe :
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 conserve le type de donnĂ©es, qui permet au nĆud de distinguer un bloc d'une transaction ou d'autres donnĂ©es. Pour un bloc, cette valeur est Ă©gale Ă 1.
BlockHeight conserve la hauteur du bloc.
Timestamp est le marqueur de temps.
HeaderSize est la taille du bloc en octets.
PrevBlockHash est le hachage du bloc précédent, tandis que SelfBlockHash est le hachage du bloc actuel.
TxsHash est le hachage global des transactions.
MerkleRoot est la racine de l'arbre de Merkle.
Ensuite, les champs contiennent 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 bien sĂ»r ces transactions elles-mĂȘmes.
Examinons ses méthodes :
Pour créer un bloc, on utilise 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. On définit également le type de bloc depuis la constante du paquet types :
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 établit son hachage actuel.
La mĂ©thode ToBytesHeader() []byte convertit l'en-tĂȘte du bloc (sans transactions) en un tableau d'octets.
La méthode ToJSON() string convertit le bloc en format JSON en représentation textuelle des données.
La méthode FromJSON(data []byte) error charge des données JSON dans la structure du bloc.
La méthode Check() bool génÚre le hachage du bloc et le compare avec celui spécifié dans le champ du hachage du bloc.
La méthode GetTxsHash() string retourne le hachage global de toutes les transactions dans le bloc.
La méthode GetMerkleRoot() définit la racine de l'arbre de 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) enregistre la hauteur du bloc dans le champ de la structure du bloc.
La méthode GetHeight() int retourne la hauteur du bloc telle qu'indiquée dans le champ correspondant de la structure du bloc.
La méthode ToGOBBytes() []byte encode le bloc au format GOB et le retourne sous forme de tableau d'octets.
La méthode FromGOBBytes(data []byte) error enregistre les données du bloc dans la structure du bloc à partir du tableau d'octets fourni au format GOB.
La méthode GetHash() string retourne le hachage de ce bloc.
La méthode GetPrevHash() string retourne le hachage du bloc précédent.
La méthode SetPublicKey(pubk string) enregistre dans le bloc la clé publique du créateur du bloc.
Ainsi, grùce aux méthodes de l'objet Block, nous pouvons facilement le convertir au format pour le transmettre sur le réseau et le stocker dans une base de données LevelDB.
Les fonctions du paquet blockchain sont responsables de la sauvegarde dans la 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
}La connexion à la base de données est créée une fois lors de l'initialisation du paquet dans la fonction init() :
db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).CloseDB() est une enveloppe pour db.Close() â elle est appelĂ©e aprĂšs avoir travaillĂ© avec les fonctions du paquet pour fermer la connexion Ă la base de donnĂ©es.
La fonction SetTargetBlockHash(hash string) error enregistre dans la base de données le hachage du bloc actuel avec la clé définie par la constante BLOCK_HASH.
La fonction GetTargetBlockHash() (string, error) retourne le hachage du bloc actuel, stocké dans la base de données.
La fonction SetTargetBlockHeight(height int) error enregistre dans la base de donnĂ©es la valeur de la hauteur de la blockchain pour le nĆud avec la clĂ© dĂ©finie par la constante BLOCK_HEIGHT.
La fonction GetTargetBlockHeight() (int, error) retourne la hauteur de la blockchain pour le nĆud donnĂ©, stockĂ©e dans la base de donnĂ©es.
La fonction CheckBlock(block IBlock) bool effectue une vérification du bloc pour en assurer la validité avant de l'ajouter à la blockchain.
La fonction AddBlock(block IBlock) error ajoute le bloc Ă la blockchain.
Les fonctions pour obtenir et visualiser les blocs se trouvent dans le fichier explore.go du paquet blockchain :
La fonction GetBlockByHash(hash string) (*block.Block, error) crée un objet de bloc vide, charge le bloc correspondant de la base de données dont le hachage lui a été transmis et retourne un pointeur vers celui-ci.
La création d'un bloc génésis est effectuée par la fonction Genesis() error du fichier genesis.go du paquet blockchain.
Dans l'article suivant, nous aborderons la connexion des nĆuds clients via le mĂ©canisme WebSocket.
Source : habr.com
