Como projetei blocos e transações no meu blockchain Go

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

imagem

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

Aqui 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.go

A 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.Para

isso, 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.

All Articles