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).
Dit is het tweede artikel over blockchain voor de industrie, het eerste
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:
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:
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:
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