Com vaig dissenyar blocs i transaccions a la meva cadena de blocs Go

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).

Com vaig dissenyar blocs i transaccions a la meva cadena de blocs Go

Aquest és el segon article sobre blockchain per a la indústria, el primer aquí.

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: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

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: github.com/Rusldv/bcstartup/blob/master/block/builder.go

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: github.com/Rusldv/bcstartup/tree/master/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

Afegeix comentari