Si si projektova blloqet dhe transaksionet në blockchainin tim në Go

Për të arritur në fund të fundit një blokçain dhe jo thjesht një bazë të dhënash, na nevojiten tre elementë të rëndësishëm 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 blokçainit qĂ« ruajnĂ« blloqet nĂ« bazĂ«n e tĂ« dhĂ«nave dhe i gjejnĂ« atje nĂ«pĂ«rmjet hash-it tĂ« tyre ose lartĂ«sisĂ« (apo ndonjĂ« forme tjetĂ«r).

Si si projektova blloqet dhe transaksionet në blockchainin tim në Go

Ky është artikulli i dytë për blokçainin për industrinë, i pari këtu.

Duke u rikujtuar pyetjet që më bënë lexuesit në artikullin e mëparshëm të këtij cikli, duhet të theksoj: për ruajtjen e të dhënave të blokçainit në këtë rast përdoret një bazë të dhënash LevelDB, por asgjë nuk e ndalon përdorimin e një të tjerës, le të themi MySQL-në e njëjtë. Tani le të shqyrtojmë strukturën e këtyre të dhënave.

Le të fillojmë me transaksionet: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Këtu është 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 ruhen tipin e të dhënave (për transaksionin 2), hash-i i këtij transaksioni, tipi i vetë transaksionit, timestamp-i, si dhe hyrjet dhe daljet. Hyrjet TxIn ruajnë hash-in e transaksionit, në daljen e të cilit referohen, numrin e kësaj daljeje dhe bytecode, ndërsa daljet TxOut ruajnë një vlerë dhe gjithashtu bytecode.

Tani le të shohim cilat veprime mund të kryejnë transaksionet mbi të dhënat e tyre, pra t'i shqyrtojmë metodat.

Funksioni transaction.NewTransaction(txtype byte) *TX shërben për krijimin e një transaksioni.

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ë slice bajtësh.

Funksioni i brendshëm preByteHash(bytes []byte) string aplikohet në Build() dhe Check() për t'u siguruar që hash-i i krijuar i transaksioneve të jetë në përputhje me hash-et e transaksioneve të gjeneruara nga aplikacionet në JavaScript.

Metoda Build() përcakton hash-in e transaksionit kështu: tx.TxHash = preByteHash(tx.ToBytes()).

Metoda ToJSON() string e kthen transaksionin në një varg JSON.

Metoda FromJSON(data []byte) error ngarkon transaksionin nga formati JSON, i dërguar si një slice bajtësh.

Metoda Check() bool krahasohet hash-i i marrës nga fusha e hash-it të transaksionit me hash-in e marrë si rezultat i hash-it 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ë:

tip 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 blokun, kjo vlerë është e barabartë me 1.

BlockHeight ruan lartësinë e blokut.
Timestamp është stampë e kohës.
HeaderSize është madhësia e blokut në byte.
PrevBlockHash është hash-i i blokut të mëparshëm, ndërsa SelfBlockHash është aktuali.
TxsHash është hash-i total i transaksioneve.
MerkleRoot është rrënjës i pemës Merkle.

Më poshtë në fushat ndodhet çelësi publik i krijuesit të blokut, nënshkrimi i krijuesit, versioni i blokut, numri i transaksioneve në bllok dhe vetë këto transaksione.

Le të shqyrtojmë metodat e tij:
Për të krijuar një blok, përdoret funksioni block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, i cili pranon hash-in e blokut të mëparshëm dhe lartësinë e vendosur për blokun e krijuar në blockchain. Gjithashtu, vendoset tipi i blokut 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 blokut dhe gjeneron dhe vendos hash-in e tij aktual.

Metoda ToBytesHeader() []byte shndërron header-in e blokut (pa transaksionet) në një slice byte.

Metoda ToJSON() string shndërron blokun në formatin JSON në një përfaqësim string të të dhënave.

Metoda FromJSON(data []byte) error ngarkon të dhënat nga JSON në strukturën e blokut.

Metoda Check() bool gjeneron hash-in e blokut dhe e krahason me atë të caktuar në fushën e hash-it të blokut.

Metoda GetTxsHash() string kthen hash-in total të të gjitha transaksioneve në bllok.

Metoda GetMerkleRoot() vendos rrënjën e 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ç tregohet 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 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ë mëparshëm.

Metoda SetPublicKey(pubk string) shkruan në bllok çelësin publik të krijuesit të bllokut.

Kështu, me metodat e objektit Block, ne mund të konvertojmë lehtësisht atë në një format për transferim rrjeti 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ë implementojë ndërfaqen IBlock:

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

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

}

Kconnection to the database is created once during the initialization of the package in the function init():

db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB() Ă«shtĂ« njĂ« mbĂ«shtjellĂ«s pĂ«r db.Close() — thirret pas punĂ«s me funksionet e paketĂ«s pĂ«r tĂ« mbyllur lidhjen me DB.

Funksioni SetTargetBlockHash(hash string) error shkruan në DB hash-in e bllokut aktual me çelësin e caktuar nga konstanta BLOCK_HASH.

Funksioni GetTargetBlockHash() (string, error) kthen hash-in e bllokut aktual, i cili ruhet në DB.

Funksioni SetTargetBlockHeight(height int) error shkruan në DB vlerën e lartësisë së blockchain për noden me çelësin e caktuar nga konstanta BLOCK_HEIGHT.

Funksioni GetTargetBlockHeight() (int, error) kthen lartësinë e blockchain për këtë nodë, e ruajtur në DB.

Funksioni CheckBlock(block IBlock) bool kryen verifikimin e bllokut për korrektësinë para se ta shtojmë këtë bllok në blockchain.

Funksioni AddBlock(block IBlock) error shton një bllok 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 bllokun e tij nga DB me hash-in e dhënë dhe kthen një pointer ndaj tij.

Krijimi i bllokut të gjenesis kryhet nga funksioni Genesis() error nga skedari genesis.go i paketës blockchain.

Në artikullin e ardhshëm do të flasim për lidhjen me nodin e klientëve duke përdorur mekanizmin WebSocket.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster