Paano ako nagdisenyo ng mga bloke at transaksyon sa aking Go blockchain

Upang sa huli ay magkaroon ng isang blockchain at hindi lamang isang database, kailangan naming magdagdag ng 3 mahahalagang elemento sa aming proyekto:

  • Paglalarawan ng istraktura at pamamaraan ng block data
  • Paglalarawan ng istraktura ng data at mga pamamaraan ng transaksyon
  • Mga function ng Blockchain na nagse-save ng mga block sa isang database at hanapin ang mga ito doon ayon sa kanilang hash o taas (o iba pa).

Paano ako nagdisenyo ng mga bloke at transaksyon sa aking Go blockchain

Ito ang pangalawang artikulo tungkol sa blockchain para sa industriya, ang una dito.

Ang pag-alala sa mga tanong na tinanong sa akin ng mga mambabasa tungkol sa nakaraang artikulo sa seryeng ito, dapat itong tandaan: sa kasong ito, ang database ng LevelDB ay ginagamit upang mag-imbak ng data ng blockchain, ngunit walang pumipigil sa iyo na gumamit ng iba pa, halimbawa, MySQL. Ngayon tingnan natin ang istraktura ng data na ito.

Magsimula tayo sa mga transaksyon: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Narito ang istraktura ng data nito:

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
}

Iniimbak ng TX ang uri ng data (para sa transaksyon 2), ang hash ng transaksyong iyon, ang uri ng mismong transaksyon, isang timestamp, at mga input at output. Ang mga input ng TxIn ay nag-iimbak ng hash ng transaksyon kung saan ang output ay isinangguni, ang bilang ng output at bytecode na ito, at ang mga TxOut na output ay nag-iimbak ng ilang halaga at pati na rin ang bytecode.

Ngayon tingnan natin kung anong mga pagkilos ang maaaring gawin ng isang transaksyon sa data nito, i.e. Tingnan natin ang mga pamamaraan.

Upang gumawa ng transaksyon, gamitin ang transaksyon.NewTransaction(txtype byte) *TX function.

Ang AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) ay nagdaragdag ng input sa transaksyon.

Ang AddTxOut(value int, data []byte) (*TxOut, error) na paraan ay nagdaragdag ng output sa transaksyon.

Ginagawa ng ToBytes() []byte method ang transaksyon sa isang byte slice.

Ang panloob na function na preByteHash(bytes []byte) string ay ginagamit sa Build() at Check() para gawing tugma ang nabuong transaction hash sa mga transaction hash na nabuo mula sa mga application na JavaScript.

Itinatakda ng Build() method ang transaction hash gaya ng sumusunod: tx.TxHash = preByteHash(tx.ToBytes()).

Ang ToJSON() string method ay nagko-convert ng isang transaksyon sa isang JSON string.

Ang FromJSON(data []byte) na paraan ng error ay naglo-load ng isang transaksyon mula sa JSON na format na ipinasa bilang isang byte slice.

Inihahambing ng Check() bool method ang nagreresultang hash mula sa transaction hash field sa hash na nakuha bilang resulta ng pag-hash ng transaksyon na ito (binalewala ang hash field).

Ang mga transaksyon ay idinagdag sa block: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Ang istraktura ng block data ay mas makapal:

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
}

Iniimbak ng DataType ang uri ng data, ginagamit ito ng node at nakikilala ang bloke mula sa isang transaksyon o iba pang data. Para sa isang bloke ang halagang ito ay 1.

Iniimbak ng BlockHeight ang taas ng block.
timestamp ng timestamp.
Ang HeaderSize ay ang laki ng block sa mga byte.
Ang PrevBlockHash ay ang hash ng nakaraang block, at ang SelfBlockHash ay ang hash ng kasalukuyan.
Ang TxsHash ay isang pangkalahatang hash ng mga transaksyon.
Ang MerkleRoot ay ang ugat ng puno ng Merkle.

Karagdagan sa mga patlang ay mayroong pampublikong susi ng lumikha ng bloke, ang lagda ng lumikha, ang bersyon ng bloke, ang bilang ng mga transaksyon sa bloke, at ang mga transaksyong ito mismo.

Tingnan natin ang mga pamamaraan nito:
Para gumawa ng block, gamitin ang block.NewBlock() function: NewBlock(prevBlockHash string, height int) *Block, na kumukuha ng hash ng nakaraang block at taas na itinakda para sa ginawang block sa blockchain. Ang uri ng block ay itinakda rin mula sa mga uri ng package constant:

