A estrutura do Decred

16 minutos de leitura

1. Introdução

Para compreender o funcionamento do Decred e aproveitar melhor seu potencial é necessário entender os tipos de redes, componentes, conexões e endereços.

2. Componentes

Figura 1 - Uma visão geral dos componentes do Decred
Figura 1 - Uma visão geral dos componentes do Decred

2.1. dcrd

As funcionalidades do Decred estão divididas em dois componentes principais: o primeiro componente é o dcrd, o blockchain server, o full node. É esse componente que resolve questões de blockchain, regras de consenso e comunicação peer-to-peer para sincronização. O dcrd é a espinha dorsal da rede Decred.

2.2. dcrwallet

O segundo componente é a carteira, que gerencia moedas (transações não gastas), chaves privadas, geração determinística de chaves, etc. Diferentemente do Bitcoin Core, onde toda a funcionalidade foi construída em um componente monolítico, no Decred são componentes separados.

Para saber o seu saldo o dcrwallet busca com o dcrd informações da blockchain. Esse é um dos motivos para o dcrwallet falar com o dcrd via RPC.

Figura 2 - Os componentes mais básicos do Decred
Figura 2 - Os componentes mais básicos do Decred

2.3. dcrctl

dcrctl é o cliente que se conecta no servidor de blockchain (dcrd) e no servidor da carteira (dcrwallet) para fazer consultas e assnar transações.

2.4. Decrediton

Decrediton é a aplicação gráfica da carteira, disponível em várias plataformas. Com o Decrediton não é necessário se preocupar com dcrd, dcrwallet e dcrctl, porque é uma aplicação 3-em-1.

2.5. Simple Payment Verification (SPV)

O SPV é um modo de funcionamento que não depende da execução local de um dcrd (full node) para realizar suas funções. O SPV utiliza DNS Seeds para localizar full nodes e se conectar na rede ponto-a-ponto.

2.6. Outros componentes

Outros componentes da rede serão abordados em outros artigos. Segue uma breve descrição de cada um deles.

atomicswap

Um atomic swap é uma troca entre dois usuários de criptomoedas diferentes, que queiram trocar Decred e Bitcoin, por exemplo, sem usar um escrow (intermediário de confiança). Como as blockchains não são relacionadas e as transações não podem ser revertidas, não há proteção contra uma das partes não honrar o negócio (aquele que enviará as moedas no final).

Um atomic swap resolve esse problema sem a necessidade de um intermediário, conectando as partes através de uma transação contratual em cada blockchain.

dcrdata

É o explorador de blocos da rede. Pode ser instalado localmente por questões de privacidade e confiabilidade ou pode ser acessado diretamente no endereço https://www.dcrdata.org.

dcrlnd

O Lightning Network Daemon (lnd) é uma implementação completa de um node da Lightning Network e atualmente implantado na testnet3, uma rede de testes do Bitcoin. A Lightning Network habilita pagamentos instantâneos, maior escalabilidade e transações com custo extremamente baixo.

dcrpayments

É o conjunto de bibliotecas e utilitários para integração com um gateway de pagamentos Decred. Há também a biblioteca para integração do e-commerce Magento com carteiras Decred.

dcrstakepool

É a aplicação web que coordena a geração de endereços multisig 1-de-2 usados num pool de servidores dcrwallet para que os usuários possam comprar tickets da mineração PoS (proof-of-stake) na rede Decred e fazer com que o pool de servidores vote em seu nome quando o ticket for sorteado.

dcrtime

Implementação cliente e servidor do serviço de registro de data e hora publicamente verificável na blockchain.

dcrseeder

É o agregador da rede Decred, que expõe uma lista de nodes confiáveis usando um servidor de DNS interno. Veja mais sobre o serviço na seção 6.

Politeia

Politeia é o sistema de proposta do Decred para armazenar dados off-chain com versionamento e ancorados na blockchain através de timestamps do dcrtime. Essencialmente, “git, um sistema de controle de revisão popular, com timestamping”.

3. Tipos de rede e endereços

Há três redes usadas pelo Decred. A Mainnet é a rede de produção. Essa é a rede principal, a blockchain que contém os recursos com valor, a rede com o maior hash power.

A Testnet é um ambiente de desenvolvimento, um ambiente livre onde novos códigos são testados sem qualquer prejuízo. É também a rede ideal para fazer demonstrações e aprender o funcionamento dos componentes.

A Simnet é uma rede de simulação, um ambiente de homologação. É como uma Testnet privada usada pelos desenvolvedores e para testes mais avançados. Para criar a sua própria Simnet, veja https://docs.decred.org/advanced/simnet/.

Figura 3 - Os tipos de redes do Decred
Figura 3 - Os tipos de redes do Decred

Um endereço Decred é uma representação de uma chave pública com um prefixo de 2 bytes que identifica a rede e o tipo de chave, além de um sufixo que contém um checksum para detectar endereços errados.

Por isso sempre é possível saber o tipo de endereço com base nesse prefixo de 2 bytes.

O primeiro byte identifica a rede. Todos os endereços da Mainnet começam com “D”, os endereços da Testnet começam com “T”, e os da Simnet com “S”.

O segundo byte identifica o tipo de endereço. Os endereços mais comumente utilizados são os secp256k1 pubkey hashes, que são identificados pelo “s” minúsculo. Esse tipo representa uma única chave pública e portanto só possui uma única chave privada associada que pode ser usada para resgatá-lo.

A pool de ticket usa um endereço pay-to-script-hash, que é identificado pelo segundo byte, um “c” minúsculo. Esse tipo de script gera uma multi-assinatura 1-de-2 (multi-signature 1-of-2). Tanto o usuário como a pool de tickets tem cada um sua chave privada. Como o script só exige uma assinatura de duas possíveis (1-de-2), tanto o usuário como a pool podem votar, e é assim que funciona a delegação de direitos de voto para a pool sem que o usuário abra mão de votar por completo.

A seguir alguns tipos de chaves usados em cada ambiente do Decred. Há outros tipos de chaves que serão tratados em outros artigos.

Mainnet

PubKeyHashAddrID: [2]byte{0x07, 0x3f}, // starts with Ds
ScriptHashAddrID: [2]byte{0x07, 0x1a}, // starts with Dc

Simnet

PubKeyHashAddrID: [2]byte{0x0e, 0x91}, // starts with Ss
ScriptHashAddrID: [2]byte{0x0e, 0x6c}, // starts with Sc

Testnet

PubKeyHashAddrID: [2]byte{0x0f, 0x21}, // starts with Ts
ScriptHashAddrID: [2]byte{0x0e, 0xfc}, // starts with Tc

4. Estrutura de arquivos

4.1. dcrd, dcrwallet e dcrctl

Os arquivos de configuração estão localizados dentro do diretório padrão de cada aplicação. Abaixo, a localização padrão para os diretórios em cada sistema operacional:

Windows

C:\Users\$USERNAME\AppData\Local\Dcrwallet\
C:\Users\$USERNAME\AppData\Local\Dcrd\
C:\Users\$USERNAME\AppData\Local\Dcrctl\

macOS

~/Library/Application Support/Dcrwallet/
~/Library/Application Support/Dcrd/
~/Library/Application Support/Dcrctl/

Linux

~/.dcrwallet/
~/.dcrd/
~/.dcrctl/

Dentro dessas pastas ficam localizados os arquivos de configuração: dcrd.conf, dcrwallet.conf e dcrctl.conf.

Se não for possível localizar os arquivos de configuração, copie a partir dos samples: sample-dcrd.conf, sample-dcrwallet.conf e sample-dcrctl.conf. Esses arquivos vem com o pacote de instalação dcrinstall.

4.2. Decrediton

O Decrediton armazena a carteira, os arquivos de log e sua configuração em um único diretório. O arquivo de configuração do Decrediton é o config.json em todos os sistemas operacionais.

Windows: C:\Users\$USERNAME\AppData\Local\Decrediton
macOS: ~/Library/Application Support/Decrediton
Linux: ~/.config/decrediton

O Decrediton usa a pasta padrão do dcrd em cada sistema operacional para armazenar a blockchain. Já a carteira, wallet.db, é armazenada em uma pasta com o nome da rede (wallets/mainnet/$WALLET_NAME/mainnet, wallets/testnet/$WALLET_NAME/testnet2, etc) dentro da sua própria estrutura (sem qualquer relação com o diretório do dcrwallet).

4.3. Blockchain data (dcrd e Decrediton)

É possível alterar o diretório para armazenamento da blockchain por questões de performance ou espaço em disco. No dcrd.conf a configuração é feita no parâmetro datadir. No Decrediton é necessário configurar o parâmetro appdata_path no arquivo config.json.

4.4. Carteira (dcrwallet e Decrediton)

A carteira é armazenada no arquivo wallet.db. Mesmo que um dispositivo tenha dcrwallet e Decrediton instalados, as carteiras serão arquivos diferentes. É possível copiar o arquivo entre os diretórios, permitindo o uso alternado dos aplicativos. É possível também configurar o dcrwallet para usar o wallet.db do Decrediton.

4.5. Configuração via linha de comando

Via linha de comando é possível alterar os parâmetros para aquela execução, sem necessidade de alterar o arquivo de configuração. É possível até mesmo configurar um HD completamente diferente para armazenar a blockchain da Testnet.

$ ./dcrd --datadir=/opt/blockchain
$ ./dcrd --testnet --datadir=/test/blockchain

Para executar qualquer app na Testnet basta incluir a opção --testnet.

dcrd e dcrwallet também suportam parâmetros de linha de comando para configuração do diretório padrão e do diretório para arquivos de log. Arquivos de log podem ser armazenados em um disco separado para não comprometer a performance dos serviços.

--appdata=[dir], --logdir=[dir]

Tanto no Linux como no macOS é possível executar o Decrediton em modo Testnet via linha comando. Use a opção --help para ver os outros parâmetros.

$ ./decrediton --testnet
$ /Applications/decrediton.app/Contents/MacOS/decrediton --testnet

5. Comunicação de rede

Decrediton, dcrd, dcrwallet e dcrctl se comunicam através de portas TCP. Se todos os componentes estão no mesmo dispositivo a comunicação deve ocorrer sem problemas. Se algum desses componentes está instalado em um dispositivo diferente e algum desses dispositivos tem um firewall configurado, pode ser necessário abrir portas para comunicação dos componentes.

Pule toda a seção 5 se:

  • Todos os componentes (dcrd, dcrwallet, dcrctl) estão no mesmo dispositivo e não há regras de firewall;
  • Todos os componentes (dcrd, dcrwallet, dcrctl) estão no mesmo dispositivo, o firewall é usado e há regras de firewall permitindo a comunicação localhost;
  • Nem todos os componentes estão no mesmo dispositivo mas não há nenhum firewall instalado nos dispositivos;
  • Nem todos os componentes estão no mesmo dispositivo mas todos os dispositivos estão na rede local, há um firewall instalado mas não há nenhuma regra bloqueando dispositivos da rede local

Por padrão os sistemas operacionais (firewalls) costumam permitir a saída de qualquer pacote de rede. Caso o firewall esteja configurado para proibir até mesmo pacotes de saída que não estejam explicitamente permitidos, veja as portas que precisam ser liberadas nas próximas seções.

5.1. localhost e Decrediton

Se todos os componentes (dcrd, dcrwallet, dcrctl) estão no mesmo dispositivo a comunicação deve fluir normalmente. No entanto, é possível que com regras muito rígidas no firewall até a comunicação localhost (no mesmo dispositivo) seja bloqueada. Se a comunicação não fluir normalmente, verifique se o iptables possui as regras que permitem a comunicação no localhost:

$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
$ sudo iptables -A OUTPUT -o lo -j ACCEPT

Se o Decrediton não foi configurado para usar um dcrd ou dcrwallet externo, então todos os componentes estão no mesmo dispositivo e a descrição acima é aplicável.

5.2. dcrd

Para permitir que o seu dcrd (incluído o dcrd do Decrediton) fale com outros dcrds no mundo exterior com apenas uma regra no iptables:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd to dcrd mainnet,testnet" -j ACCEPT

Para permitir a entrada de pacotes vindos de outros dcrds no mundo:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd from dcrd mainnet,testnet" -j ACCEPT

Para permitir a entrada de pacotes vindos de um dcrwallet instalado em outro dispositivo:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9109,19109 -s $LOCALNET -m comment --comment "dcrd from dcrwallet mainnet,testnet" -j ACCEPT

5.3. dcrwallet

Se o seu dcrwallet irá se conectar a um dcrd instalado em outro dispositivo pode ser necessário configurar as regras de saída:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrwallet to dcrd mainnet,testnet" -j ACCEPT

Se o dcrwallet será controlado por um dcrctl instalado em outro dispositivo:

$ sudo iptables -A INPUT -m multiport -p tcp --dports 9110,19110 -s $LOCALNET -m comment --comment "dcrwallet from dcrctl mainnet,testnet" -j ACCEPT

5.4. dcrctl

Se o dcrctl será usado para gerenciar um dcrd instalado em outro dispositivo pode ser necessário configurar as regras de saída:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrctl to dcrd mainnet,testnet" -j ACCEPT

Se o dcrctl será usado para gerenciar um dcrwallet instalado em outro dispositivo pode ser necessário configurar as regras de saída:

$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9110,19110 -d $LOCALNET -m comment --comment "dcrctl to dcrwallet mainnet,testnet" -j ACCEPT

5.5. Outros serviços

Será necessário permitir a saída de outros pacotes para o uso mínimo do dispositivo e dos componentes do Decred. Esse uso inclui:

  • Baixar novas versões do Decrediton e de outros binaries;
  • Verificar assinaturas digitais;
  • Consultar o DNS em busca de outros nodes da rede Decred;
  • Receber um endereço IP do DHCP Server;
  • Atualizar o sistema operacional
  • Atualizar o horário do sistema
$ sudo iptables -A OUTPUT -p udp --dport 53 -m comment --comment "DNS Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Extended Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 11371 -d pgp.mit.edu -m comment --comment "GPG HKP" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 67 -d $LOCALNET -m comment --comment "dhcp" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d ftp.debian.org -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d github.com -j ACCEPT

Para enviar pacotes ICMP Echo Request (pedidos) a qualquer destino e enviar ICMP Echo Reply (resposta) apenas para a rede local (PINGs):

$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -s $LOCALNET -m comment --comment "icmp ping reply" -j ACCEPT
$ sudo iptables -A OUTPUT -p icmp --icmp-type any -d -d $LOCALNET -m comment --comment "icmp out" -j ACCEPT

5.6. Regras gerais

A opção -P configura uma política para as chains do iptables. Para manter uma configuração whitelist (tudo é proibido exceto o que é especificamente permitido), as chains são configurada para recusar (drop) qualquer pacote que não se encaixe em uma das regras.

Não é comum proibir a saída de pacotes (OUTPUT DROP). Geralmente usa-se uma configuração OUTPUT ACCEPT.

$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
$ sudo iptables -P OUTPUT DROP

Para controlar a entrada de pacotes geralmente são usadas as seguintes regras: a primeira bloqueia pacotes inválidos (sem flags, com características fora do protocolo, etc) e a segunda permite conexões relacionadas a pacotes que já se encaixaram em alguma regra da chain.

$ sudo iptables -A INPUT -m state --state INVALID -j DROP
$ sudo iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT

Todos os pacotes que iniciam uma conexão e não tem a flag SYN devem ser recusados.

$ sudo iptables -A INPUT -m state --state NEW ! --syn -j DROP

No final todos os pacotes que não se encaixaram em nenhuma regra serão logados antes de serem recusados caso seja necessário fazer uma análise.

$ sudo iptables -A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
$ sudo iptables -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4

5.7. NAT

É provavel que, dependendo da sua estrutura de rede, ainda seja necessário criar uma regra de NAT no roteador. NAT (ou PAT) é uma tradução de endereços IP e portas no roteador para que servidores em uma rede privada estejam acessíveis a partir de uma rede pública.

5.8. O conjunto de regras

A seguir, uma lista com as regras sugeridas até agora. A ordem das regras está relacionada a expectativa de uso de cada uma delas. Como o processamento das regras ocorre sequencialmente de cima para baixo, coloca-se no topo da chain (INPUT, OUTPUT) as regras que se espera que sejam as mais utilizadas. A lista não é exaustiva.

$ sudo iptables -A INPUT -i lo -j ACCEPT
$ sudo iptables -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
$ sudo iptables -A INPUT -m state --state INVALID -j DROP
$ sudo iptables -A INPUT -m state --state ESTABLISHED -j ACCEPT
$ sudo iptables -A INPUT -p tcp -m state --state NEW ! --syn -j DROP
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd from dcrd mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9109,19109 -s $LOCALNET -m comment --comment "dcrd from dcrwallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -m multiport -p tcp --dports 9110,19110 -s $LOCALNET -m comment --comment "dcrwallet from dcrctl mainnet,testnet" -j ACCEPT
$ sudo iptables -A INPUT -p icmp --icmp-type echo-request -s $LOCALNET -m comment --comment "icmp ping reply" -j ACCEPT
$ sudo iptables -A INPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_INPUT_denied: " --log-level 4
$ sudo iptables -P INPUT DROP
$ sudo iptables -P FORWARD DROP
$ sudo iptables -A OUTPUT -o lo -j ACCEPT
$ sudo iptables -A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9108,19108 -m comment --comment "dcrd to dcrd mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9109,19109 -d $LOCALNET -m comment --comment "dcrwallet/ctl to dcrd/wallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 9110,19110 -d $LOCALNET -m comment --comment "dcrctl to dcrwallet mainnet,testnet" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 53 -m comment --comment "DNS Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 53 -m comment --comment "DNS Extended Queries" -j ACCEPT
$ sudo iptables -A OUTPUT -p tcp --dport 11371 -d pgp.mit.edu -m comment --comment "GPG HKP" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 67 -d $LOCALNET -m comment --comment "dhcp" -j ACCEPT
$ sudo iptables -A OUTPUT -p udp --dport 123 -m comment --comment "ntp" -j ACCEPT
$ sudo iptables -A OUTPUT -p icmp --icmp-type any -d $LOCALNET -m comment --comment "icmp out" -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d ftp.debian.org -j ACCEPT
$ sudo iptables -A OUTPUT -m multiport -p tcp --dports 80,443 -d github.com -j ACCEPT
$ sudo iptables -A OUTPUT -m limit --limit 3/min -j LOG --log-prefix "iptables_OUTPUT_denied: " --log-level 4
$ sudo iptables -P OUTPUT DROP

