Nola diseinatu nituen blokeak eta transakzioak nire Go blockchain-en

Azken finean blockchain batekin amaitzeko eta ez datu-base batekin bakarrik, 3 elementu garrantzitsu gehitu behar dizkiogu gure proiektuari:

  • Blokeen datuen egituraren eta metodoen deskribapena
  • Datuen egituraren eta transakzio metodoen deskribapena
  • Blockchain-en funtzioak, blokeak datu-base batean gorde eta bertan aurkitzen dituzten hash edo altueraren arabera (edo beste zerbait).

Nola diseinatu nituen blokeak eta transakzioak nire Go blockchain-en

Hau industriarako blockchain-ari buruzko bigarren artikulua da, lehenengoa Hemen.

Irakurleek serie honetako aurreko artikuluari buruz egin zizkidaten galderak gogoratuz, kontuan izan behar da: kasu honetan, LevelDB datu-basea erabiltzen da blockchain datuak gordetzeko, baina ezerk ez dizu eragozten beste edozein, esate baterako, MySQL erabiltzea. Ikus dezagun orain datu horien egitura.

Has gaitezen transakzioekin: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Hona hemen bere datuen egitura:

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-k datu mota (2. transakziorako), transakzio horren hash-a, transakzio mota bera, denbora-zigilua eta sarrerak eta irteerak gordetzen ditu. TxIn sarrerek bere irteera erreferentzia duen transakzioaren hash-a gordetzen dute, irteera honen zenbakia eta byte-kodeak, eta TxOut-ek irteerek balio batzuk eta byte-kodeak gordetzen dituzte.

Ikus dezagun orain transakzio batek bere datuetan zer ekintza egin ditzakeen, hau da. Ikus ditzagun metodoak.

Transakzio bat sortzeko, erabili transakzioa.NewTransaction(txtype byte) *TX funtzioa.

AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) metodoak sarrera bat gehitzen dio transakzioari.

AddTxOut(value int, data []byte) (*TxOut, error) metodoak irteera bat gehitzen dio transakzioari.

ToBytes() []byte metodoak transakzioa byte zati batean bihurtzen du.

Barne-funtzioa preByteHash(bytes []byte) katea Build() eta Check()-en erabiltzen da sortutako transakzio-hash-a JavaScript aplikazioetatik sortutako transakzio-hashekin bateragarria izan dadin.

Build() metodoak honela ezartzen du transakzio-hash-a: tx.TxHash = preByteHash(tx.ToBytes()).

ToJSON() kate metodoak transakzio bat JSON kate bihurtzen du.

FromJSON(data []byte) errore-metodoak byte zati gisa pasatako JSON formatuko transakzio bat kargatzen du.

Check() bool metodoak transakzio hash-eremutik sortzen den hash-a konparatzen du transakzio honen hash-aren ondorioz lortutako hasharekin (hash-eremua alde batera utzita).

Transakzioak blokeari gehitzen zaizkio: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Blokeen datuen egitura bolumen handiagoa da:

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-k datu-mota gordetzen du, nodoak erabiltzen du eta blokea transakzio batetik edo bestelako datuetatik bereizten du. Bloke baterako balio hau 1 da.

BlockHeight blokearen altuera gordetzen du.
Denbora-zigilua denbora-zigilua.
HeaderSize blokearen tamaina da bytetan.
PrevBlockHash aurreko blokearen hash-a da, eta SelfBlockHash uneko blokearen hash-a.
TxsHash transakzioen hash orokorra da.
MerkleRoot Merkle zuhaitzaren erroa da.

Gehiago eremuetan blokearen sortzailearen gako publikoa, sortzailearen sinadura, blokearen bertsioa, blokeko transakzio kopurua eta transakzio horiek beraiek daude.

Ikus ditzagun bere metodoak:
Bloke bat sortzeko, erabili block.NewBlock() funtzioa: NewBlock(prevBlockHash string, height int) *Blokea, aurreko blokearen hash-a eta sortutako blokearen altuera ezarritako bloke-katean hartzen duena. Bloke mota ere mota paketearen konstantetik ezartzen da:

