Jak jsem navrhoval bloky a transakce ve své blockchainové aplikaci v Go

Aby se nakonec vytvořil blockchain, a nikoli jen databáze, musíme do svého projektu přidat 3 důležité prvky:

  • Popis datové struktury a metod bloku
  • Popis datové struktury a metod transakce
  • Funkce blockchainu, které ukládají bloky do databáze a nacházejí je pomocí jejich hashe nebo výšky (nebo jakkoli jinak).

Jak jsem navrhoval bloky a transakce ve své blockchainové aplikaci v Go

Toto je druhý článek o blockchainu pro průmysl, první tady.

Vzpomeneme na otázky, které mi kladli čtenáři k předchozímu článku této série, a je třeba poznamenat: pro uložení dat blockchainu se v tomto případě používá databáze LevelDB, ale nic nebrání použití jakékoli jiné, řekněme téže MySQL. A nyní se podívejme na strukturu těchto dat.

Začněme s transakcemi: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Zde je její datová struktura:

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
}

V TX jsou uloženy typ dat (pro transakci 2), hash této transakce, typ samotné transakce, časová značka, a také vstupy a výstupy. Vstupy TxIn uchovávají hash transakce, na kterou se odkazuje, číslo tohoto výstupu a bytecode, zatímco výstupy TxOut uchovávají nějakou hodnotu a také bytecode.

Nyní se podívejme, jaké operace může transakce provádět se svými daty, tj. prozkoumejme metody.

Pro vytvoření transakce slouží funkce transaction.NewTransaction(txtype byte) *TX.

Metoda AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) přidává vstup k transakci.

Metoda AddTxOut(value int, data []byte) (*TxOut, error) přidává výstup k transakci.

Metoda ToBytes() []byte převádí transakci na byte slice.

Interní funkce preByteHash(bytes []byte) string se používá v Build() a Check() pro zajištění kompatibility vytvářeného hashe transakcí s hashemi transakcí generovanými z aplikací na JavaScriptu.

Metoda Build() nastavuje hash transakce následujícím způsobem: tx.TxHash = preByteHash(tx.ToBytes()).

Metoda ToJSON() string převádí transakci na JSON řetězec.

Metoda FromJSON(data []byte) error načítá transakci z formátu JSON, přenášeného ve formě byte slice.

Metoda Check() bool porovnává získaný hash z pole hashe transakce s hashem, který byl získán jako výsledek hashování této transakce (bez zohlednění pole hashe).

Transakce se přidávají do bloku: github.com/Rusldv/bcstartup/blob/master/block/builder.go

Struktura dat bloku je objemnější:

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 uchovává typ dat, podle něhož uzel rozlišuje blok od transakce nebo jiných dat. Pro blok je tato hodnota rovna 1.

BlockHeight uchovává výšku bloku.
Timestamp je časová značka.
HeaderSize je velikost bloku v bajtech.
PrevBlockHash je hash předchozího bloku, a SelfBlockHash je aktuální.
TxsHash je celkový hash transakcí.
MerkleRoot je kořen Merkleova stromu.

Dále jsou v polích veřejný klíč tvůrce bloku, podpis tvůrce, verze bloku, počet transakcí v bloku a samotné transakce.

Podívejme se na jeho metody:
Pro vytvoření bloku se používá funkce block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, která přijímá hash předchozího bloku a výšku nastavenou pro vytvořený blok v blockchainu. Také se nastavuje typ bloku z konstanty balíčku types:

b.DataType = types.BLOCK_TYPE.

Metoda AddTx(tx *transaction.TX) přidává transakci do bloku.

Metoda Build() načítá hodnoty do polí bloku a generuje a nastavuje jeho aktuální hash.

Metoda ToBytesHeader() []byte převádí hlavičku bloku (bez transakcí) na bajtový řez.

Metoda ToJSON() string převádí blok do formátu JSON ve formě řetězce dat.

Metoda FromJSON(data []byte) error načítá data z JSON do struktury bloku.

Metoda Check() bool generuje hash bloku a porovnává s tím, který je zadán v poli hash bloku.

Metoda GetTxsHash() string vrací celkový hash všech transakcí v bloku.

Metoda GetMerkleRoot() nastavuje kořen Merkleova stromu pro transakce v bloku.

Metoda Sign(privk string) podepisuje blok soukromým klíčem tvůrce bloku.

Metoda SetHeight(height int) zapisuje výšku bloku do pole struktury bloku.

Metoda GetHeight() int vrací výšku bloku, jak je uvedeno v odpovídajícím poli struktury bloku.

Metoda ToGOBBytes() []byte kóduje blok do formátu GOB a vrací ho ve formě bajtového řezu.

Metoda FromGOBBytes(data []byte) error zapisuje data bloku do struktury bloku z předaného bajtového řezu ve formátu GOB.

Metoda GetHash() string vrací hash tohoto bloku.

Metoda GetPrevHash() string vrací hash předchozího bloku.

Metoda SetPublicKey(pubk string) zapisuje do bloku veřejný klíč tvůrce bloku.

Tímto způsobem můžeme pomocí metod objektu Block snadno převést do formátu pro přenos po síti a ukládání do databáze LevelDB.

Za uložení do blockchainu odpovídají funkce balíčku blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

K tomu musí blok implementovat rozhraní IBlock:

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

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

}

Připojení k databázi se vytváří jednou při inicializaci balíčku ve funkci init():

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

CloseDB() je obal pro db.Close() — je volána po práci s funkcemi balíčku pro uzavření spojení s DB.

Funkce SetTargetBlockHash(hash string) error zapisuje do DB hash aktuálního bloku s klíčem určeným konstantou BLOCK_HASH.

Funkce GetTargetBlockHash() (string, error) vrací hash aktuálního bloku uloženého v DB.

Funkce SetTargetBlockHeight(height int) error zapisuje do DB hodnotu výšky blockchainu pro uzel s klíčem určeným konstantou BLOCK_HEIGHT.

Funkce GetTargetBlockHeight() (int, error) vrací výšku blockchainu pro daný uzel uloženou v DB.

Funkce CheckBlock(block IBlock) bool provádí kontrolu bloku na správnost před přidáním tohoto bloku do blockchainu.

Funkce AddBlock(block IBlock) error přidává blok do blockchainu.

Funkce pro získání a prohlížení bloků se nacházejí v souboru explore.go balíčku blockchain:

Funkce GetBlockByHash(hash string) (*block.Block, error) vytváří prázdný objekt bloku, načítá do něj blok z DB, jehož hash byl předán, a vrací na něj ukazatel.

Vytvoření genesis bloku se provádí pomocí funkce Genesis() error ze souboru genesis.go balíčku blockchain.

V dalším článku se budeme věnovat připojení klientských uzlů pomocí mechanismu WebSocket.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster