Для таго, каб у канчатковым рахунку атрымалася блокчейн, а не проста база дадзеных, нам трэба дадаць у свой праект 3 важныя элементы:
- Апісанне структуры дадзеных і метадаў блока
- Апісанне структуры даных і метадаў транзакцыі
- Функцыі блокчейна, якія захоўваюць блокі ў БД і знаходзяць іх тамака па іх хешу або вышыні (ці яшчэ як небудзь).
Гэта другі артыкул пра блокчэйн для прамысловасці, першы
Успамінаючы пытанні, якія мне задавалі чытачы да папярэдняга артыкула гэтага цыклу, варта адзначыць: для захоўвання дадзеных блокчейна ў дадзеным выпадку выкарыстоўваецца база дадзеных LevelDB, але ні чаго не мяшае выкарыстоўваць любую іншую, скажам тую ж MySQL. А зараз разбяромся са структурай гэтых дадзеных.
Пачнём з транзакцый:
Вось яе структура дадзеных:
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 захоўваюць, якое-небудзь значэнне і таксама байткод.
Цяпер паглядзім, якія дзеянні над сваімі дадзенымі можа выконваць транзакцыя, г.зн. разбяром метады.
Для стварэння транзакцыі служыць функцыя transaction.NewTransaction(txtype byte) *TX.
Метад AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) дадае ўваход да транзакцыі.
Метад AddTxOut(value int, data []byte) (*TxOut, error) дадае выйсце да транзакцыі.
Метад ToBytes() []byte ператварае транзакцыю ў байтавы зрэз.
Унутраная функцыя preByteHash(bytes []byte) string ужываецца ў Build() і Check() для сумяшчальнасці стваранага хеша транзакцый з хэшамі транзакцый генераванымі з прыкладанняў на JavaScript.
Метад Build() задае хэш транзакцыі наступным чынам: tx.TxHash = preByteHash(tx.ToBytes()).
Метад ToJSON() string пераўтворыць транзакцыю ў JSON радок.
Метад FromJSON(data []byte) error загружае транзакцыю з фармату JSON, перададзенага ў выглядзе байтавага слайса.
Метад Check() bool параўноўвае атрыманых хэш з поля хэша транзакцыі з хэшам, атрыманым у выніку хэшавання гэтай транзакцыі (без уліку поля хеша).
Транзакцыі дадаюцца ў блок:
Структура дадзеных блока больш аб'ёмная:
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 захоўвае вышыню блока.
Timestamp часовую пазнаку.
HeaderSize памер блока ў байтах.
PrevBlockHash хэш папярэдняга блока, а SelfBlockHash - бягучага.
TxsHash - гэта агульны хэш транзакцый.
MerkleRoot - корань дрэва Меркла.
Далей у палях знаходзіцца публічны ключ стваральніка блока, подпіс стваральніка, версія блока, колькасць транзакцый у блоку і ўласна самі гэтыя транзакцыі.
Разгледзім яго метады:
Для стварэння блока ўжываецца функцыя block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, якая прымае хэш папярэдняга блока і вышыню ўсталяваную для створанага блока ў блокчейне. Таксама задаецца тып блока з канстанты пакета types:
b.DataType = types.BLOCK_TYPE.
Метад AddTx(tx *transaction.TX) дадае транзакцыю ў блок.
Метад Build() загружае значэнні ў палі блока і генеруе і ўсталёўвае яго бягучы хэш.
Метад ToBytesHeader() []byte перакладае загаловак блока (без транзакцый) у байтавы слайс.
Метад ToJSON() string перакладае блок у фармат JSON у радковым уяўленні дадзеных.
Метад FromJSON(data []byte) error загружае дадзеныя з JSON у структуру блока.
Метад Check() bool генеруе хэш блока і параўноўвае з зададзеным у поле хеша блока.
Метад GetTxsHash() string вяртае агульны хэш ўсіх транзакцый у блоку.
Метад GetMerkleRoot() задае корань дрэва Меркла для транзакцый у блоку.
Метад Sign (privk string) падпісвае блок прыватным дзюбай стваральніка блока.
Метад SetHeight (height int) запісвае вышыню блока ў поле структуры блока.
Метад GetHeight() int вяртае вышыню блока, бо паказана ў адпаведным полі структуры блока.
Метад ToGOBBytes() []byte кадуе блок у GOB фармат і вяртае яго ў выглядзе байтавага слайса.
Метад FromGOBBytes(data []byte) error запісвае дадзеныя блока ў структуру блока з перададзенага байтавага слайса ў фармаце GOB.
Метад GetHash() string вяртае хэш дадзенага блока.
Метад GetPrevHash() string вяртае хэш папярэдняга блока.
Метад SetPublicKey (pubk string) запісвае ў блок публічны ключ стваральніка блока.
Такім чынам, з дапамогай метадаў аб'екта Block мы можам лёгка канвертаваць яго ў фармат для перадачы па сетцы і захавання ў базу дадзеных LevelDB.
За захаванні ў блокчейн адказваюць функцыі пакета 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) error запісвае ў БД хэш бягучага блока з ключом зададзеным канстантай BLOCK_HASH.
Функцыя GetTargetBlockHash() (string, error) вяртае хэш бягучага блока, які захоўваецца ў БД.
Функцыя SetTargetBlockHeight(height int) error запісвае ў БД значэнне вышыні блокчейна для ноды з ключом зададзеным канстантай BLOCK_HEIGHT.
Функцыя GetTargetBlockHeight() (int, error) вяртае вышыню блокчейна для дадзенай ноды, якая захоўваецца ў БД.
Функцыя CheckBlock(block IBlock) bool выконвае праверку блока на карэктнасць перад даданнем гэтага блока ў блокчэйн.
Функцыя AddBlock(block IBlock) error дадае блок у блокчейн.
Функцыі для атрымання і прагляду блокаў знаходзяцца ў файле explore.go пакета blockchain:
Функцыя GetBlockByHash(hash string) (*block.Block, error) стварае пусты аб'ект блока, загружае туды блок з БД хэш якога ёй перададзены і вяртае на яго паказальнік.
Стварэнне блока генезісу ажыццяўляецца функцыяй Genesis() error з файла genesis.go пакета blockchain.
У наступным артыкуле прамова пайдзе аб падлучэнні да ноды кліентаў з дапамогай механізму WebSocket.
Крыніца: habr.com