Si i projektova blloqet dhe transaksionet në zinxhirin tim Go

Në mënyrë që të përfundojmë përfundimisht me një blockchain dhe jo vetëm me një bazë të dhënash, ne duhet të shtojmë 3 elementë të rëndësishëm në projektin tonë:

  • Përshkrimi i strukturës dhe metodave të të dhënave të bllokut
  • Përshkrimi i strukturës së të dhënave dhe metodave të transaksionit
  • Funksionet e Blockchain që ruajnë blloqet në një bazë të dhënash dhe i gjejnë ato sipas hash-it ose lartësisë së tyre (ose diçka tjetër).

Si i projektova blloqet dhe transaksionet në zinxhirin tim Go

Ky është artikulli i dytë në lidhje me blockchain për industrinë, i pari këtu.

Duke kujtuar pyetjet që më bënë lexuesit në lidhje me artikullin e mëparshëm në këtë seri, duhet theksuar: në këtë rast, baza e të dhënave LevelDB përdoret për të ruajtur të dhënat e blockchain, por asgjë nuk ju pengon të përdorni ndonjë, të themi, MySQL. Tani le të shohim 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 tij 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
}

TX ruan llojin e të dhënave (për transaksionin 2), hash-in e atij transaksioni, llojin e vetë transaksionit, një vulë kohore dhe hyrjet dhe daljet. Inputet TxIn ruajnë hash-in e transaksionit, prodhimi i të cilit është referuar, numrin e këtij outputi dhe bajtkodi, dhe daljet TxOut ruajnë disa vlera dhe gjithashtu bajtkod.

Tani le të shohim se çfarë veprimesh mund të kryejë një transaksion në të dhënat e tij, d.m.th. Le të shohim metodat.

Për të krijuar një transaksion, përdorni funksionin transaksion.NewTransaction(txtype byte) *TX.

Metoda AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, gabim) shton një hyrje në transaksion.

Metoda AddTxOut(value int, data []byte) (*TxOut, gabim) shton një dalje në transaksion.

Metoda ToBytes() []byte e kthen transaksionin në një copë bajt.

Vargu i funksionit të brendshëm preByteHash(bytes []byte) përdoret në Build() dhe Check() për ta bërë hash-in e transaksionit të krijuar të pajtueshëm me hash-et e transaksioneve të krijuara nga aplikacionet JavaScript.

Metoda Build() vendos hash-in e transaksionit si më poshtë: tx.TxHash = preByteHash(tx.ToBytes()).

Metoda e vargut ToJSON() konverton një transaksion në një varg JSON.

Metoda e gabimit FromJSON(data []byte) ngarkon një transaksion nga formati JSON i kaluar si një pjesë bajt.

Metoda Check() bool krahason hash-in që rezulton nga fusha hash e transaksionit me hash-in e marrë si rezultat i hashimit të këtij transaksioni (duke injoruar fushën hash).

Transaksionet shtohen në bllok: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Struktura e të dhënave të bllokut është më voluminoze:

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 ruan llojin e të dhënave, nyja e përdor atë dhe e dallon bllokun nga një transaksion ose të dhëna të tjera. Për një bllok, kjo vlerë është 1.

BlockHeight ruan lartësinë e bllokut.
Vula kohore.
HeaderSize është madhësia e bllokut në bajt.
PrevBlockHash është hash-i i bllokut të mëparshëm dhe SelfBlockHash është hash-i i atij aktual.
TxsHash është një hash i përgjithshëm i transaksioneve.
MerkleRoot është rrënja e pemës Merkle.

Më tej në fusha gjendet çelësi publik i krijuesit të bllokut, nënshkrimi i krijuesit, versioni i bllokut, numri i transaksioneve në bllok dhe vetë këto transaksione.

Le të shohim metodat e tij:
Për të krijuar një bllok, përdorni funksionin block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, i cili merr hash-in e bllokut të mëparshëm dhe lartësinë e vendosur për bllokun e krijuar në blockchain. Lloji i bllokut caktohet gjithashtu nga konstanta e paketës së llojeve:

b.DataType = types.BLOCK_TYPE.

Metoda AddTx(tx *transaction.TX) shton një transaksion në një bllok.

Metoda Build() ngarkon vlerat në fushat e bllokut dhe gjeneron dhe vendos hash-in e tij aktual.

Metoda ToBytesHeader() []byte konverton kokën e bllokut (pa transaksione) në një copë bajt.

Metoda e vargut ToJSON() e konverton bllokun në formatin JSON në një paraqitje string të të dhënave.

Metoda e gabimit FromJSON(data []byte) ngarkon të dhënat nga JSON në një strukturë blloku.

Metoda Check() bool gjeneron një hash blloku dhe e krahason atë me atë të specifikuar në fushën hash të bllokut.

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

Metoda GetMerkleRoot() specifikon rrënjën e pemës Merkle për transaksionet në një bllok.

Metoda Sign (string privk) nënshkruan një bllok 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 siç specifikohet në fushën përkatëse të strukturës së bllokut.

Metoda ToGOBBytes() []byte kodon një bllok në formatin GOB dhe e kthen atë si një copë bajt.

Metoda e gabimit FromGOBBytes(data []byte) shkruan të dhënat e bllokut në strukturën e bllokut nga pjesa e kaluar e bajtit në formatin GOB.

Metoda e vargut GetHash() kthen hash-in e bllokut të dhënë.

Metoda e vargut GetPrevHash() kthen hash-in e bllokut të mëparshëm.

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

Kështu, duke përdorur metodat e objektit Block, ne mund ta shndërrojmë atë lehtësisht në një format për transmetim 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 ta bërë këtë, blloku duhet të zbatojë ndërfaqen IBlock:

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

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

}

Lidhja e bazës së të dhënave krijohet një herë kur paketa inicializohet në funksionin init():

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

CloseDB() është një mbështjellës për db.Cloce() - thirret pas punës me funksionet e paketës për të mbyllur lidhjen me bazën e të dhënave.

Funksioni i gabimit SetTargetBlockHash (vargu hash) shkruan hash-in e bllokut aktual me çelësin e specifikuar nga konstantja BLOCK_HASH në bazën e të dhënave.

Funksioni GetTargetBlockHash() (string, gabim) kthen hash-in e bllokut aktual të ruajtur në bazën e të dhënave.

Funksioni i gabimit SetTargetBlockHeight(height int) shkruan në bazën e të dhënave vlerën e lartësisë së blockchain për nyjen me çelësin e specifikuar nga konstantja BLOCK_HEIGHT.

Funksioni GetTargetBlockHeight() (int, error) kthen lartësinë e blockchain për një nyje të caktuar, të ruajtur në bazën e të dhënave.

Funksioni CheckBlock(block IBlock) bool kontrollon një bllok për korrektësi përpara se ta shtojë këtë bllok në zinxhirin e bllokut.

Funksioni i gabimit AddBlock(block IBlock) shton një bllok në blockchain.

Funksionet për marrjen dhe shikimin e blloqeve janë në skedarin explore.go të paketës blockchain:

Funksioni GetBlockByHash (vargu hash) (*block.Block, error) krijon një objekt bllok bosh, ngarkon një bllok në të nga baza e të dhënave, hash-i i të cilit i është kaluar dhe i kthen një tregues.

Krijimi i një blloku të gjenezës kryhet nga funksioni i gabimit Genesis() nga skedari genesis.go i paketës blockchain.

Artikulli tjetër do të flasë për lidhjen e klientëve me një nyje duke përdorur mekanizmin WebSocket.

Burimi: www.habr.com

Shto një koment