Si e projektuam blloqet dhe transaksionet në blockchain-in tim në Go

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).

Si e projektuam blloqet dhe transaksionet në blockchain-in tim në Go

Ky është artikulli i dytë për blockchain në industri, i pari këtu.

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: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

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: github.com/Rusldv/bcstartup/blob/master/block/builder.go

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: github.com/Rusldv/bcstartup/tree/master/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

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster