Hoe ik blokken en transacties ontwierp in mijn Go-blockchain

Om uiteindelijk te eindigen met een blockchain en niet alleen maar een database, moeten we 3 belangrijke elementen aan ons project toevoegen:

  • Beschrijving van de blokdatastructuur en methoden
  • Beschrijving van de datastructuur en transactiemethoden
  • Blockchain-functies die blokken in een database opslaan en ze daar vinden op basis van hun hash of hoogte (of iets anders).

Hoe ik blokken en transacties ontwierp in mijn Go-blockchain

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

Als ik me de vragen herinner die lezers mij stelden over het vorige artikel in deze serie, moet worden opgemerkt: in dit geval wordt de LevelDB-database gebruikt om blockchain-gegevens op te slaan, maar niets belet je om een ​​andere, bijvoorbeeld MySQL, te gebruiken. Laten we nu eens kijken naar de structuur van deze gegevens.

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
}

TX slaat het gegevenstype op (voor transactie 2), de hash van die transactie, het type transactie zelf, een tijdstempel en invoer en uitvoer. TxIn-ingangen slaan de hash op van de transactie waarnaar de uitvoer verwijst, het nummer van deze uitvoer en bytecode, en TxOut-uitgangen slaan een waarde en ook bytecode op.

Laten we nu eens kijken welke acties een transactie op zijn gegevens kan uitvoeren, d.w.z. Laten we naar de methoden kijken.

Om een ​​transactie aan te maken, gebruikt u de functie transaction.NewTransaction(txtype byte) *TX.

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

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

De ToBytes() []byte-methode verandert de transactie in een byteplak.

De interne functie preByteHash(bytes []byte) string wordt gebruikt in Build() en Check() om de gegenereerde transactie-hash compatibel te maken met transactie-hashes gegenereerd door JavaScript-applicaties.

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

De tekenreeksmethode ToJSON() converteert een transactie naar een JSON-tekenreeks.

De foutmethode FromJSON(data []byte) laadt een transactie uit het JSON-formaat dat wordt doorgegeven als een bytesegment.

De Check() bool-methode vergelijkt de resulterende hash uit het transactiehashveld met de hash die wordt verkregen als resultaat van het hashen van deze transactie (waarbij het hashveld wordt genegeerd).

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

De blokdatastructuur 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 datatype op, de node gebruikt het en onderscheidt het blok van een transactie of andere data. Voor een blok is deze waarde 1.

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

Verderop in de velden staat de publieke sleutel van de maker van het blok, de handtekening van de maker, de versie van het blok, het aantal transacties in het blok en deze transacties zelf.

Laten we eens kijken naar de methoden:
Om een ​​blok te maken, gebruikt u de functie block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, dat de hash van het vorige blok en de hoogte neemt die is ingesteld voor het gemaakte blok in de blockchain. Het bloktype wordt ook ingesteld op basis van de pakketconstante van het type:

b.DataType = types.BLOCK_TYPE.

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

De Build()-methode laadt waarden in de velden van het blok en genereert en stelt de huidige hash in.

De ToBytesHeader() []byte-methode converteert de blokheader (zonder transacties) naar een byteplak.

De tekenreeksmethode ToJSON() converteert het blok naar JSON-indeling in een tekenreeksrepresentatie van de gegevens.

De foutmethode FromJSON(data []byte) laadt gegevens uit JSON in een blokstructuur.

De Check() bool-methode genereert een blok-hash en vergelijkt deze met de hash die is opgegeven in het blok-hash-veld.

De tekenreeksmethode GetTxsHash() retourneert de totale hash van alle transacties in het blok.

De GetMerkleRoot()-methode specificeert de wortel van de Merkle-boom voor transacties in een blok.

De Sign(privk string)-methode ondertekent een blok met de privésleutel van de maker van het blok.

De SetHeight(height int)-methode schrijft de hoogte van het blok naar het blokstructuurveld.

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

De ToGOBBytes() []byte-methode codeert een blok in GOB-indeling en retourneert dit als een byteplak.

De foutmethode FromGOBBytes(data []byte) schrijft blokgegevens naar de blokstructuur vanuit het doorgegeven bytesegment in GOB-formaat.

De GetHash() stringmethode retourneert de hash van het gegeven blok.

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

De SetPublicKey(pubk string) methode schrijft de publieke sleutel van de maker van het blok naar het blok.

Met behulp van de methoden van het Block-object kunnen we het dus eenvoudig converteren naar een formaat voor verzending via het netwerk en opslaan in de LevelDB-database.

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

Om dit te doen, moet het blok de IBlock-interface implementeren:

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

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

}

De databaseverbinding wordt één keer gemaakt wanneer het pakket wordt geïnitialiseerd in de functie init():

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

CloseDB() is een wrapper voor db.Cloce() - aangeroepen na het werken met de pakketfuncties om de verbinding met de database te sluiten.

De foutfunctie SetTargetBlockHash(hash string) schrijft de hash van het huidige blok met de sleutel gespecificeerd door de constante BLOCK_HASH naar de database.

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

De foutfunctie SetTargetBlockHeight(height int) schrijft de waarde van de blockchain-hoogte voor het knooppunt naar de database met de sleutel die is opgegeven door de constante BLOCK_HEIGHT.

De functie GetTargetBlockHeight() (int, error) retourneert de hoogte van de blockchain voor een bepaald knooppunt, opgeslagen in de database.

De CheckBlock(block IBlock) bool-functie controleert een blok op juistheid voordat dit blok aan de blockchain wordt toegevoegd.

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

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

De functie GetBlockByHash(hash string) (*block.Block, error) creëert een leeg blokobject, laadt daarin een blok vanuit de database, waarvan de hash eraan is doorgegeven, en retourneert er een verwijzing naar.

Het aanmaken van een genesisblok wordt uitgevoerd door de Genesis()-foutfunctie uit het genesis.go-bestand van het blockchain-pakket.

In het volgende artikel wordt gesproken over het verbinden van clients met een knooppunt met behulp van het WebSocket-mechanisme.

Bron: www.habr.com

Voeg een reactie