Jinsi nilivyosanifu vizuizi na miamala katika Go blockchain yangu

Ili hatimaye kupata blockchain na sio hifadhidata pekee, tunahitaji kuongeza vipengele 3 muhimu kwenye mradi wetu:

  • Maelezo ya muundo wa data ya kuzuia na njia
  • Maelezo ya muundo wa data na mbinu za manunuzi
  • Kazi za Blockchain ambazo huhifadhi vizuizi kwenye hifadhidata na kuzipata hapo kwa heshi au urefu wao (au kitu kingine).

Jinsi nilivyosanifu vizuizi na miamala katika Go blockchain yangu

Hii ni nakala ya pili kuhusu blockchain kwa tasnia, ya kwanza hapa.

Kukumbuka maswali ambayo wasomaji waliniuliza kuhusu makala iliyopita katika mfululizo huu, ni lazima ieleweke: katika kesi hii, database ya LevelDB hutumiwa kuhifadhi data ya blockchain, lakini hakuna kitu kinachozuia kutumia nyingine yoyote, sema, MySQL. Sasa hebu tuangalie muundo wa data hii.

Wacha tuanze na shughuli: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Huu hapa ni muundo wake wa data:

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 huhifadhi aina ya data (kwa muamala wa 2), heshi ya muamala huo, aina ya muamala wenyewe, muhuri wa muda, na pembejeo na matokeo. Ingizo za TxIn huhifadhi heshi ya muamala ambayo matokeo yake yamerejelewa, nambari ya pato hili na bytecode, na matokeo ya TxOut huhifadhi thamani fulani na pia bytecode.

Sasa hebu tuone ni hatua gani shughuli inaweza kufanya kwenye data yake, i.e. Hebu tuangalie mbinu.

Ili kuunda muamala, tumia kitendakazi.NewTransaction(txtype byte) *TX.

Mbinu ya AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) huongeza ingizo kwenye muamala.

Njia ya AddTxOut(value int, data []byte) (*TxOut, error) huongeza matokeo kwenye muamala.

Mbinu ya ToBytes() []baiti hugeuza muamala kuwa kipande kidogo.

Mfuatano wa utendakazi wa ndani preByteHash(baiti []baiti) hutumika katika Build() na Angalia() ili kufanya heshi ya muamala inayozalishwa iendane na heshi za ununuzi zinazozalishwa kutoka kwa programu za JavaScript.

Mbinu ya Build() huweka heshi ya muamala kama ifuatavyo: tx.TxHash = preByteHash(tx.ToBytes()).

Mbinu ya mfuatano wa ToJSON() hubadilisha muamala kuwa mfuatano wa JSON.

Mbinu ya hitilafu ya FromJSON(data []baiti) hupakia muamala kutoka kwa umbizo la JSON lililopitishwa kama kipande cha baiti.

Mbinu ya Check() bool inalinganisha heshi inayotokana na sehemu ya reli ya muamala na heshi iliyopatikana kutokana na kuharakisha muamala huu (kupuuza sehemu ya heshi).

Shughuli zinaongezwa kwenye kizuizi: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Muundo wa data ya kuzuia ni mkali zaidi:

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 huhifadhi aina ya data, nodi hutumia na kutofautisha kizuizi kutoka kwa shughuli au data nyingine. Kwa kizuizi thamani hii ni 1.

BlockHeight huhifadhi urefu wa block.
Muhuri wa muda wa saa.
HeaderSize ni saizi ya kizuizi katika baiti.
PrevBlockHash ni heshi ya kizuizi kilichotangulia, na SelfBlockHash ni heshi ya hiki cha sasa.
TxsHash ni heshi ya jumla ya shughuli.
MerkleRoot ni mzizi wa mti wa Merkle.

Zaidi katika uwanja kuna ufunguo wa umma wa muundaji wa block, saini ya muundaji, toleo la block, idadi ya shughuli kwenye block, na shughuli hizi zenyewe.

Wacha tuangalie mbinu zake:
Ili kuunda kizuizi, tumia kipengele cha block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, ambayo inachukua heshi ya kizuizi kilichotangulia na urefu uliowekwa kwa block iliyoundwa kwenye blockchain. Aina ya block pia imewekwa kutoka kwa kifurushi cha aina mara kwa mara:

b.DataType = types.BLOCK_TYPE.

Mbinu ya AddTx(tx *transaction.TX) huongeza muamala kwenye kizuizi.

Njia ya Build() hupakia thamani kwenye sehemu za kizuizi na hutoa na kuweka heshi yake ya sasa.

