Hvordan jeg designede blokke og transaktioner i min blockchain med Go

For a blockchain to ultimately emerge rather than just a database, we need to add three important elements to our project:

  • Description of the data structure and methods of a block
  • Description of the data structure and methods of a transaction
  • Blockchain functions that store blocks in the database and retrieve them by their hash or height (or in other ways).

Hvordan jeg designede blokke og transaktioner i min blockchain med Go

This is the second article about blockchain for industry; the first one her.

Recalling the questions that readers asked me about the previous article in this series, it should be noted: LevelDB is used to store blockchain data in this case, but there is nothing preventing the use of any other, say, MySQL. And now let's delve into the structure of this data.

Let's start with transactions: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Here is its data structure:

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
}

In TX, the data type (2 for a transaction), the hash of this transaction, the type of transaction, the timestamp, as well as inputs and outputs are stored. Inputs TxIn store the hash of the transaction referenced by the output, the index of that output, and the bytecode, while outputs TxOut store some value and also bytecode.

Now let's look at what actions a transaction can perform on its data, i.e., let's examine the methods.

The function transaction.NewTransaction(txtype byte) *TX is used to create a transaction.

The method AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) adds an input to the transaction.

The method AddTxOut(value int, data []byte) (*TxOut, error) adds an output to the transaction.

The method ToBytes() []byte converts the transaction into a byte slice.

The internal function preByteHash(bytes []byte) string is used in Build() and Check() to ensure compatibility of the generated transaction hash with hashes generated from JavaScript applications.

The method Build() sets the transaction hash as follows: tx.TxHash = preByteHash(tx.ToBytes()).

The method ToJSON() string converts the transaction to a JSON string.

The method FromJSON(data []byte) error loads the transaction from the JSON format provided as a byte slice.

The method Check() bool compares the received hash from the transaction hash field with the hash obtained from hashing this transaction (excluding the hash field).

Transactions are added to the block: github.com/Rusldv/bcstartup/blob/master/block/builder.go

The data structure of the block is more comprehensive:

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 gemmer datatypen, som noderne bruger til at skelne blokke fra transaktioner eller andre data. For en blok er denne værdi lig med 1.

BlockHeight gemmer blokkens højde.
Timestamp gemmer tidsstemplet.
HeaderSize gemmer størrelsen af blokken i bytes.
PrevBlockHash er hash af den forrige blok, mens SelfBlockHash er den nuværende.
TxsHash er den samlede hash af transaktionerne.
MerkleRoot er roden af Merkle-træet.

Derefter indeholder felterne den offentlige nøgle fra blokskaberen, signaturen fra skaberen, blokkens version, antallet af transaktioner i blokken og selve disse transaktioner.

Lad os se på dens metoder:
For at oprette en blok anvendes funktionen block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, som modtager hash af den forrige blok og højden, der er indstillet for den oprettede blok i blockchainen. Desuden bestemmes blokkens type fra konstanten i pakken types:

b.DataType = types.BLOCK_TYPE.

Metoden AddTx(tx *transaction.TX) tilføjer en transaktion til blokken.

Metoden Build() indlæser værdierne i blokkens felter og genererer og sætter dens nuværende hash.

Metoden ToBytesHeader() []byte konverterer blokkens header (uden transaktioner) til et byte-slice.

Metoden ToJSON() string konverterer blokken til JSON-format i en stråiform.

Metoden FromJSON(data []byte) error indlæser data fra JSON til blokkens struktur.

Metoden Check() bool genererer hash af blokken og sammenligner med den angivne hash i blokkens hashfelt.

Metoden GetTxsHash() string returnerer den samlede hash af alle transaktioner i blokken.

Metoden GetMerkleRoot() sætter roden af Merkle-træet for transaktioner i blokken.

Metoden Sign(privk string) underskriver blokken med skaberens private nøgle.

Metoden SetHeight(height int) skriver blokkens højde ind i blokkens strukturfelt.

Metoden GetHeight() int returnerer blokkens højde, som angivet i det relevante strukturfelt.

Metoden ToGOBBytes() []byte kodificerer blokken i GOB-format og returnerer den som et byte-slice.

Metoden FromGOBBytes(data []byte) error skriver blokkens data ind i blokkens struktur fra det modtagne byte-slice i GOB-format.

Metoden GetHash() string returnerer hash af denne blok.

Metoden GetPrevHash() string returnerer hash af den forrige blok.

Metoden SetPublicKey(pubk string) skriver den offentlige nøgle fra blokskaberen ind i blokken.

Dermed kan vi ved hjælp af Block-objektets metoder nemt konvertere det til et format til overførsel over netværket og gemme det i LevelDB.

Funktionerne i blockchain-pakken er ansvarlige for at gemme i blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

For dette skal blokken implementere IBlock-grænsefladen:

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

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

}

Forbindelsen til databasen oprettes én gang ved initialisering af pakken i init()-funktionen:

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

CloseDB() er en wrapper til db.Close() — kaldes efter arbejde med pakkens funktioner for at lukke forbindelsen til databasen.

Funktionen SetTargetBlockHash(hash string) error skriver hash af den aktuelle blok i databasen med nøglen givet af konstanten BLOCK_HASH.

Funktionen GetTargetBlockHash() (string, error) returnerer hash af den aktuelle blok, der er gemt i databasen.

Funktionen SetTargetBlockHeight(height int) error skriver højden af blockchain til noden i databasen med nøglen givet af konstanten BLOCK_HEIGHT.

Funktionen GetTargetBlockHeight() (int, error) returnerer højden af blockchain for denne node, gemt i databasen.

Funktionen CheckBlock(block IBlock) bool udfører en kontrol af blokken for korrekthed, før denne blok tilføjes til blockchain.

Funktionen AddBlock(block IBlock) error tilføjer blokken til blockchain.

Funktionerne til at hente og se blokke findes i filen explore.go i blockchain-pakken:

Funktionen GetBlockByHash(hash string) (*block.Block, error) opretter et tomt blokobjekt, indlæser blokken fra databasen, hvis hash er givet, og returnerer en pointer til det.

Oprettelse af genesis-blokken udføres af funktionen Genesis() error fra filen genesis.go i blockchain-pakken.

I den næste artikel vil der blive talt om tilslutning til noden af klienter ved hjælp af WebSocket-mekanismen.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster