Како дизајнирав блокови и трансакции во мојот блок синџир Go

Со цел на крајот да завршиме со блокчејн, а не само со база на податоци, треба да додадеме 3 важни елементи на нашиот проект:

  • Опис на структурата и методите на блок податоци
  • Опис на структурата на податоците и методите на трансакција
  • Функции на блокчејн кои зачувуваат блокови во базата на податоци и ги наоѓаат таму според нивниот хаш или висина (или нешто друго).

Како дизајнирав блокови и трансакции во мојот блок синџир Go

Ова е втор напис за блокчејн за индустрија, првиот тука.

Сеќавајќи се на прашањата што ми ги поставија читателите за претходната статија од оваа серија, треба да се забележи: во овој случај, базата на податоци LevelDB се користи за складирање на податоци за блокчејн, но ништо не ве спречува да користите било кој друг, да речеме, MySQL. Сега да ја погледнеме структурата на овие податоци.

Да почнеме со трансакции: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Еве ја нејзината структура на податоци:

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 го складира типот на податоци (за трансакција 2), хашот на таа трансакција, типот на самата трансакција, временскиот печат и влезовите и излезите. Влезовите TxIn го складираат хашот на трансакцијата чиј излез е референциран, бројот на овој излез и бајтекод, а излезите TxOut складираат одредена вредност и исто така бајтекод.

Сега да видиме кои дејства може да ги изврши една трансакција на своите податоци, т.е. Ајде да ги погледнеме методите.

За да креирате трансакција, користете ја трансакцијата.NewTransaction(txtype byte) *TX функција.

Методот AddTxIn(thattxhash []бајт, txoutn int, код []бајт) (*TxIn, грешка) додава влез во трансакцијата.

Методот AddTxOut(value int, data []byte) (*TxOut, error) додава излез на трансакцијата.

Методот ToBytes() []byte ја претвора трансакцијата во бајт парче.

Низата на внатрешната функција preByteHash(бајти []бајт) се користи во Build() и Check() за да го направи генерираниот хаш на трансакцијата компатибилен со хашовите на трансакциите генерирани од JavaScript апликации.

Методот Build() го поставува хашот на трансакцијата на следниов начин: tx.TxHash = preByteHash(tx.ToBytes()).

Методот стринг ToJSON() конвертира трансакција во низа JSON.

Методот за грешка FromJSON(податоци []бајт) вчитува трансакција од форматот JSON предадена како парче бајт.

Методот Check() bool го споредува добиениот хаш од полето за хаш трансакција со хашот добиен како резултат на хеширање на оваа трансакција (игнорирање на полето за хаш).

Трансакциите се додаваат во блокот: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Структурата на податоци за блок е пообемна:

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 го складира типот на податоци, јазолот го користи и го разликува блокот од трансакција или други податоци. За блок оваа вредност е 1.

BlockHeight ја складира висината на блокот.
Временски печат.
HeaderSize е големината на блокот во бајти.
PrevBlockHash е хашот на претходниот блок, а SelfBlockHash е хашот на тековниот.
TxsHash е општ хаш на трансакции.
MerkleRoot е коренот на дрвото Merkle.

Понатаму во полињата има јавниот клуч на создавачот на блокот, потписот на креаторот, верзијата на блокот, бројот на трансакции во блокот и самите овие трансакции.

Да ги погледнеме неговите методи:
За да креирате блок, користете ја функцијата block.NewBlock(): NewBlock(prevBlockHash стринг, height int) *Block, која го зема хашот од претходниот блок и поставената висина за креираниот блок во блокчејнот. Типот на блок е исто така поставен од константата на пакетот типови:

b.DataType = types.BLOCK_TYPE.

Методот AddTx(tx *transaction.TX) додава трансакција во блок.

Методот Build() ги вчитува вредностите во полињата на блокот и го генерира и поставува неговиот тековен хаш.

Методот ToBytesHeader() []byte го конвертира заглавието на блокот (без трансакции) во парче бајт.

Методот на низа ToJSON() го конвертира блокот во формат JSON во низа претставување на податоците.

Методот за грешка FromJSON(податоци []бајт) вчитува податоци од JSON во структура на блок.

Методот Check() bool генерира хаш блок и го споредува со оној наведен во полето за хаш блок.

Методот на низа GetTxsHash() го враќа вкупниот хаш на сите трансакции во блокот.

Методот GetMerkleRoot() го одредува коренот на дрвото Merkle за трансакции во блок.

Методот Sign(privk string) потпишува блок со приватниот клуч на креаторот на блокот.

Методот SetHeight(height int) ја запишува висината на блокот во полето за структурата на блокот.

Методот GetHeight() int ја враќа висината на блокот како што е наведено во соодветното поле на структурата на блокот.

Методот ToGOBBytes() []byte кодира блок во GOB формат и го враќа како бајт парче.

Методот за грешка FromGOBBytes(податоци []бајт) запишува блок податоци во структурата на блокот од положеното парче бајт во GOB формат.

Методот на низа GetHash() го враќа хашот на дадениот блок.

Методот на низа GetPrevHash() го враќа хашот од претходниот блок.

Методот SetPublicKey(pubk string) го запишува јавниот клуч на креаторот на блокот во блокот.

Така, користејќи ги методите на објектот Block, лесно можеме да го претвориме во формат за пренос преку мрежата и зачувување во базата на податоци LevelDB.

Функциите на блокчејн пакетот се одговорни за зачувување на блокчејнот: github.com/Rusldv/bcstartup/tree/master/blockchain

За да го направите ова, блокот мора да го имплементира интерфејсот IBlock:

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

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

}

Поврзувањето со базата на податоци се креира еднаш кога пакетот се иницијализира во функцијата init():

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

CloseDB() е обвивка за db.Cloce() - повикана по работа со функциите на пакетот за да се затвори врската со базата на податоци.

Функцијата за грешка SetTargetBlockHash(hash string) го запишува хашот на тековниот блок со клучот одреден со константата BLOCK_HASH во базата на податоци.

Функцијата GetTargetBlockHash() (низа, грешка) го враќа хашот на тековниот блок зачуван во базата на податоци.

Функцијата за грешка SetTargetBlockHeight(height int) ја запишува во базата на податоци вредноста на висината на блокчејнот за јазолот со клучот одреден со константата BLOCK_HEIGHT.

Функцијата GetTargetBlockHeight() (int, error) ја враќа висината на блокчејнот за даден јазол, зачуван во базата на податоци.

Функцијата CheckBlock(block IBlock) bool проверува блок за исправност пред да го додаде овој блок во блокчејнот.

Функцијата за грешка AddBlock(block IBlock) додава блок на блокчејнот.

Функциите за преземање и гледање блокови се во датотеката explore.go на блокчејн пакетот:

Функцијата GetBlockByHash(hash стринг) (*block.Block, error) создава празен блок објект, вчитува блок во него од базата на податоци, чиј хаш му бил предаден и враќа покажувач кон него.

Создавањето на генеза блок се врши со функцијата за грешка Genesis() од датотеката genesis.go на блокчејн пакетот.

Следната статија ќе зборува за поврзување со клиентски јазол користејќи го механизмот WebSocket.

Извор: www.habr.com

Додадете коментар