Per acabar amb una cadena de blocs i no només una base de dades, hem d'afegir 3 elements importants al nostre projecte:
- Descripció de l'estructura i mètodes de dades del bloc
- Descripció de l'estructura de dades i mètodes de transacció
- Funcions de cadena de blocs que guarden blocs en una base de dades i els troben allà pel seu hash o alçada (o una altra cosa).
Aquest és el segon article sobre blockchain per a la indústria, el primer
Recordant les preguntes que em van fer els lectors sobre l'article anterior d'aquesta sèrie, cal tenir en compte: en aquest cas, la base de dades LevelDB s'utilitza per emmagatzemar dades de blockchain, però res no impedeix utilitzar cap altre, per exemple, MySQL. Vegem ara l'estructura d'aquestes dades.
Comencem amb les transaccions:
Aquesta és la seva estructura de dades:
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 emmagatzema el tipus de dades (per a la transacció 2), el hash d'aquesta transacció, el tipus de transacció en si, una marca de temps i entrades i sortides. Les entrades TxIn emmagatzemen el hash de la transacció a la sortida de la qual es fa referència, el número d'aquesta sortida i el bytecode, i les sortides TxOut emmagatzemen algun valor i també bytecode.
Ara vegem quines accions pot realitzar una transacció sobre les seves dades, és a dir. Vegem els mètodes.
Per crear una transacció, utilitzeu la funció transaction.NewTransaction(txtype byte) *TX.
El mètode AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) afegeix una entrada a la transacció.
El mètode AddTxOut(valor int, dades []byte) (*TxOut, error) afegeix una sortida a la transacció.
El mètode ToBytes() []byte converteix la transacció en una porció de bytes.
La cadena de funció interna preByteHash(bytes []byte) s'utilitza a Build() i Check() per fer compatible el hash de transacció generat amb els hash de transacció generats a partir d'aplicacions JavaScript.
El mètode Build() estableix el hash de la transacció de la manera següent: tx.TxHash = preByteHash(tx.ToBytes()).
El mètode de cadena ToJSON() converteix una transacció en una cadena JSON.
El mètode d'error FromJSON(data []byte) carrega una transacció del format JSON passat com a porció de bytes.
El mètode bool Check() compara el hash resultant del camp hash de la transacció amb el hash obtingut com a resultat del hash d'aquesta transacció (ignorant el camp hash).
Les transaccions s'afegeixen al bloc:
L'estructura de dades del bloc és més voluminosa:
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 emmagatzema el tipus de dades, el node l'utilitza i distingeix el bloc d'una transacció o d'altres dades. Per a un bloc, aquest valor és 1.
BlockHeight emmagatzema l'alçada del bloc.
Marca de temps Marca de temps.
HeaderSize és la mida del bloc en bytes.
PrevBlockHash és el hash del bloc anterior i SelfBlockHash és el hash del bloc actual.
TxsHash és un hash general de transaccions.
MerkleRoot és l'arrel de l'arbre Merkle.
A més, als camps hi ha la clau pública del creador del bloc, la signatura del creador, la versió del bloc, el nombre de transaccions al bloc i aquestes transaccions en si.
Vegem els seus mètodes:
Per crear un bloc, utilitzeu la funció block.NewBlock(): NewBlock(prevBlockHash string, height int) *Block, que pren el hash del bloc anterior i l'alçada establerta per al bloc creat a la cadena de blocs. El tipus de bloc també s'estableix des de la constant del paquet de tipus:
b.DataType = types.BLOCK_TYPE.
El mètode AddTx(tx *transaction.TX) afegeix una transacció a un bloc.
El mètode Build() carrega valors als camps del bloc i genera i estableix el seu hash actual.
El mètode ToBytesHeader() []byte converteix la capçalera del bloc (sense transaccions) en una porció de bytes.
El mètode de cadena ToJSON() converteix el bloc al format JSON en una representació de cadena de les dades.
El mètode d'error FromJSON(data []byte) carrega dades de JSON en una estructura de blocs.
El mètode bool Check() genera un hash de bloc i el compara amb l'especificat al camp hash de bloc.
El mètode de cadena GetTxsHash() retorna el hash total de totes les transaccions del bloc.
El mètode GetMerkleRoot() especifica l'arrel de l'arbre Merkle per a les transaccions en un bloc.
El mètode Sign(privk string) signa un bloc amb la clau privada del creador del bloc.
El mètode SetHeight(height int) escriu l'alçada del bloc al camp de l'estructura del bloc.
El mètode GetHeight() int retorna l'alçada del bloc tal com s'especifica al camp corresponent de l'estructura del bloc.
El mètode ToGOBBytes() []byte codifica un bloc en format GOB i el retorna com a porció de bytes.
El mètode d'error FromGOBBytes(data []byte) escriu les dades del bloc a l'estructura del bloc des del segment de bytes passat en format GOB.
El mètode de cadena GetHash() retorna el hash del bloc donat.
El mètode de cadena GetPrevHash() retorna el hash del bloc anterior.
El mètode SetPublicKey(cadena pubk) escriu la clau pública del creador del bloc al bloc.
Així, utilitzant els mètodes de l'objecte Block, podem convertir-lo fàcilment en un format per a la transmissió a la xarxa i desar-lo a la base de dades LevelDB.
Les funcions del paquet blockchain s'encarreguen de desar a la blockchain:
Per fer-ho, el bloc ha d'implementar la interfície IBlock:
type IGOBBytes interface {
ToGOBBytes() []byte
FromGOBBytes(data []byte) error
}
type IBlock interface {
IGOBBytes
GetHash() string
GetPrevHash() string
GetHeight() int
Check() bool
}
La connexió a la base de dades es crea una vegada quan el paquet s'inicia a la funció init():
db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).
CloseDB() és un embolcall per a db.Cloce() - cridat després de treballar amb les funcions del paquet per tancar la connexió a la base de dades.
La funció d'error SetTargetBlockHash(cadena hash) escriu el hash del bloc actual amb la clau especificada per la constant BLOCK_HASH a la base de dades.
La funció GetTargetBlockHash() (cadena, error) retorna el hash del bloc actual emmagatzemat a la base de dades.
La funció d'error SetTargetBlockHeight(height int) escriu a la base de dades el valor de l'alçada de la cadena de blocs per al node amb la clau especificada per la constant BLOCK_HEIGHT.
La funció GetTargetBlockHeight() (int, error) retorna l'alçada de la cadena de blocs per a un node determinat, emmagatzemat a la base de dades.
La funció bool CheckBlock(block IBlock) comprova la correcció d'un bloc abans d'afegir aquest bloc a la cadena de blocs.
La funció d'error AddBlock (bloc IBlock) afegeix un bloc a la cadena de blocs.
Les funcions per recuperar i visualitzar blocs es troben al fitxer explore.go del paquet blockchain:
La funció GetBlockByHash(cadena hash) (*block.Block, error) crea un objecte bloc buit, hi carrega un bloc des de la base de dades, el hash del qual se li va passar i hi retorna un punter.
La creació d'un bloc genesis es realitza mitjançant la funció d'error Genesis() del fitxer genesis.go del paquet blockchain.
El següent article parlarà de la connexió de clients a un node mitjançant el mecanisme WebSocket.
Font: www.habr.com