Hoe ik blokken en transacties in mijn blockchain op Go heb ontworpen

Om uiteindelijk een blockchain te creƫren en geen gewoon database, moeten we drie belangrijke elementen aan ons project toevoegen:

  • Beschrijving van de datastructuur en methoden van een blok
  • Beschrijving van de datastructuur en methoden van een transactie
  • Blockchainfuncties die blokken in de database opslaan en ze daar vinden op basis van hun hash of hoogte (of op een andere manier).

Hoe ik blokken en transacties in mijn blockchain op Go heb ontworpen

Dit is het tweede artikel over blockchain voor de industrie, het eerste here.

Terugdenkend aan de vragen die lezers me stelden over het vorige artikel in deze reeks, is het belangrijk om op te merken: voor de opslag van blockchain-gegevens wordt in dit geval de LevelDB-database gebruikt, maar er staat niets in de weg om een andere database zoals MySQL te gebruiken. Laten we nu de structuur van deze gegevens bekijken.

Laten we beginnen met transacties: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Hier is de datastructuur:

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 worden het type gegevens (voor een transactie 2), de hash van deze transactie, het type van de transactie, de timestamp, evenals de invoer en uitvoer opgeslagen. De invoeren TxIn slaan de hash van de transactie op waarop ze verwijzen, het nummer van deze uitvoer en de bytecode, terwijl de uitvoeren TxOut een waarde en ook bytecode opslaan.

Laten we nu eens kijken welke acties een transactie met zijn gegevens kan uitvoeren, dat wil zeggen, laten we de methoden bekijken.

De functie transaction.NewTransaction(txtype byte) *TX dient voor het aanmaken van een transactie.

De methode AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) voegt een invoer aan de transactie toe.

De methode AddTxOut(value int, data []byte) (*TxOut, error) voegt een uitvoer aan de transactie toe.

De methode ToBytes() []byte zet de transactie om in een byte-array.

De interne functie preByteHash(bytes []byte) string wordt gebruikt in Build() en Check() om de compatibiliteit van de gemaakte hash van transacties met de hashes van transacties die door JavaScript-applicaties worden gegenereerd te waarborgen.

De methode Build() stelt de hash van de transactie als volgt in: tx.TxHash = preByteHash(tx.ToBytes()).

De methode ToJSON() string zet de transactie om in een JSON-string.

De methode FromJSON(data []byte) error laadt de transactie uit een JSON-formaat dat wordt doorgegeven als een byte-array.

De methode Check() bool vergelijkt de hash die is verkregen uit het hash-veld van de transactie met de hash die is verkregen door deze transactie te hashen (zonder rekening te houden met het hash-veld).

Transacties worden aan een blok toegevoegd: github.com/Rusldv/bcstartup/blob/master/block/builder.go

De datastructuur van een blok is omvangrijker:

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 slaat het type gegevens op, waardoor de node het blok van een transactie of andere gegevens kan onderscheiden. Voor een blok is deze waarde gelijk aan 1.

BlockHeight slaat de hoogte van het blok op.
Timestamp slaat een tijdstempel op.
HeaderSize slaat de grootte van het blok in bytes op.
PrevBlockHash is de hash van het vorige blok, en SelfBlockHash is de huidige.
TxsHash is de algemene hash van de transacties.
MerkleRoot is de root van de Merkle-boom.

Daarna bevinden zich in de velden de publieke sleutel van de blokmaker, de handtekening van de maker, de versie van het blok, het aantal transacties in het blok en de transacties zelf.

Laten we zijn methoden bekijken:
Om een blok te maken, wordt de functie block.NewBlock() gebruikt: NewBlock(prevBlockHash string, height int) *Block, die de hash van het vorige blok en de hoogte voor het gemaakte blok in de blockchain accepteert. Ook wordt het type blok ingesteld uit de constante van het pakket types:

b.DataType = types.BLOCK_TYPE.

De methode AddTx(tx *transaction.TX) voegt een transactie aan het blok toe.

De methode Build() laadt de waarden in de blokvelden en genereert en stelt de huidige hash in.

De methode ToBytesHeader() []byte converteert de header van het blok (zonder transacties) naar een byte-slice.

De methode ToJSON() string converteert het blok naar JSON-formaat als een stringrepresentatie van de gegevens.

De methode FromJSON(data []byte) error laadt gegevens uit JSON in de structuur van het blok.

De methode Check() bool genereert de hash van het blok en vergelijkt deze met de opgegeven hash in het veld van het blok.

De methode GetTxsHash() string retourneert de algemene hash van alle transacties in het blok.

De methode GetMerkleRoot() stelt de root van de Merkle-boom voor de transacties in het blok in.

De methode Sign(privk string) ondertekent het blok met de privƩr sleutel van de blokmaker.

De methode SetHeight(height int) slaat de hoogte van het blok op in het veld van de blokstructuur.

De methode GetHeight() int retourneert de hoogte van het blok zoals opgegeven in het overeenkomstige veld van de blokstructuur.

De methode ToGOBBytes() []byte codeert het blok in GOB-formaat en retourneert het als een byte-slice.

De methode FromGOBBytes(data []byte) error schrijft de gegevens van het blok in de blokstructuur vanuit de meegegeven byte-slice in GOB-indeling.

De methode GetHash() string retourneert de hash van dit blok.

De methode GetPrevHash() string retourneert de hash van het vorige blok.

De methode SetPublicKey(pubk string) slaat de publieke sleutel van de blokmaker op in het blok.

Zo kunnen we met behulp van de methoden van het Block-object eenvoudig het formaat voor netwerkverzending en opslag in de LevelDB-database converteren.

De functies van het blockchain-pakket zijn verantwoordelijk voor het opslaan in de blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain

Hiervoor moet een blok de interface IBlock implementeren:

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

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

}

De verbinding met de database wordt ƩƩn keer aangemaakt bij het initialiseren van het pakket in de functie init():

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

CloseDB() is een wrapper voor db.Close() — deze wordt aangeroepen na het werken met de functies van het pakket om de verbinding met de database te sluiten.

De functie SetTargetBlockHash(hash string) error schrijft de hash van het huidige blok met de sleutel gedefinieerd door de constante BLOCK_HASH in de database.

De functie GetTargetBlockHash() (string, error) retourneert de hash van het huidige blok, opgeslagen in de database.

De functie SetTargetBlockHeight(height int) error schrijft de waarde van de blokhoogte voor de node met de sleutel gedefinieerd door de constante BLOCK_HEIGHT in de database.

De functie GetTargetBlockHeight() (int, error) retourneert de hoogte van de blockchain voor deze node, opgeslagen in de database.

De functie CheckBlock(block IBlock) bool voert een controle uit op het blok op geldigheid voordat dit blok aan de blockchain wordt toegevoegd.

De functie AddBlock(block IBlock) error voegt een blok toe aan de blockchain.

De functies voor het ophalen en bekijken van blokken bevinden zich in het bestand explore.go van het blockchain-pakket:

De functie GetBlockByHash(hash string) (*block.Block, error) creƫert een leeg blokobject, laadt het blok uit de database waarvan de hash is doorgegeven en retourneert een verwijzing naar dit blok.

De creatie van het genese blok gebeurt met de functie Genesis() error uit het bestand genesis.go van het blockchain-pakket.

In het volgende artikel zal het gaan over de verbinding met de clientnodes via het WebSocket-mechanisme.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster