Ahogyan a blokkokat és tranzakciókat terveztem a saját blokkláncomon Go nyelven

Ahhoz, hogy végül blokkláncunk legyen, és ne csupán adatbázis, három fontos elemet kell hozzáadnunk a projektünkhöz:

  • A blokk adatainak és módszereinek leírása
  • A tranzakció adatai és módszereinek leírása
  • A blokklánc funkciói, amelyek a blokkokat tárolják az adatbázisban, és megtalálják őket hash alapján vagy magasság szerint (vagy más módon).

Ahogyan a blokkokat és tranzakciókat terveztem a saját blokkláncomon Go nyelven

Ez a második cikk a blokkláncról az ipar számára, az első itt.

Emlékezve a kérdésekre, amelyeket az előző cikkemhez tettek fel az olvasók, érdemes megjegyezni: a blokklánc adatok tárolására ebben az esetben LevelDB adatbázist használunk, de semmi nem akadályozza meg, hogy bármely másikat használjunk, mondjuk a MySQL-t. Most vizsgáljuk meg az adatok struktúráját.

Kezdjük a tranzakciókkal: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Íme, az adatszerkezete:

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
}

A TX tárolja az adat típusát (a tranzakciónál 2), a tranzakció hash-ét, a tranzakció típusát, az időbélyeget, valamint a bemeneteket és kimeneteket. A TxIn bemenetek tárolják a hivatkozott tranzakció hash-ét, annak kimenet számát és a byte kódot, míg a TxOut kimenetek tárolnak egy értéket és szintén byte kódot.

Most nézzük meg, milyen műveleteket hajthat végre a tranzakció az adataival, azaz vizsgáljuk meg a módszereket.

A tranzakció létrehozására a transaction.NewTransaction(txtype byte) *TX függvény szolgál.

Az AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) metódus új bemenetet ad a tranzakcióhoz.

Az AddTxOut(value int, data []byte) (*TxOut, error) metódus új kimenetet ad a tranzakcióhoz.

A ToBytes() []byte metódus átalakítja a tranzakciót egy byte sorozattá.

A belső preByteHash(bytes []byte) string függvény a Build() és Check() metódusokban alkalmazásra kerül a generált tranzakciós hash-ek és a JavaScript alkalmazásokból származó hash-ek kompatibilitásának biztosítása érdekében.

A Build() metódus a tranzakció hash-ét a következőképpen állítja be: tx.TxHash = preByteHash(tx.ToBytes()).

A ToJSON() string metódus a tranzakciót JSON stringgé alakítja.

A FromJSON(data []byte) error metódus a tranzakciót betölti a JSON formátumból, amely byte slice formájában lett átadva.

A Check() bool metódus összehasonlítja a tranzakció hash mezőjében lévő hash-t azzal a hash-tel, amely a tranzakció hash-elésének eredményeként keletkezett (a hash mező figyelembevételével nélkül).

A tranzakciókat a blokkokba adjuk hozzá: github.com/Rusldv/bcstartup/blob/master/block/builder.go

A blokk adatszerkezete lényegesen összetettebb:

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
}

A DataType tárolja az adat típusát, amely alapján a node meg tudja különböztetni a blokkot a tranzakcióktól vagy egyéb adatforrásoktól. Blokk esetén ez az érték 1.

A BlockHeight tárolja a blokk magasságát.
A Timestamp az időbélyeg.
A HeaderSize a blokk mérete byte-ban.
A PrevBlockHash a megelőző blokk hash értéke, míg a SelfBlockHash a jelenlegi.
A TxsHash a tranzakciók összesített hash értéke.
A MerkleRoot a Merkle fágy gyökere.

Ezután a mezők tartalmazzák a blokk létrehozójának nyilvános kulcsát, a létrehozó aláírását, a blokk verzióját, a blokkban található tranzakciók számát és magukat a tranzakciókat.

Vizsgáljuk meg a metódusait:
A blokk létrehozásához a block.NewBlock() függvényt használjuk: NewBlock(prevBlockHash string, height int) *Block, amely a megelőző blokk hash értékét és a blokkláncban létrehozott blokk magasságát veszi figyelembe. A blokk típusát a types csomag konstansából állítjuk be:

b.DataType = types.BLOCK_TYPE.

Az AddTx(tx *transaction.TX) metódus tranzakciót ad hozzá a blokkhoz.

A Build() metódus betölti a mezők értékeit és generálja, valamint beállítja a blokk aktuális hash értékét.

A ToBytesHeader() []byte metódus a blokk fejlécek (tranzakciók nélkül) byte szlájzba konvertálja.

A ToJSON() string metódus a blokkot JSON formátumba alakítja, sztring reprezentációban.

A FromJSON(data []byte) error metódus a JSON-ból betölti az adatokat a blokk struktúrájába.

A Check() bool metódus generálja a blokk hash értékét és összehasonlítja a blokk hash mezőjében megadott értékkel.

A GetTxsHash() string metódus visszaadja a blokkban található tranzakciók összesített hash értékét.

A GetMerkleRoot() metódus beállítja a tranzakciók Merkle fájának gyökér értékét a blokkban.

A Sign(privk string) metódus a blokkot aláírja a blokk létrehozójának privát kulcsával.

A SetHeight(height int) metódus beírja a blokk magasságát a blokk struktúrájának mezőjébe.

A GetHeight() int metódus visszaadja a blokk magasságát, ahogy az a struktúra megfelelő mezőjében van megadva.

A ToGOBBytes() []byte metódus a blokkot GOB formátumban kódolja, és visszaadja byte szlájzként.

A FromGOBBytes(data []byte) error metódus a blokk adatait GOB formátumban írja be a blokk struktúrájába a megadott byte szlájzból.

A GetHash() string metódus visszaadja az adott blokk hash értékét.

A GetPrevHash() string metódus visszaadja a megelőző blokk hash értékét.

A SetPublicKey(pubk string) metódus a blokkba beírja a blokk létrehozójának nyilvános kulcsát.

Így a Block objektum módszereivel könnyen átkonvertálhatjuk azt olyan formátumba, amely alkalmas hálózati továbbításra és a LevelDB adatbázisban való tárolásra.

A blokkláncba való tárolásért a blockchain csomag funkciói felelnek: github.com/Rusldv/bcstartup/tree/master/blockchain

Ehhez a blokknak meg kell valósítania az IBlock interfészt:

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

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

}

Az adatbázishoz való kapcsolódást egyszer hozzuk létre a csomag inicializálásakor az init() funkcióban:

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

A CloseDB() a db.Close() köré csomagolt hívás — ezt a csomag funkcióival való munka után hívják, hogy bezárja az adatbázis-kapcsolatot.

A SetTargetBlockHash(hash string) error funkció a BLOCK_HASH állandóval megadott kulccsal a jelenlegi blokk hash-ét írja az adatbázisba.

A GetTargetBlockHash() (string, error) funkció visszaadja a jelenlegi blokk hash-ét, amely az adatbázisban található.

A SetTargetBlockHeight(height int) error funkció a BLOCK_HEIGHT állandóval megadott kulccsal az adatbázisba írja a blokklánc magasságát a csomópont számára.

A GetTargetBlockHeight() (int, error) funkció visszaadja a blokk lánc magasságát a megadott csomóponthoz, amely az adatbázisban van tárolva.

A CheckBlock(block IBlock) bool funkció a blokk érvényességének ellenőrzését végzi el, mielőtt ezt a blokkot hozzáadnánk a blokklánchoz.

Az AddBlock(block IBlock) error funkció hozzáadja a blokkot a blokklánchoz.

A blokkok lekérésére és megjelenítésére szolgáló funkciók a blockchain csomag explore.go fájljában találhatók:

A GetBlockByHash(hash string) (*block.Block, error) funkció egy üres blokkobjektumot hoz létre, betölti a blokkot az adatbázisból, amelynek a hash-e át van adva, és visszaadja rá a mutatót.

A genézis blokk létrehozását a Genesis() error funkció végzi a blockchain csomag genesis.go fájljából.

A következő cikkben a kliensek csomóponthoz való csatlakozásáról lesz szó a WebSocket mechanizmus segítségével.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster