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).
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.goAquí 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.goLa 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.