Për t'u siguruar që në fund të krijohej një blockchain dhe jo thjesht një bazë të dhënash, na nevojiten 3 elemente të rëndësishme në projektin tonë:
- Përshkrimi i strukturës së të dhënave dhe metodave të bllokut
- Përshkrimi i strukturës së të dhënave dhe metodave të transaksionit
- Funksionet e blockchain që ruajnë blloqet në DB dhe i gjejnë atje sipas hash-it të tyre ose lartësisë (ose ndonjë mënyre tjetër).

Ky është artikulli i dytë për blockchain në industri, i pari .
Duke iu rikujtuar pyetjeve që më kanë bërë lexuesit për artikullin e kaluar të këtij cikli, duhet të theksoj se për ruajtjen e të dhënave të blockchain në këtë rast përdoret baza e të dhënave LevelDB, por asgjë nuk e ndalon përdorimin e ndonjë baze tjetër, për shembull MySQL. Tani le të shqyrtojmë strukturën e këtyre të dhënave.
Të fillojmë me transaksionet:
Ja struktura e saj e të dhënave:
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
}Në TX ruhet lloji i të dhënave (për transaksionin 2), hash-i i këtij transaksioni, lloji i vetë transaksionit, vula kohore, si dhe hyrjet dhe daljet. Hyrjet TxIn ruajnë hash-in e transaksionit, në daljen e të cilit referohen, numrin e kësaj daljeje dhe kodin bajt, ndërsa daljet TxOut ruajnë një vlerë dhe gjithashtu kodin bajt.
Tani le të shohim se çfarë veprimesh mund të kryejë transaksioni me të dhënat e tij, domethënë të shqyrtojmë metodat.
Për krijimin e një transaksioni shërben funksioni transaction.NewTransaction(txtype byte) *TX.
Metoda AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) shton një hyrje në transaksion.
Metoda AddTxOut(value int, data []byte) (*TxOut, error) shton një dalje në transaksion.
Metoda ToBytes() []byte e kthen transaksionin në një prerje bajtesh.
Funksioni i brendshëm preByteHash(bytes []byte) string përdoret në Build() dhe Check() për përputhshmërinë e hash-it të krijuar të transaksioneve me hash-et e transaksioneve të gjeneruara nga aplikacione në JavaScript.
Metoda Build() cakton hash-in e transaksionit në këtë mënyrë: tx.TxHash = preByteHash(tx.ToBytes()).
Metoda ToJSON() string e konverton transaksionin në një varg JSON.
Metoda FromJSON(data []byte) error ngarkon transaksionin nga formati JSON, i kaluar në formën e një prerje bajtesh.
Metoda Check() bool krahason hash-in e marrë nga fusha e hash-it të transaksionit me hash-in e marrë nga procesi i hash-imit të këtij transaksioni (pa marrë parasysh fushën e hash-it).
Transaksionet shtohen në bllok:
Struktura e të dhënave të bllokut është më e gjerë:
tipi 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 ruan tipin e dhënave, me të cilin nodi dallon blokun nga transaksionet ose të dhëna të tjera. Për një blok, ky vlerë është 1.
BlockHeight ruan lartësinë e blokut.
Timestamp ruan vulën e kohës.
HeaderSize ruan madhësinë e blokut në byte.
PrevBlockHash është hash-i i blokut të kaluar, ndërsa SelfBlockHash është i tanishmi.
TxsHash është hash-i total i transaksioneve.
MerkleRoot është gishti i pemës Merkle.
Më tej në fusha ndodhen çelësi publik i krijuesit të blokut, nënshkrimi i krijuesit, versioni i bllokut, numri i transaksioneve në bllok dhe ndodhen vetë këto transaksione.
Le të shqyrtojmë metodat e tij:
Për krijimin e një bloku përdoret funksioni block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, që pranon hash-in e blokut të kaluar dhe lartësinë e caktuar për bllokun e krijuar në blockchain. Gjithashtu caktuat tipi i bllokut nga konstanta e paketës types:
b.DataType = types.BLOCK_TYPE.Metoda AddTx(tx *transaction.TX) shton një transaksion në bllok.
Metoda Build() ngarkon vlerat në fushat e bllokut dhe gjeneron dhe vendos hash-in e tij të tanishëm.
Metoda ToBytesHeader() []byte konverton titullin e bllokut (pa transaksione) në një slice byte.
Metoda ToJSON() string konverton bllokun në formatin JSON në përfaqësimin e të dhënave si varg.
Metoda FromJSON(data []byte) error ngarkon të dhënat nga JSON në strukturën e bllokut.
Metoda Check() bool gjeneron hash-in e bllokut dhe e krahasohet me atë të dhënë në fushën e hash-it të bllokut.
Metoda GetTxsHash() string kthen hash-in total të të gjitha transaksioneve në bllok.
Metoda GetMerkleRoot() vendos gishti i pemës Merkle për transaksionet në bllok.
Metoda Sign(privk string) nënshkruan bllokun me çelësin privat të krijuesit të bllokut.
Metoda SetHeight(height int) shkruan lartësinë e bllokut në fushën e strukturës së bllokut.
Metoda GetHeight() int kthen lartësinë e bllokut ashtu siç është e caktuar në fushën përkatëse të strukturës së bllokut.
Metoda ToGOBBytes() []byte kodon bllokun në formatin GOB dhe e kthen atë si një slice byte.
Metoda FromGOBBytes(data []byte) error shkruan të dhënat e bllokut në strukturën e bllokut nga slice-i byte i dërguar në formatin GOB.
Metoda GetHash() string kthen hash-in e këtij blloku.
Metoda GetPrevHash() string kthen hash-in e bllokut të kaluar.
Metoda SetPublicKey(pubk string) shkruan në bllok çelësin publik të krijuesit të bllokut.
Kështu, duke përdorur metodat e objektit Block, mund ta konvertojmë lehtësisht atë në një format për transferim në rrjet dhe ruajtje në bazën e të dhënave LevelDB.
Funksionet e paketës blockchain janë përgjegjëse për ruajtjen në blockchain:
Për këtë, blloku duhet të realizojë ndërfaqen IBlock:
type IGOBBytes interface {
ToGOBBytes() []byte
FromGOBBytes(data []byte) error
}
type IBlock interface {
IGOBBytes
GetHash() string
GetPrevHash() string
GetHeight() int
Check() bool
}Kufizimi në bazën e të dhënave krijohet një herë gjatë inicializimit të paketës në funksionin init():
db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).CloseDB() është një mbështjellës për db.Cloce() — thirret pas përdorimit të funksioneve të paketës për të mbyllur lidhjen me bazën e të dhënave.
Funksioni SetTargetBlockHash(hash string) error shkruan në bazën e të dhënave hashin e bllokut aktual me çelësin e caktuar nga konstanta BLOCK_HASH.
Funksioni GetTargetBlockHash() (string, error) kthen hashin e bllokut aktual, të ruajtur në bazën e të dhënave.
Funksioni SetTargetBlockHeight(height int) error shkruan në bazën e të dhënave vlerën e lartësisë së blockchain për nodën me çelësin e caktuar nga konstanta BLOCK_HEIGHT.
Funksioni GetTargetBlockHeight() (int, error) kthen lartësinë e blockchain për këtë nodë, të ruajtur në bazën e të dhënave.
Funksioni CheckBlock(block IBlock) bool kryen kontrollin e bllokut para se të shtohet ky bllok në blockchain.
Funksioni AddBlock(block IBlock) error shton bllokun në blockchain.
Funksionet për marrjen dhe shikimin e bllokëve ndodhen në skedarin explore.go të paketës blockchain:
Funksioni GetBlockByHash(hash string) (*block.Block, error) krijon një objekt bosh blloku, ngarkon aty bllokun nga baza e të dhënave i cili ka hashin e dërguar dhe kthen një tregues për të.
Krijimi i bllokut të gjenezës realizohet nga funksioni Genesis() error nga skedari genesis.go i paketës blockchain.
Në artikullin vijues do të diskutohet lidhja me noden e klientëve përmes mekanizmit WebSocket.
Burimi: habr.com
