Kuidas ma projekteerisin plokid ja tehingud oma plokiahelas Go keeles

Kuna saaksime lõpuks luua plokiahela, mitte lihtsalt andmebaasi, peame lisama oma projekti kolm olulist elementi:

  • Andmestruktuuri ja blokimeetodite kirjeldus
  • Tehingustruktuuri ja meetodite kirjeldus
  • Plokiahela funktsioonid, mis salvestavad plokid andmebaasi ja leiavad need seal nende räsiväärtuse või kõrguse (või muul viisil) järgi.

Kuidas ma projekteerisin plokid ja tehingud oma plokiahelas Go keeles

See on teine artikkel plokiahela kohta tööstuses, esimene siin.

Käies läbi küsimusi, mida lugejad küsisid eelneva artikli kohta, tuleb märkida: plokiahela andmete salvestamiseks kasutatakse antud juhul LevelDB andmebaasi, kuid pole midagi, mis takistaks kasutada mõnda muud, näiteks MySQL-i. Nüüd vaatame nende andmete struktuuri.

Alustame tehingutest: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Siin on selle andmestruktuur:

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-s hoitavad andmetüübid (tehingu 2 jaoks), selle tehingu hash, tehingu tüüp, ajatempli kood ning sisendid ja väljundid. Sisendid TxIn sisaldavad selle tehingu hash'i, millele viidatakse, selle väljundi numbrit ja bytekoodi, samas kui väljundid TxOut hoiavad mingit väärtust ja ka bytekoodi.

Vaadakem nüüd, milliseid toiminguid saab tehing oma andmetega teha, st uurime meetodeid.

Tehingu loomiseks kasutatakse funktsiooni transaction.NewTransaction(txtype byte) *TX.

Meetod AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) lisab tehingule sisendi.

Meetod AddTxOut(value int, data []byte) (*TxOut, error) lisab tehingule väljundi.

Meetod ToBytes() []byte muudab tehingu byte-slice'iks.

Sisemine funktsioon preByteHash(bytes []byte) string rakendatakse Build() ja Check() funktsioonides, et tagada loodud tehingu hash'i ühilduvus JavaScript'i rakendustest genereeritud tehingu hash'idega.

Meetod Build() määrab tehingu hash'i järgmiselt: tx.TxHash = preByteHash(tx.ToBytes()).

Meetod ToJSON() string muundab tehingu JSON stringiks.

Meetod FromJSON(data []byte) error laadib tehingu JSON-formaadist, mis on edastatud byte-slice'ina.

Meetod Check() bool võrreldab saadud hash'i tehingu hash'alalt tehingu hash'iga, mis saadakse selle tehingu hash'imise tulemusena (ilma hash'i alampunktita).

Tehingud lisatakse plokki: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Ploki andmestruktuur on suurem:

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 hoiab andmetüüpi, mille põhjal node eristab plokki tehingust või muudest andmetest. Ploki puhul on see väärtus 1.

BlockHeight hoiab ploki kõrgust.
Timestamp ajatemplit.
HeaderSize ploki suurust baitides.
PrevBlockHash on eelmise ploki hash ja SelfBlockHash on praegune.
TxsHash on tehingute koguhash.
MerkleRoot on Merkle puu juur.

Edasi, välistes väljadest, on ploki looja avalik võti, looja allkiri, ploki versioon, tehingute arv plokis ja muidugi ise need tehingud.

Vaadakem tema meetodeid:
Ploki loomisel kasutatakse funktsiooni block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, mis võtab vastu eelmise ploki hash'i ja kõrguse, mis on määratud loodud plokile plokiahelas. Samuti määratakse ploki tüüp paketist types konstantide abil:

b.DataType = types.BLOCK_TYPE.

Meetod AddTx(tx *transaction.TX) lisab plokki tehingu.

Meetod Build() laadib ploki väljadele väärtused ja genereerib ning määrab selle hetke hash'i.

Meetod ToBytesHeader() []byte muundab ploki päise (ilma tehinguteta) baitide lõiguks.

Meetod ToJSON() string muundab ploki JSON-vormingusse stringi kujul.

Meetod FromJSON(data []byte) error laadib andmed JSON'ist ploki struktuuri.

Meetod Check() bool genereerib ploki hash'i ja võrdleb seda ploki hash'i väljas määratud väärtusega.

Meetod GetTxsHash() string tagastab kõigi plokis olevate tehingute koguhash'i.

Meetod GetMerkleRoot() määrab plokis olevate tehingute Merkle puu juure.

Meetod Sign(privk string) allkirjastab ploki looja privaatsuse võtmega.

Meetod SetHeight(height int) salvestab ploki kõrguse ploki struktuuri väljal.

Meetod GetHeight() int tagastab ploki kõrguse, nagu on määratud ploki struktuuri vastavas väljas.

Meetod ToGOBBytes() []byte kodeerib ploki GOB formaati ja tagastab selle baitide lõiguna.

Meetod FromGOBBytes(data []byte) error kirjutab ploki andmed struktuuri plokist edastatud baitide lõigus GOB formaadis.

Meetod GetHash() string tagastab selle ploki rümba.

Meetod GetPrevHash() string tagastab eelmise ploki rümba.

Meetod SetPublicKey(pubk string) kirjutab plokki looja avaliku võtme.

Nii et, objektide Block meetodite abil saame kergesti konverteerida need formaati edastamiseks võrgu kaudu ja salvestamiseks LevelDB andmebaasi.

Bloki salvestamise eest vastutavad blockchain paketi funktsioonid: github.com/Rusldv/bcstartup/tree/master/blockchain

Selleks peab plokk rakendama liidest IBlock:

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

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

}

Andmebaasi ühendus luuakse üks kord paketi initsialiseerimise ajal funktsioonis init():

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

CloseDB() on db.Cloce() ümbrik — kutsutakse välja pärast paketi funktsioonidega töötamist, et sulgeda ühendus andmebaasiga.

Funktsioon SetTargetBlockHash(hash string) error salvestab andmebaasi praeguse ploki rümbas võti, mille on määranud konstandi BLOCK_HASH.

GetTargetBlockHash() (string, error) funktsioon tagastab praeguse ploki hash'i, mis on salvestatud andmebaasi.

SetTargetBlockHeight(height int) error funktsioon kirjutab andmebaasi blockchain'i kõrguse väärtuse sõlmele, mille võti on määratud konstant BLOCK_HEIGHT.

GetTargetBlockHeight() (int, error) funktsioon tagastab blockchain'i kõrguse selle sõlme jaoks, mis on salvestatud andmebaasi.

CheckBlock(block IBlock) bool funktsioon kontrollib ploki korrektsust enne, kui see plokk lisatakse blockchain'i.

AddBlock(block IBlock) error funktsioon lisab ploki blockchain'i.

Plokkide saamise ja vaatamise funktsioonid on failis explore.go blockchain'i paketis:

GetBlockByHash(hash string) (*block.Block, error) funktsioon loob tühja ploki objekti, laadib sinna ploki andmebaasist, mille hash on edastatud, ja tagastab sellele näitaja.

Genesis() error funktsioon, mis asub failis genesis.go blockchain'i paketis, vastutab geenesisploki loomise eest.

Järgmises artiklis käsitletakse, kuidas ühendada klientide sõlmega WebSocket'i mehhanismi abil.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster