Alvo (Target)
O número que o hash de um bloco precisa ficar abaixo
O alvo (target) é um número que o hash de um bloco candidato precisa ficar igual ou abaixo para que o bloco seja adicionado à blockchain. Ele é usado durante a mineração.
O alvo é ajustado a cada 2016 blocos (aproximadamente a cada duas semanas) para tentar garantir que os blocos sejam minerados a cada 10 minutos em média. Isso cria um tempo consistente entre os blocos e uma emissão consistente de novos bitcoins (via recompensa de bloco).
Para compensar o aumento da velocidade do hardware e o interesse variável em rodar nós ao longo do tempo, a dificuldade da prova de trabalho é determinada por uma média móvel que mira um número médio de blocos por hora. Se eles são gerados rápido demais, a dificuldade aumenta.
Período
Quando o alvo se ajusta?
O alvo se ajusta a cada 2016 blocos, que é aproximadamente a cada duas semanas.
Os blocos são minerados a cada 10 minutos (aproximadamente), e há 20.160 minutos em duas semanas (2016 × 10).
Histórico
Aqui estão a altura, o alvo e a variação de cada ajuste de dificuldade na história do Bitcoin (do mais recente para o gênese — role para carregar mais):
| Altura | Alvo | Variação da Dificuldade | Data |
|---|
Ajuste
Como o alvo é calculado?
O alvo do primeiro bloco (gênese) foi definido como:
00000000ffff0000000000000000000000000000000000000000000000000000
Esse valor inicial é fixo no código-fonte de todo nó Bitcoin (chainparams.cpp). É também o valor máximo possível do alvo. Foi provavelmente um palpite do Satoshi sobre um bom ponto de partida para um alvo difícil o suficiente para resultar em um intervalo de 10 minutos.
A cada 2016º bloco, cada nó olha o tempo entre os 2015 blocos anteriores e calcula se eles foram minerados mais rápido ou mais devagar que 10 minutos em média.
Se os blocos desse período forem minerados mais rápido que 10 minutos, o alvo é ajustado para baixo, tornando mais difícil ficar abaixo dele no próximo período de blocos.
Inversamente, se os blocos forem minerados mais devagar que 10 minutos, o alvo é ajustado para cima, tornando menos difícil ficar abaixo dele no próximo período de blocos.
Como resultado, cada nó recalcula regularmente o alvo para manter um intervalo médio de 10 minutos conforme os mineradores entram e saem da rede.
Veja o código no fim da página para um exemplo prático.
Sincronização
Como os nós calculam o mesmo alvo?
Todos fazem o mesmo cálculo com os mesmos dados da cadeia, então todos obtêm o mesmo resultado no mesmo elo da cadeia.
Cada nó da rede opera de forma independente, então não há uma autoridade central para determinar o valor atual do alvo.
Porém, como os nós sempre adotam a cadeia mais longa de blocos como a sua blockchain, eles calculam o mesmo alvo.
Por exemplo, quando você roda o Bitcoin pela primeira vez, o seu nó faz o download inicial da blockchain (initial block download) e calcula os alvos conforme avança. E, como você está recebendo os mesmos blocos que todos os outros, acaba calculando o mesmo alvo atual ao chegar à ponta da blockchain.
Além disso, todos os nós atualizam continuamente para a mesma versão da blockchain (pois sempre adotam a cadeia de blocos mais longa disponível). Portanto, os nós também calculam o mesmo valor do alvo a cada novo bloco minerado.
Como resultado, apesar de os nós calcularem o alvo de forma independente, todos chegam ao mesmo alvo porque compartilham a mesma visão da blockchain.
Propósito
Por que o Bitcoin usa um alvo?
O alvo regula a velocidade com que novos blocos são adicionados à blockchain. Isso tem dois benefícios:
1. Dá tempo para os blocos se propagarem pela rede.
Se as transmissões acabarem sendo mais lentas na prática do que o esperado, o tempo-alvo entre blocos talvez precise ser aumentado para evitar desperdício de recursos. Queremos que os blocos normalmente se propaguem em muito menos tempo do que leva para gerá-los, caso contrário os nós passariam tempo demais trabalhando em blocos obsoletos.
É preferível que os mineradores trabalhem para estender a mesma cadeia de blocos o máximo possível. Para que isso funcione, precisamos dar tempo para que os novos blocos se propaguem pela rede antes do próximo ser minerado.
Se os blocos forem minerados mais rápido do que conseguem ser transmitidos pela rede, os mineradores frequentemente trabalharão em cima de blocos "antigos" da blockchain (porque ainda não tiveram a chance de receber os blocos mais recentes).
Isso fará com que os mineradores construam várias blockchains concorrentes; apenas uma delas se tornará a mais longa, então alguns mineradores acabarão desperdiçando energia construindo em cima de uma cadeia concorrente, só para ela ser deixada para trás por causa de uma reorganização da cadeia.
Portanto, esse atraso de tempo (o intervalo entre blocos) permite que os blocos se propaguem pela rede, de modo que mais mineradores possam adotar a cadeia mais longa disponível, o que ajuda a concentrar o poder de mineração da rede na extensão da mesma cadeia de blocos.
2. Uma emissão consistente de novos bitcoins.
As moedas precisam ser distribuídas inicialmente de alguma forma, e uma taxa constante parece ser a melhor fórmula.
O Bitcoin é uma moeda, então ter uma taxa fixa de novos bitcoins introduzidos no sistema ajuda a fornecer estabilidade.
Então, graças ao alvo, você pode ter confiança de que novos bitcoins serão cunhados a uma taxa previsível.
Localização
Onde você encontra o alvo?
O alvo fica armazenado no campo bits do cabeçalho de cada bloco.
O campo bits é uma representação compacta do alvo (para economizar espaço no cabeçalho do bloco). Mas você pode converter facilmente entre a representação bits e o alvo completo.
Comandos
bitcoin-cli getblocktemplate
A forma mais simples de obter o alvo atual. Ao solicitar um modelo de bloco (para mineração), ele também retorna o alvo atual.
Este comando retorna muitos dados, então é melhor usar grep para filtrar o alvo.
$ bitcoin-cli getblocktemplate '{"rules": ["segwit"]}' | grep target
"target": "00000000000000000002068f0000000000000000000000000000000000000000", bitcoin-cli getdifficulty
Alternativamente, você pode pedir a dificuldade atual e convertê-la para o alvo:
$ bitcoin-cli getdifficulty
138955357012247.30
Dificuldade
Converter de dificuldade para alvo nem sempre é preciso. A dificuldade é um número de ponto flutuante calculado a partir da mudança entre o alvo inicial e o atual, então pode perder precisão.
bitcoin-cli getblockheader [hash do bloco]
Este comando permite encontrar um alvo anterior de um bloco específico. O alvo na época da mineração fica armazenado em cada cabeçalho de bloco no formato bits, que você pode converter para o alvo completo.
$ bitcoin-cli getblockheader 000000000000000002e9533a4fe03bb251b3fdb30ffaa384aad133b7fae594cf
{
"hash": "000000000000000002e9533a4fe03bb251b3fdb30ffaa384aad133b7fae594cf",
"confirmations": 425677,
"height": 401184,
"version": 4,
"versionHex": "00000004",
"merkleroot": "b4afa0502a55fdfa4a5cda6ea2bc546ba527d276ea9c7e848b8cd478cd9b6607",
"time": 1457133956,
"mediantime": 1457132303,
"nonce": 3778923481,
"bits": "1806f0a8",
"difficulty": 158427203767.3917,
"chainwork": "00000000000000000000000000000000000000000012da32364c8f47d519604d",
"nTx": 845,
"previousblockhash": "000000000000000003c4a4d9c62b3a7f4893afe14eef8a6a377229d23ad4b1ea",
"nextblockhash": "00000000000000000037ab74c8db9b7a9d7de039210d8eafaeb44ba35adfb624"
}
Bits do Alvo
Você pode obter o alvo do bloco mais recente da cadeia com este one-liner:
$ bitcoin-cli getblockheader $(bitcoin-cli getblockhash $(bitcoin-cli getblockcount)) Código
Aqui está um exemplo de código em Ruby para calcular os ajustes do alvo.
Este código calcula o novo alvo do bloco 403.200, usando os timestamps dos bloco 401.184 e bloco 403.199.
# 403,200 - NEW TARGET
# 403,199 | last block
# |
# |
# |
# 401,184 - NEW TARGET | first block (target = 0x000000000000000006f0a8000000000000000000000000000000000000000000)
# 1. Get the timestamps for the first and last block in the target adjustment period
first = 1457133956 # block 401,184
last = 1458291885 # block 403,199
# 2. Work out the ratio of the actual time against the expected time
actual = last - first # 1157929 (number of seconds between first and last block)
expected = 2016 * 10 * 60 # 1209600 (number of seconds expected between 2016 blocks)
ratio = actual.to_f / expected.to_f
# 3. Limit the adjustment by a factor of 4 (to prevent massive changes from one target to the next)
ratio = 0.25 if ratio < 0.25
ratio = 4 if ratio > 4
# 4. Multiply the current target by this ratio to get the new target
current_target = 0x000000000000000006f0a8000000000000000000000000000000000000000000
new_target = (current_target * ratio)
# 5. Don't let the target go above the maximum target
max_target = 0x00000000ffff0000000000000000000000000000000000000000000000000000
new_target = max_target if new_target > max_target
# 5. Truncate the target, because the official target is the truncated "bits" format stored in the block header
# This code is a bit rough, because it's working with strings when I should really be working with actual bytes.
new_target = new_target.to_i.to_s(16) # convert from decimal to hexadecimal
new_target = new_target.size % 2 != 0 ? '0' + new_target : new_target # make sure it's an even number of characters (i.e. bytes)
truncated = new_target.scan(/../).each_with_index.map { |byte, i| byte = i >= 3 ? "00" : byte }.join # set all bytes apart from first 3 to zeros
# e.g. 6a4c316c01f354000000000000000000000000000000000 <- full precision
# e.g. 6a4c3000000000000000000000000000000000000000000 <- official target
# 6. Display the full target (with leading zeros)
target = truncated.rjust(64, '0')
puts target
# 000000000000000006a4c3000000000000000000000000000000000000000000 - Você pode obter o timestamp de um bloco com
bitcoin-cli getblockheader [hash do bloco]. - Você pode obter o hash de um bloco em uma altura específica com
bitcoin-cli getblockhash [altura].
Erro de "off-by-one". Os ajustes de dificuldade são, na verdade, calculados usando o tempo ao longo de 2015 blocos (ex.: 403199 − 401184 = 2015), e não 2016 como seria de se esperar. Isso foi um erro de implementação no código, e ainda existe hoje.
Alvo oficial. O alvo que os mineradores realmente precisam ficar abaixo ao minerar é o alvo truncado que é armazenado no campo bits. Ou seja, não é o alvo de precisão completa que você obtém após o cálculo de ajuste do alvo.
Perguntas Frequentes
Por que 10 minutos entre os blocos?
Acho que ninguém, exceto o Satoshi, sabe exatamente por que 10 minutos foi escolhido. Meu palpite é que parecia longo o suficiente para permitir que os blocos se propagassem pela rede (minimizando reorganizações da cadeia) e curto o suficiente para não esperar demais pelas novas transações. E 10 é um número redondo agradável.
O que faz os blocos serem minerados mais rápido ou mais devagar que 10 minutos?
Primeiro, a mineração é imprevisível: você nunca sabe quando um minerador vai encontrar o próximo bloco. Segundo (e mais importante), os mineradores podem entrar e sair da rede a qualquer momento, o que afeta a velocidade. Quanto mais mineradores entram, mais hashing acontece, e mais provável é que um novo bloco seja minerado em menos de 10 minutos.
Recursos
- pow.cpp – a função
CalculateNextWorkRequired()ajusta o alvo. - chainparams.cpp – o valor inicial (e máximo) do alvo é definido por
consensus.powLimit. - en.bitcoin.it/wiki/Target
- Como o alvo do Bitcoin é definido? Quem faz isso?
- Por que não reajustar o alvo a cada bloco?
- Por que o tempo-alvo entre blocos foi escolhido como 10 minutos?
- Explorando o bug de "off-by-one" (reajuste de dificuldade baseado em 2015 em vez de 2016)?
Obrigado a David Harding por apontar que é possível obter o alvo diretamente do bitcoind usando bitcoin-cli getblocktemplate.