Bytes
Unidades de armazenamento para dados
Este é um guia rápido para explicar o que são bytes e como são usados no bitcoin. Será útil se você está trabalhando com transações e outros dados brutos do bitcoin.
Você vai fazer alguma programação de baixo nível ao trabalhar com dados do bitcoin, então é bom saber o que está olhando.
Introdução
Ao usar bitcoin no dia a dia, você verá frequentemente bytes brutos de dados:
- Chave Privada. São 32 bytes de dados representando um número muito grande.
- TXID. São 32 bytes de dados representando um identificador único de uma transação.
Ao trabalhar com bitcoin, você logo descobre que todos os dados centrais também são feitos de bytes brutos:
- Transação. Um monte de bytes descrevendo a movimentação de bitcoins de um lugar para outro.
0100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000 - Bloco. Uma coleção de transações, junto com um cabeçalho de bloco no topo resumindo os dados do bloco.
0100000055bd840a78798ad0da853f68974f3d183e2bd1db6a842c1feecf222a00000000ff104ccb05421ab93e63f8c3ce5c2c2e9dbb37de2764b3a3175c8166562cac7d51b96a49ffff001d283e9e700201000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0102ffffffff0100f2052a01000000434104d46c4968bde02899d2aa0963367c7a6ce34eec332b32e42e5f3407e052d64ac625da6f0718e7b302140434bd725706957c092db53805b821a85b23a7ac61725bac000000000100000001c997a5e56e104102fa209c6a852dd90660a20b2d9c352423edce25857fcd3704000000004847304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901ffffffff0200ca9a3b00000000434104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac00286bee0000000043410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3ac00000000
O Bitcoin é um programa de computador, e computadores leem e se comunicam usando bytes. Então, se você planeja trabalhar com bitcoin no nível técnico, é útil saber o que é um byte, como ele é exibido e os tipos de dados que ele armazena.
Básico
Antes de chegar aos bytes, precisamos saber o que é um "bit".
Bit
Um bit é a menor unidade de dados que um computador pode guardar. Pode ser um 1 ou um 0 (ou seja, um único transistor "ligado" ou "desligado"):
Esses bits são os blocos de construção para armazenar dados dentro dos computadores.
O Ben Eater tem ótimos vídeos sobre como computadores funcionam.
Se você travar ao programar, lembre que, no fim das contas, é tudo só um monte de uns e zeros.
Byte
Um byte é só um grupo de 8 bits individuais:
Um byte é uma unidade conveniente de armazenamento de dados em um computador. Assim como às vezes é mais prático medir peso em quilogramas em vez de gramas, às vezes é mais prático medir dados em bytes em vez de bits.
Bytes são, na verdade, a medida padrão para dados, e a maioria dos dados com que você vai trabalhar no bitcoin é medida em bytes.
Um byte são 8 bits individuais. Então uma chave privada de 32 bytes tem 256 bits (32 × 8 = 256).
Representando Bytes
Podemos representar um byte de duas formas:
- Usando oito dígitos binários, um para cada bit (ex.:
0b11111111) - Usando dois dígitos hexadecimais (ex.:
0xFF)
Isso funciona porque, se você dividir um byte em duas metades de 4 bits, cada metade consegue lidar com 16 combinações diferentes de 1s e 0s. Então, se você der a cada metade o seu próprio caractere hexadecimal, pode representar um byte usando apenas dois caracteres em vez de oito.
Essa representação mais curta é chamada de byte hexadecimal.
Frequentemente exibimos bytes em formato hexadecimal para economizar espaço, o que é muito mais conveniente ao representar vários bytes de dados:
Então, da próxima vez que você ver uma chave privada assim:
61dc9ff8b15450212970c6fa997338bb205dd48ffaca3a056b09a3b44a244d76
Você está, na verdade, olhando para 32 bytes individuais:
61 dc 9f f8 b1 54 50 21 29 70 c6 fa 99 73 38 bb 20 5d d4 8f fa ca 3a 05 6b 09 a3 b4 4a 24 4d 76
Quando comecei a trabalhar com Bitcoin, cometi o erro de interpretar coisas como chaves privadas como strings de letras e números individuais. Mas, na realidade, é uma sequência de bytes, em que cada dois caracteres são um byte.
Não importa se os caracteres hexadecimais são maiúsculos ou minúsculos. Por exemplo, 6b é o mesmo que 6B.
Armazenando Dados em Bytes
Então, como podemos armazenar coisas úteis como números, texto e outras coisas dentro desses bytes?
Honestamente, depende só de como você interpreta os bits.
Um byte pode conter diferentes tipos de dados dependendo de como você o interpreta. Por exemplo, o byte 01100111 poderia representar a letra "g" ou o número 103. Tudo depende de que tipo de dado você está trabalhando.
Números
Você pode usar bytes para armazenar números inteiros:
Se queremos armazenar um número em um computador, nós o armazenamos usando sua representação binária dentro dos bits de um byte. E, se queremos armazenar números maiores, simplesmente usamos mais bytes.
Exemplos
Números são muito comuns dentro dos dados do bitcoin: chave privada (número de 32 bytes), valor de saída (8 bytes), VOUT (4 bytes), nonce (4 bytes), alvo (32 bytes), locktime (4 bytes) e tempo do bloco (4 bytes, em Unix Time).
Texto
Você também pode usar bytes para armazenar texto, atribuindo a cada caractere o seu próprio byte.
Não há um padrão oficial para codificar texto dentro dos dados do bitcoin, mas o mapeamento de caracteres-para-bytes mais usado é o ASCII:
Como você pode ver, cada byte representa um caractere diferente. Você só precisa da tabela ASCII à mão para ver qual byte corresponde a qual caractere.
Exemplos
Texto não é frequentemente armazenado nos dados do Bitcoin, mas aparece em alguns lugares: OP_RETURN (dados arbitrários em uma saída), o scriptsig da transação coinbase (texto do minerador), o tipo/"comando" no cabeçalho de cada mensagem (12 bytes ASCII) e o campo User-Agent na mensagem "version".
Configurações (Bit Field)
Às vezes você pode usar os bits dentro de bytes de dados para representar várias configurações de ligado/desligado.
Isso é conhecido como bit field (campo de bits), e é uma forma eficiente de armazenar várias configurações no menor espaço possível.
Exemplos
Bit fields são usados em alguns lugares no bitcoin: o campo Services na mensagem "version" (8 bytes/64 bits indicando os serviços de um nó), o campo version do cabeçalho de bloco (4 bytes/32 bits para sinalizar prontidão para atualizações) e o campo sequence de uma transação (interpretado como bit field ao definir o locktime relativo).
Apenas Bytes
Às vezes os bytes não precisam representar nada em particular. Eles podem ser úteis simplesmente como um pedaço único de dados.
Exemplos
A saída de uma função de hash é só uma série única de bytes, e isso os torna úteis como "impressões digitais" de dados: TXID (identificador único de transação), hash de bloco (identificador único de bloco) e hash de chave pública. E às vezes usamos apenas um conjunto de bytes de aparência aleatória, sem significado, como os magic bytes (f9beb4d9) usados como marcador entre mensagens.
Então você não precisa interpretar bytes como nada em especial. Ter um conjunto único de bytes para usar como "impressão digital" dos dados já é útil por si só.
Um hash de bloco na verdade é interpretado tanto como um identificador único quanto como um número. Geralmente é só um identificador único para o bloco, mas também é interpretado como um número durante o processo de mineração para verificar se o hash está abaixo do valor de alvo atual.
Dados Personalizados
No fim, você pode usar bytes para representar o que quiser. Não precisa ser só números e texto (embora sejam os mais comuns). Tudo depende de como você escolhe interpretar as combinações de 1s e 0s dentro desses bytes.
Exemplos
Estas são algumas codificações exclusivas do bitcoin: Script (um byte em um scriptpubkey/scriptsig pode se referir a uma operação "OP_CODE"), Compact Size e o campo bits do cabeçalho de bloco (armazena o alvo atual de forma compacta).
Trabalhando com Bytes
Conseguir trabalhar com bytes brutos no bitcoin é especialmente importante quando se trata de rede ou quando você está fazendo o hash de dados.
A boa notícia é que você pode trabalhar com bytes brutos em qualquer linguagem de programação decente. Isso varia entre linguagens, mas normalmente envolve escrever o valor de cada byte individual em algum tipo de string ou array especial, assim:
"\xF9\xBE\xB4\xD9"
{0xF9, 0xBE, 0xB4, 0xD9}
Mas esse tipo de formato não é fácil de passar adiante, então você frequentemente vai converter esses bytes em strings hexadecimais para fins de exibição:
"f9beb4d9"
É assim que eu normalmente exibo bytes neste site, e como você normalmente verá bytes sendo exibidos em exploradores de blockchain.
Às vezes você também vai querer obter o valor inteiro que esses bytes representam:
4190024921
Então, ao trabalhar com dados do Bitcoin, você quer conseguir converter de um lado para o outro entre bytes de verdade, strings hexadecimais e inteiros na sua linguagem de programação preferida.
Aqui estão alguns exemplos rápidos de como fazer isso em algumas linguagens de programação comuns:
Ruby
# Trabalhe com bytes diretamente usando caracteres hexadecimais para representar cada byte.
bytes = "\xF9\xBE\xB4\xD9" #=> (jargão - tenta exibir a codificação de caracteres para cada valor de byte)
# Bytes -> String Hexadecimal
hex_string = bytes.unpack("H*")[0] #=> "f9beb4d9"
# String Hexadecimal -> Bytes
bytes = [hex_string].pack("H*") #=> (jargão - tenta exibir uma codificação de caracteres para cada valor de byte)
# String Hexadecimal -> Inteiro
integer = hex_string.to_i(16) #=> 4190024921 Ruby pode ser um pouco estranho ao exibir bytes. Se você tentar imprimir bytes diretamente, o Ruby tentará exibi-los usando a codificação de caracteres de cada byte (em vez de sua representação hexadecimal), então você precisa converter para hexadecimal para exibi-los ao depurar.
As funções "pack" e "unpack" são as mais úteis quando se trata de trabalhar com bytes brutos em linguagens como Ruby e Python, então vale a pena conhecê-las.
Python
# NOTA: Python 3.5+
# Cria bytes
raw_bytes = b'\xf9\xbe\xb4\xd9'
# Converte bytes para string hex
hex_string = b'\xf9\xbe\xb4\xd9'.hex()
print(hex_string) #=> f9beb4d9
# Converte string hex para bytes
raw_bytes = bytes.fromhex('f9beb4d9')
print(raw_bytes) #=> b'\xf9\xbe\xb4\xd9'
# Converte bytes para inteiro
integer = int.from_bytes(b'\xf9\xbe\xb4\xd9', byteorder="big") # segundo argumento é a endianness
print(integer) #=> 4190024921 Veja little-endian para detalhes sobre endianness no bitcoin.
Go
package main
import "fmt"
import "encoding/hex"
import "math/big"
func main() {
// Cria um array de bytes
bytes := []byte{0xF9, 0xBE, 0xB4, 0xD9}
fmt.Println(bytes) //=> [249 190 180 217]
// Converte array de bytes para string hexadecimal
hex_string := hex.EncodeToString(bytes)
fmt.Println(hex_string) //=> f9beb4d9
// Converte string hexadecimal para array de bytes
byte_array, _ := hex.DecodeString(hex_string)
fmt.Println(byte_array) //=> [249 190 180 217]
// Converte array de bytes para inteiro
integer := new(big.Int).SetBytes(byte_array)
fmt.Println(integer) //=> 4190024921
// Converte inteiro para array de bytes
byte_array_from_integer := integer.Bytes()
fmt.Println(byte_array_from_integer) //=> [249 190 180 217]
} Resumo
Um byte é apenas um grupo de 8 bits:
byte (binário):
┌─┬─┬─┬─┬─┬─┬─┬─┐
│0│1│1│0│1│0│1│1│
└─┴─┴─┴─┴─┴─┴─┴─┘
Para economizar espaço, geralmente representamos cada byte usando 2 caracteres hexadecimais em vez de usar 8 bits individuais:
byte (hexadecimal):
┌─┬─┐
│6│B│
└─┴─┘
Um bit é a menor unidade de dados (um 1 ou 0), e um byte é um grupo de 8 bits. Os bytes são a unidade básica dos dados brutos do Bitcoin.
Normalmente exibimos bytes em formato hexadecimal (2 caracteres por byte) para economizar espaço. E um byte pode armazenar diferentes tipos de dados — números, texto, configurações, impressões digitais — dependendo de como você interpreta os seus bits.
Quando você começa a trabalhar com dados brutos do Bitcoin, é tudo só uma questão de saber o que aqueles bytes representam.