b.DataType = types.BLOCK_TYPE.

AddTx(tx *transaction.TX) metodoak transakzio bat gehitzen dio bloke bati.

Build() metodoak balioak blokearen eremuetan kargatzen ditu eta bere uneko hash-a sortzen eta ezartzen du.

ToBytesHeader() []byte metodoak blokearen goiburua (transakziorik gabe) byte zati batean bihurtzen du.

ToJSON() kate metodoak blokea JSON formatura bihurtzen du datuen katearen irudikapen batean.

FromJSON(data []byte) errore-metodoak JSONko datuak bloke-egitura batean kargatzen ditu.

Check() bool metodoak bloke hash bat sortzen du eta bloke hash eremuan zehaztutakoarekin alderatzen du.

GetTxsHash() kate metodoak blokeko transakzio guztien hash osoa itzultzen du.

GetMerkleRoot() metodoak Merkle zuhaitzaren erroa zehazten du bloke bateko transakzioetarako.

Sign(privk string) metodoak bloke bat sinatzen du bloke-sortzailearen gako pribatuarekin.

SetHeight(height int) metodoak blokearen altuera idazten du bloke-egituraren eremuan.

GetHeight() int metodoak blokearen altuera itzultzen du bloke-egituraren dagokion eremuan zehaztutako moduan.

ToGOBBytes() []byte metodoak bloke bat GOB formatuan kodetzen du eta byte zati gisa itzultzen du.

FromGOBBytes(data []byte) errore-metodoak bloke-datuak bloke-egituran idazten ditu pasatutako byte zatitik GOB formatuan.

GetHash() kate metodoak emandako blokearen hash-a itzultzen du.

GetPrevHash() string metodoak aurreko blokearen hash-a itzultzen du.

SetPublicKey(pubk string) metodoak bloke-sortzailearen gako publikoa idazten du blokean.

Horrela, Block objektuaren metodoak erabiliz, erraz bihur dezakegu sarean transmititzeko eta LevelDB datu-basean gordetzeko formatu batean.

Blockchain paketearen funtzioak blockchain-en gordetzeaz arduratzen dira: github.com/Rusldv/bcstartup/tree/master/blockchain

Horretarako, blokeak IBlock interfazea ezarri behar du:

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

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

}

Datu-basearen konexioa behin sortzen da paketea init() funtzioan hasieratzen denean:

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

CloseDB() db.Cloce()-ren bilgarri bat da - datu-baserako konexioa ixteko pakete-funtzioekin lan egin ondoren deitzen da.

SetTargetBlockHash(hash string) errore-funtzioak uneko blokearen hash-a idazten du datu-basean BLOCK_HASH konstanteak zehaztutako gakoarekin.

GetTargetBlockHash() (katea, errorea) funtzioak datu-basean gordetako uneko blokearen hash-a itzultzen du.

SetTargetBlockHeight(height int) errore-funtzioak datu-basean idazten du nodoaren bloke-katearen altueraren balioa BLOCK_HEIGHT konstanteak zehaztutako gakoarekin.

GetTargetBlockHeight() (int, error) funtzioak nodo jakin baterako bloke-katearen altuera itzultzen du, datu-basean gordeta.

CheckBlock(block IBlock) bool funtzioak bloke bat zuzena den egiaztatzen du bloke hau bloke-katean gehitu aurretik.

AddBlock(blokea IBlock) errore-funtzioak bloke bat gehitzen dio bloke-kateari.

Blokeak berreskuratzeko eta ikusteko funtzioak blockchain paketearen explore.go fitxategian daude:

GetBlockByHash(hash string) (*block.Block, error) funtzioak bloke-objektu huts bat sortzen du, bloke bat kargatzen du datu-basetik, zeinaren hash-a pasatu zitzaion eta erakusle bat itzultzen du.

Genesis bloke baten sorrera Blockchain paketearen genesis.go fitxategiko Genesis() errore-funtzioaren bidez egiten da.

Hurrengo artikuluan bezeroak WebSocket mekanismoa erabiliz nodo batera konektatzeari buruz hitz egingo da.

Iturria: www.habr.com

Gehitu iruzkin berria