Mbinu ya ToBytesHeader() []baiti hubadilisha kichwa cha kuzuia (bila miamala) kuwa kipande cha baiti.

Mbinu ya mfuatano wa ToJSON() hubadilisha kizuizi kuwa umbizo la JSON katika uwakilishi wa mfuatano wa data.

Mbinu ya hitilafu ya FromJSON(data []baiti) hupakia data kutoka kwa JSON hadi kwenye muundo wa kuzuia.

Njia ya Check() bool hutoa heshi ya kuzuia na kuilinganisha na ile iliyoainishwa kwenye sehemu ya heshi ya block.

Njia ya mfuatano wa GetTxsHash() hurejesha jumla ya heshi ya miamala yote kwenye kizuizi.

Njia ya GetMerkleRoot() hubainisha mzizi wa mti wa Merkle kwa shughuli katika block.

Mbinu ya Sign(privk string) husaini kizuizi kwa ufunguo wa faragha wa mtengenezaji wa kuzuia.

Njia ya SetHeight(urefu int) huandika urefu wa kizuizi kwenye uwanja wa muundo wa block.

Njia ya GetHeight() int inarudisha urefu wa kizuizi kama ilivyoainishwa katika uwanja unaolingana wa muundo wa block.

Mbinu ya ToGOBBytes() []baiti husimba kizuizi katika umbizo la GOB na kukirejesha kama kipande cha baiti.

Mbinu ya hitilafu ya FromGOBBytes(data []baiti) huandika data ya zuio kwa muundo wa kuzuia kutoka kipande cha baiti kilichopitishwa katika umbizo la GOB.

Njia ya kamba ya GetHash() inarudisha heshi ya kizuizi ulichopewa.

Njia ya kamba ya GetPrevHash() inarudisha heshi ya kizuizi kilichopita.

Mbinu ya SetPublicKey(pubk string) huandika ufunguo wa umma wa kiunda kizuizi kwenye kizuizi.

Kwa hivyo, kwa kutumia njia za kitu cha Kuzuia, tunaweza kuibadilisha kwa urahisi kuwa umbizo la usambazaji kwenye mtandao na kuhifadhi kwenye hifadhidata ya LevelDB.

Kazi za kifurushi cha blockchain zina jukumu la kuokoa kwenye blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

Ili kufanya hivyo, kizuizi lazima kitekeleze kiolesura cha IBlock:

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

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

}

Muunganisho wa hifadhidata huundwa mara moja wakati kifurushi kinaanzishwa katika kazi ya init():

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

CloseDB() ni wrapper ya db.Cloce() - inayoitwa baada ya kufanya kazi na vifurushi ili kufunga unganisho kwenye hifadhidata.

Hitilafu ya SetTargetBlockHash(hash string) huandika heshi ya kizuizi cha sasa kwa ufunguo uliobainishwa na BLOCK_HASH mara kwa mara kwenye hifadhidata.

Kitendaji cha GetTargetBlockHash() (kamba, kosa) kinarudisha heshi ya kizuizi cha sasa kilichohifadhiwa kwenye hifadhidata.

Hitilafu ya SetTargetBlockHeight(height int) huandika kwa hifadhidata thamani ya urefu wa blockchain kwa nodi kwa ufunguo uliobainishwa na BLOCK_HEIGHT mara kwa mara.

Kitendaji cha GetTargetBlockHeight() (int, error) kinarudisha urefu wa blockchain kwa nodi fulani, iliyohifadhiwa kwenye hifadhidata.

ChekiBlock(block IBlock) bool hukagua kizuizi kwa usahihi kabla ya kuongeza kizuizi hiki kwenye blockchain.

Hitilafu ya AddBlock(block IBlock) inaongeza kizuizi kwenye blockchain.

Kazi za kurejesha na kutazama vizuizi ziko katika faili ya explore.go ya kifurushi cha blockchain:

Kazi ya GetBlockByHash(hash string) (*block.Block, error) huunda kitu tupu cha kuzuia, hupakia kizuizi ndani yake kutoka kwa hifadhidata, ambayo heshi yake ilipitishwa kwake, na kurudisha pointer kwake.

Uundaji wa kizuizi cha genesis unafanywa na kazi ya kosa la Genesis() kutoka kwa faili ya genesis.go ya kifurushi cha blockchain.

Nakala inayofuata itazungumza juu ya kuunganisha wateja kwenye nodi kwa kutumia utaratibu wa WebSocket.

Chanzo: mapenzi.com

Kuongeza maoni