Para finalmente produzir uma blockchain, e não apenas um banco de dados, precisamos adicionar 3 elementos importantes ao nosso projeto:- Descrição da estrutura de dados e métodos de bloqueio
- Descrição da estrutura de dados e métodos de transação
- Funções de blockchain que salvam blocos no banco de dados e os encontram lá por seu hash ou altura (ou qualquer outra coisa).
Este é o segundo artigo sobre blockchain para a indústria, o primeiro aqui .Lembrando as perguntas que os leitores me fizeram no artigo anterior desta série, observe-se: nesse caso, o banco de dados LevelDB é usado para armazenar dados de blockchain, mas não interfere no uso de nenhum outro, digamos o mesmo MySQL. E agora vamos entender a estrutura desses dados.Vamos começar com as transações: github.com/Rusldv/bcstartup/blob/master/transaction/builder.goAqui está sua estrutura de dados: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 armazena o tipo de dados (para a transação 2), o hash dessa transação, o tipo de transação em si, o carimbo de data e hora e também as entradas e saídas. As entradas TxIn armazenam o hash da transação à qual a saída é referenciada, o número dessa saída e o bytecode, e as saídas TxOut armazenam algum valor e também o bytecode.Agora vamos ver quais ações uma transação pode executar em seus dados, ou seja, vamos analisar os métodos.Para criar uma transação, use a função transaction.NewTransaction (txtype byte) * TX.O método AddTxIn (thattxhash [] byte, txoutn int, código [] byte) (* TxIn, erro) adiciona a entrada à transação.O método AddTxOut (valor int, data [] byte) (* TxOut, erro) adiciona saída à transação.O método de bytes ToBytes () [] transforma uma transação em uma fatia de bytes.A função interna preByteHash (bytes [] byte) é usada em Build () e Check () para compatibilidade do hash de transação criado com os hashes de transação gerados a partir de aplicativos JavaScript.O método Build () define o hash da transação da seguinte maneira: tx.TxHash = preByteHash (tx.ToBytes ()).O método ToJSON () de uma string converte uma transação em uma string JSON.O método de erro FromJSON (data [] byte) carrega uma transação do formato JSON transmitida como uma fatia de bytes.O método booleano Check () compara o hash recebido do campo hash da transação com o hash obtido como resultado do hash dessa transação (excluindo o campo hash).As transações são adicionadas ao bloco: github.com/Rusldv/bcstartup/blob/master/block/builder.goA estrutura de dados do bloco é mais volumosa: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 armazena um tipo de dados, um nó e desanexa o bloco de uma transação ou de outros dados. Para um bloco, esse valor é 1.BlockHeight armazena a altura do bloco.Timestamp timestamp.Tamanho do bloco HeaderSize em bytes.O hash PrevBlockHash do bloco anterior e SelfBlockHash - o atual.TxsHash é um hash de transação comum.MerkleRoot - A raiz da árvore Merkle.A seguir, nos campos, está a chave pública do criador do bloco, a assinatura do criador, a versão do bloco, o número de transações no bloco e essas próprias transações.Considere seus métodos:A função block.NewBlock () é usada para criar um bloco: NewBlock (string prevBlockHash, height int) * Block, que pega o hash do bloco anterior e a altura definida para o bloco criado na blockchain. O tipo de bloco da constante do pacote de tipos também é definido:b.DataType = types.BLOCK_TYPE.
O método AddTx (tx * transaction.TX) adiciona uma transação ao bloco.O método Build () carrega os valores nos campos do bloco e gera e define seu hash atual.O método de bytes ToBytesHeader () [] converte o cabeçalho do bloco (sem transações) em uma fatia de bytes.O método ToJSON () da string converte o bloco no formato JSON na representação da string dos dados.O método de erro FromJSON (data [] byte) carrega dados do JSON na estrutura do bloco.O método booleano Check () gera um hash de bloco e o compara com o especificado no campo de hash do bloco.O método de seqüência de caracteres GetTxsHash () retorna o hash comum de todas as transações no bloco.O método GetMerkleRoot () define a raiz da árvore Merkle para transações no bloco.O método Sign (privk string) assina o bloco com a chave privada do criador do bloco.O método SetHeight (height int) grava a altura do bloco no campo de estrutura do bloco.O método GetHeight () int retorna a altura do bloco, conforme indicado no campo correspondente da estrutura do bloco.O método ToGOBBytes () [] byte codifica o bloco no formato GOB e o retorna como uma fatia de bytes.O método de erro FromGOBBytes (data [] byte) grava dados de bloco na estrutura de blocos da fatia de bytes transmitida no formato GOB.A string do método GetHash () retorna o hash deste bloco.A string do método GetPrevHash () retorna o hash do bloco anterior.O método SetPublicKey (pubk string) grava a chave pública do criador do bloco no bloco.Assim, usando os métodos do objeto Block, podemos convertê-lo facilmente em um formato para transmissão pela rede e salvá-lo no banco de dados LevelDB.As funções do pacote blockchain são responsáveis por salvar no blockchain: github.com/Rusldv/bcstartup/tree/master/blockchain.Paraisso, o bloco deve implementar a interface IBlock:type IGOBBytes interface {
ToGOBBytes() []byte
FromGOBBytes(data []byte) error
}
type IBlock interface {
IGOBBytes
GetHash() string
GetPrevHash() string
GetHeight() int
Check() bool
}
Uma conexão com o banco de dados é criada uma vez durante a inicialização do pacote na função init ():db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).
CloseDB () é um invólucro para db.Cloce () - chamado depois de trabalhar com as funções do pacote para fechar a conexão com o banco de dados.A função de erro SetTargetBlockHash (cadeia de hash) grava o hash do bloco atual com a chave especificada pela constante BLOCK_HASH no banco de dados.A função GetTargetBlockHash () (string, error) retorna o hash do bloco atual armazenado no banco de dados.A função de erro SetTargetBlockHeight (height int) grava no banco de dados o valor da altura da blockchain para um nó com a chave especificada pela constante BLOCK_HEIGHT.A função GetTargetBlockHeight () (int, error) retorna a altura da blockchain para um determinado nó armazenado no banco de dados.A função booleana CheckBlock (block IBlock) verifica a correção do bloco antes de adicionar esse bloco ao blockchain.A função de erro AddBlock (block IBlock) adiciona um bloco ao blockchain.As funções para receber e visualizar blocos estão localizadas no arquivo explore.go do pacote blockchain:A função GetBlockByHash (string de hash) (* block.Block, error) cria um objeto de bloco vazio, carrega um bloco do banco de dados cujo hash é passado para ele e retorna um ponteiro para ele.O bloco genesis é criado pela função de erro Genesis () do arquivo genesis.go do pacote blockchain.No próximo artigo, falaremos sobre a conexão com um nó cliente usando o mecanismo WebSocket.