Após incluir as regras no kernel, não esqueça de salvar a configuração:

$ sudo iptables-save > /etc/iptables/rules.v4

Se não encontrar o iptables-save:

$ sudo apt-get install iptables-persistent

6. DNS Seeds

O dcrd guarda informações sobre outros nodes dcrd no arquivo peers.json, que fica no diretório padrão do dcrd, dentro do diretório da rede (mainnet, testnet2). Quando busca outros nodes na rede o dcrd lê esse arquivo e tenta se conectar nos nodes já conhecidos. Depois de um tempo sem executar o dcrd, é possível que todos aqueles nodes conhecidos tenham sido desligados ou que seus endereços IP já tenham mudado.

Figura 4 - dcrd usa DNS Seeds para localizar outros nodes da rede
Figura 4 - dcrd usa DNS Seeds para localizar outros nodes da rede

Para resolver isso o dcrd se conecta nos servidores DNS da rede e procura nodes válidos. É o serviço dcrseeder que frequentemente valida os nodes conhecidos e disponibiliza essa informação para outros nodes, que por sua vez passam a outros e assim por diante.

A Simnet é uma rede de simulação privada usada para testes. A descoberta dos nodes da rede não funciona como na Mainnet ou na Testnet, caso contrário essa rede seria apenas mais uma Testnet pública. Por isso o DNS Seed da Simnet não tem nenhum endereço para localização de nodes, como pode ser visto a seguir.

As informações a seguir, sobre DNS Seeds, estão no arquivo de configuração https://github.com/decred/dcrd/blob/master/chaincfg/params.go#L476.

  DNSSeeds: []DNSSeed{
    {"mainnet-seed.decred.mindcry.org", true},
    {"mainnet-seed.decred.netpurgatory.com", true},
    {"mainnet-seed.decred.org", true},
  },
(...)
  DNSSeeds: []DNSSeed{
    {"testnet-seed.decred.mindcry.org", true},
    {"testnet-seed.decred.netpurgatory.com", true},
    {"testnet-seed.decred.org", true},
  },
(...)
  DNSSeeds:    []DNSSeed{}, // NOTE: There must NOT be any seeds.

O dcrd recebe as informações sobre outros nodes e anota o endereço IP do novo node e o IP do node que passou essa informação, no arquivo peers.json no formato a seguir:

"Addresses":[
{
  "Addr":"45.55.161.169:9108",
  "Src":"45.77.55.251:9108",
  "Attempts":0,
  "TimeStamp":1519833581,
  "LastAttempt":-62135596800,
  "LastSuccess":-62135596800
},
{
  "Addr":"192.71.144.233:9108",
  "Src":"192.155.93.22:9108",
  "Attempts":0,
  "TimeStamp":1519833581,
  "LastAttempt":-62135596800,
  "LastSuccess":-62135596800
},
]

Para mais informações, veja https://github.com/decred/dcrseeder.

7. Um cenário comum

Na rede Decred encontramos os cenários mais variados:

  • Decrediton executado no Mac, Linux ou Windows;
  • Decrediton conectado a um dcrd na rede local;
  • dcrd, dcrwallet e dcrctl no mesmo dispositivo;
  • dcrd em um dispositivo, dcrwallet e dcrctl em outro;
  • Um node com dcrd, um Raspberry Pi com dcrwallet e o Decrediton como front-end

A modularidade do Decred permite inúmeras configurações, se adaptando ao perfil do usuário, da rede e das necessidades de segurança.

Figura 5 - Um cenário comum na rede Decred
Figura 5 - Um cenário comum na rede Decred

Informações sobre os endereços e sobre outros tópicos podem ser aprendidas através da leitura do código em https://github.com/decred/dcrd/blob/master/chaincfg/params.go#L326.