Cómo diseñé bloques y transacciones en mi blockchain Go

Para producir finalmente una cadena de bloques, y no solo una base de datos, necesitamos agregar 3 elementos importantes a nuestro proyecto:

  • Descripción de la estructura de datos y métodos de bloqueo.
  • Descripción de la estructura de datos y métodos de transacción.
  • Funciones de blockchain que guardan bloques en la base de datos y los encuentran allí por su hash o altura (u otra cosa).

imagen

Este es el segundo artículo sobre blockchain para la industria, el primero aquí .

Al recordar las preguntas que los lectores me hicieron en el artículo anterior de esta serie, debe tenerse en cuenta: en este caso, la base de datos LevelDB se usa para almacenar datos de blockchain, pero no interfiere con el uso de otro, digamos el mismo MySQL. Y ahora entenderemos la estructura de estos datos.

Comencemos con las transacciones: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

Aquí está su estructura de datos:

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 almacena el tipo de datos (para la transacción 2), el hash de esta transacción, el tipo de transacción en sí, la marca de tiempo y también las entradas y salidas. Las entradas TxIn almacenan el hash de la transacción a la que se hace referencia a la salida, el número de esta salida y el código de bytes, y las salidas TxOut almacenan algún valor y también el código de bytes.

Ahora veamos qué acciones puede realizar una transacción en sus datos, es decir Analicemos los métodos.

Para crear una transacción, use la función transacción.NewTransaction (txtype byte) * TX.

El método AddTxIn (thattxhash [] byte, txoutn int, code [] byte) (* TxIn, error) agrega la entrada a la transacción.

El método AddTxOut (valor int, datos [] byte) (* TxOut, error) agrega salida a la transacción.

El método de bytes ToBytes () [] convierte una transacción en un segmento de bytes.

La cadena de función interna preByteHash (bytes [] byte) se usa en Build () y Check () para la compatibilidad del hash de transacción creado con los hash de transacción generados a partir de aplicaciones JavaScript.

El método Build () establece el hash de la transacción de la siguiente manera: tx.TxHash = preByteHash (tx.ToBytes ()).

El método ToJSON () de una cadena convierte una transacción en una cadena JSON.

El método de error FromJSON (datos [] byte) carga una transacción desde el formato JSON transmitido como un segmento de bytes.

El método bool Check () compara el hash recibido del campo hash de la transacción con el hash obtenido como resultado del hash de esta transacción (excluyendo el campo hash).

Las transacciones se agregan al bloque: github.com/Rusldv/bcstartup/blob/master/block/builder.go

La estructura de datos del bloque es 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 almacena un tipo de datos, un nodo en él y separa el bloque de una transacción u otros datos. Para un bloque, este valor es 1.

BlockHeight almacena la altura del bloque.
Marca de tiempo marca de tiempo.
Tamaño del bloque HeaderSize en bytes.
PrevBlockHash hash del bloque anterior y SelfBlockHash: el actual.
TxsHash es un hash de transacción común.
MerkleRoot - La raíz del árbol Merkle.

Lo siguiente en los campos es la clave pública del creador del bloque, la firma del creador, la versión del bloque, el número de transacciones en el bloque y estas transacciones mismas.

Considere sus métodos:
La función block.NewBlock () se usa para crear un bloque: NewBlock (cadena anteriorBlockHash, altura int) * Bloque, que toma el hash del bloque anterior y la altura establecida para el bloque creado en la cadena de bloques. También se establece el tipo de bloque de la constante del paquete de tipos:
b.DataType = types.BLOCK_TYPE.


El método AddTx (tx * transaction.TX) agrega una transacción al bloque.

El método Build () carga los valores en los campos del bloque y genera y establece su hash actual.

El método de bytes ToBytesHeader () [] traduce el encabezado del bloque (sin transacciones) en un segmento de bytes.

El método ToJSON () de la cadena traduce el bloque al formato JSON en la representación de cadena de los datos.

El método de error FromJSON (datos [] byte) carga datos de JSON en la estructura de bloques.

El método bool Check () genera un hash de bloque y lo compara con el del campo de hash de bloque.

El método de cadena GetTxsHash () devuelve el hash común de todas las transacciones en el bloque.

El método GetMerkleRoot () establece la raíz del árbol Merkle para las transacciones en el bloque.

El método Sign (cadena privada) firma el bloque con la clave privada del creador del bloque.

El método SetHeight (height int) escribe la altura del bloque en el campo de estructura del bloque.

El método GetHeight () int devuelve la altura del bloque como se indica en el campo correspondiente de la estructura del bloque.

El método de byte ToGOBBytes () [] codifica el bloque en el formato GOB y lo devuelve como un segmento de byte.

El método de error FromGOBBytes (byte de datos) escribe datos de bloque en la estructura de bloque desde el segmento de bytes transmitido en formato GOB.

La cadena del método GetHash () devuelve el hash de este bloque.

La cadena del método GetPrevHash () devuelve el hash del bloque anterior.

El método SetPublicKey (cadena de publicación) escribe la clave pública del creador del bloque en el bloque.

Por lo tanto, utilizando los métodos del objeto Block, podemos convertirlo fácilmente a un formato para su transmisión a través de la red y guardarlo en la base de datos LevelDB.

Las funciones del paquete blockchain son responsables de guardar en blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain.

Para esto, el bloque debe implementar la interfaz IBlock:

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

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

}

Se crea una conexión de base de datos una vez durante la inicialización del paquete en la función init ():
db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB () es un contenedor para db.Cloce (), llamado después de trabajar con las funciones del paquete para cerrar la conexión de la base de datos.

La función de error SetTargetBlockHash (cadena hash) escribe el hash del bloque actual con la clave especificada por la constante BLOCK_HASH en la base de datos.

La función GetTargetBlockHash () (cadena, error) devuelve el hash del bloque actual almacenado en la base de datos.

La función de error SetTargetBlockHeight (height int) escribe en la base de datos el valor de la altura de blockchain para un nodo con la clave especificada por la constante BLOCK_HEIGHT.

La función GetTargetBlockHeight () (int, error) devuelve la altura de la cadena de bloques para un nodo dado almacenado en la base de datos.

La función bool CheckBlock (bloque IBlock) verifica que el bloque sea correcto antes de agregar este bloque a la cadena de bloques.

La función de error AddBlock (bloque IBlock) agrega un bloque a la cadena de bloques.

Las funciones para recibir y ver bloques se encuentran en el archivo explore.go del paquete blockchain:

la función GetBlockByHash (hash string) (* block.Block, error) crea un objeto de bloque vacío, carga un bloque de la base de datos cuyo hash se le pasa y le devuelve un puntero.

El bloque génesis es creado por la función de error Genesis () del archivo genesis.go del paquete blockchain.

En el siguiente artículo, hablaremos sobre la conexión a un nodo de cliente utilizando el mecanismo WebSocket.

All Articles