b.DataType = types.BLOCK_TYPE.

Ang paraan ng AddTx(tx *transaction.TX) ay nagdaragdag ng transaksyon sa isang block.

Ang paraan ng Build() ay naglo-load ng mga halaga sa mga field ng block at bumubuo at nagtatakda ng kasalukuyang hash nito.

Ang ToBytesHeader() []byte method ay nagko-convert ng block header (nang walang mga transaksyon) sa isang byte slice.

Kino-convert ng ToJSON() string method ang block sa JSON format sa isang string na representasyon ng data.

Ang FromJSON(data []byte) na paraan ng error ay naglo-load ng data mula sa JSON sa isang block structure.

Ang Check() bool method ay bumubuo ng block hash at inihahambing ito sa isa na tinukoy sa block hash field.

Ibinabalik ng GetTxsHash() string method ang kabuuang hash ng lahat ng transaksyon sa block.

Ang GetMerkleRoot() method ay tumutukoy sa ugat ng Merkle tree para sa mga transaksyon sa isang block.

Ang Sign(privk string) na paraan ay pumipirma ng block gamit ang pribadong key ng block creator.

Ang SetHeight(height int) method ay nagsusulat ng taas ng block sa block structure field.

Ang GetHeight() int method ay nagbabalik ng taas ng block gaya ng tinukoy sa kaukulang field ng block structure.

Ang ToGOBBytes() []byte method ay nag-encode ng isang block sa GOB na format at ibinabalik ito bilang isang byte slice.

Ang FromGOBBytes(data []byte) na paraan ng error ay nagsusulat ng block data sa block structure mula sa naipasa na byte na slice sa GOB na format.

Ang GetHash() string method ay nagbabalik ng hash ng ibinigay na block.

Ang GetPrevHash() string method ay nagbabalik ng hash ng nakaraang block.

Ang SetPublicKey(pubk string) na paraan ay nagsusulat ng pampublikong key ng gumawa ng block sa block.

Kaya, gamit ang mga pamamaraan ng Block object, madali nating mako-convert ito sa isang format para sa paghahatid sa network at pag-save sa database ng LevelDB.

Ang mga function ng blockchain package ay responsable para sa pag-save sa blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

Upang gawin ito, dapat ipatupad ng block ang interface ng IBlock:

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

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

}

Ang koneksyon sa database ay nilikha nang isang beses kapag ang package ay sinimulan sa init() function:

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

Ang CloseDB() ay isang wrapper para sa db.Cloce() - tinawag pagkatapos magtrabaho kasama ang mga function ng package upang isara ang koneksyon sa database.

Ang SetTargetBlockHash(hash string) function na error ay nagsusulat ng hash ng kasalukuyang block na may key na tinukoy ng BLOCK_HASH constant sa database.

Ang GetTargetBlockHash() (string, error) function ay nagbabalik ng hash ng kasalukuyang block na nakaimbak sa database.

Ang SetTargetBlockHeight(height int) error function ay nagsusulat sa database ng halaga ng blockchain height para sa node na may key na tinukoy ng BLOCK_HEIGHT constant.

Ibinabalik ng GetTargetBlockHeight() (int, error) function ang taas ng blockchain para sa isang partikular na node, na nakaimbak sa database.

Sinusuri ng CheckBlock(block IBlock) bool function ang isang block para sa kawastuhan bago idagdag ang block na ito sa blockchain.

Ang AddBlock(block IBlock) error function ay nagdaragdag ng block sa blockchain.

Ang mga function para sa pagkuha at pagtingin sa mga bloke ay nasa explore.go file ng blockchain package:

Ang GetBlockByHash(hash string) (*block.Block, error) function ay lumilikha ng walang laman na block object, naglo-load ng block dito mula sa database, ang hash ay ipinasa dito, at nagbabalik ng pointer dito.

Ang paglikha ng genesis block ay isinasagawa ng Genesis() error function mula sa genesis.go file ng blockchain package.

Ang susunod na artikulo ay magsasalita tungkol sa pagkonekta ng mga kliyente sa isang node gamit ang mekanismo ng WebSocket.

Pinagmulan: www.habr.com

Magdagdag ng komento