Ambiente de desenvolvimento Bitcoin Core em regtest via Docker
Um setup mínimo e reprodutível pra aprender, testar e prototipar em cima do protocolo Bitcoin sem depender da rede real, sem sincronizar blocos, sem taxa e sem espera.
- Sobre
- Pré-requisitos
- Estrutura do projeto
- Início rápido
- Acessando o
bitcoin-cli - Fluxo básico no regtest
- Experimentos
- Comandos do dia a dia
- Portas e credenciais
- Persistência e reset
- Troubleshooting
- Referências
Este repositório provisiona um node Bitcoin Core isolado em modo regtest, ideal pra:
- Estudar o protocolo Bitcoin sem risco (nada sai pra mainnet).
- Minerar blocos sob demanda (sem PoW real, um bloco por comando).
- Testar wallets, scripts, transações e aplicações que usam RPC.
- Rodar testes determinísticos em CI.
O node fica dentro de um container, os dados persistem num volume nomeado, e o bitcoin-cli é usado direto pelo host via docker compose exec.
| Ferramenta | Versão mínima |
|---|---|
| Docker Engine | 20.10+ |
| Docker Compose | v2+ |
Verifique com
docker --versionedocker compose version.
.
├── docker-compose.yml # serviço bitcoind em regtest
├── bitcoind/
│ └── bitcoin.conf # config do node (RPC, txindex, portas)
└── README.md
bitcoin.conf— fonte da verdade do node: porta RPC, credenciais,txindex,fallbackfee.- Volume
bitcoind-data— persiste blockchain, wallets e chainstate entre restarts.
# 1. subir o node em background
docker compose up -d
# 2. verificar que está rodando
docker compose ps
# 3. acompanhar logs
docker compose logs -f bitcoind
# 4. parar (preserva dados)
docker compose down
# 5. parar e zerar tudo
docker compose down -vNa primeira vez, o Docker baixa a imagem bitcoin/bitcoin:28.0 (~80 MB) e inicializa o datadir.
Valide que o node está respondendo:
docker compose exec --user bitcoin bitcoind bitcoin-cli -regtest getblockchaininfoSaída esperada num node recém-criado:
{
"chain": "regtest",
"blocks": 0,
"headers": 0,
"bestblockhash": "0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206",
"initialblockdownload": true,
"size_on_disk": 293,
"warnings": []
}O bestblockhash mostrado é o genesis block do regtest — é sempre o mesmo, então serve como sanity check.
O CLI roda dentro do container, então você não precisa instalar nada no host.
docker compose exec --user bitcoin bitcoind bitcoin-cli -regtest getblockchaininfoA flag
--user bitcoiné obrigatória: sem ela o exec entra comoroote obitcoin-cliprocura a config em/root/.bitcoin/em vez de/home/bitcoin/.bitcoin/, resultando emCould not locate RPC credentials.
Adicione ao seu ~/.bashrc ou ~/.zshrc:
alias bitcoin-cli='docker compose -f ~/Work/bitcoin-corders-bootcamp/docker-compose.yml exec -T --user bitcoin bitcoind bitcoin-cli'Recarregue:
source ~/.bashrcAgora o uso é transparente, como se fosse local:
bitcoin-cli -regtest getblockchaininfoDica: a flag
-Tdesliga o TTY — importante pra pipes (| jq,| grep) e scripts.
Do zero até uma transação confirmada:
# 1. criar uma wallet
bitcoin-cli -regtest createwallet dev
# 2. gerar um endereço pra receber
ADDR=$(bitcoin-cli -regtest getnewaddress)
echo "Meu endereço: $ADDR"
# 3. minerar 101 blocos pra ter saldo gastável
# (a recompensa coinbase só matura após 100 confirmações)
bitcoin-cli -regtest generatetoaddress 101 "$ADDR"
# 4. checar saldo
bitcoin-cli -regtest getbalance
# 5. enviar pra outro endereço
DEST=$(bitcoin-cli -regtest getnewaddress)
TXID=$(bitcoin-cli -regtest sendtoaddress "$DEST" 1.5)
echo "TXID: $TXID"
# 6. confirmar minerando 6 blocos
bitcoin-cli -regtest generatetoaddress 6 "$ADDR"
# 7. inspecionar a tx
bitcoin-cli -regtest gettransaction "$TXID"Pequenos laboratórios pra ganhar intuição sobre como o protocolo funciona. Cada um é independente e pode rodar no mesmo node.
Simula dois "usuários" no mesmo node — útil pra entender como wallets isoladas vêem a mesma blockchain.
# criar uma segunda wallet
bitcoin-cli -regtest createwallet alice
# gerar endereço da alice (precisa especificar a wallet)
ALICE=$(bitcoin-cli -regtest -rpcwallet=alice getnewaddress)
# enviar da wallet 'dev' pra alice
bitcoin-cli -regtest -rpcwallet=dev sendtoaddress "$ALICE" 1.5
# tx está na mempool (ainda não confirmada)
bitcoin-cli -regtest getrawmempool
# minerar 1 bloco pra confirmar
bitcoin-cli -regtest -generate 1
# saldos das duas wallets
bitcoin-cli -regtest -rpcwallet=dev getbalance
bitcoin-cli -regtest -rpcwallet=alice getbalanceMostra os bytes reais da tx — inputs, outputs, scripts.
TXID=<txid_da_tx_anterior>
# versão decodificada (JSON)
bitcoin-cli -regtest getrawtransaction "$TXID" true
# versão crua (hex) — é isso que vai na wire
bitcoin-cli -regtest getrawtransaction "$TXID"Repare no campo vin[].scriptSig (desbloqueio) e vout[].scriptPubKey (trava) — o coração do modelo UTXO.
# criar várias txs sem minerar
for i in 1 2 3; do
bitcoin-cli -regtest -rpcwallet=dev sendtoaddress "$ALICE" 0.1
done
# ver a fila na mempool
bitcoin-cli -regtest getmempoolinfo
bitcoin-cli -regtest getrawmempool
# confirmar todas em um bloco só
bitcoin-cli -regtest -generate 1
bitcoin-cli -regtest getmempoolinfo # mempool vazia# estimar fee (em regtest retorna valores mínimos)
bitcoin-cli -regtest estimatesmartfee 6
# enviar com fee rate explícito (sat/vB)
bitcoin-cli -regtest -rpcwallet=dev -named sendtoaddress \
address="$ALICE" amount=0.5 fee_rate=10Exclusivo do regtest: força uma reorganização e veja a chain "mudar de opinião".
# snapshot inicial
bitcoin-cli -regtest getblockcount
bitcoin-cli -regtest getbestblockhash
# invalida o último bloco (ele volta pra mempool)
TIP=$(bitcoin-cli -regtest getbestblockhash)
bitcoin-cli -regtest invalidateblock "$TIP"
# minera outro no lugar
bitcoin-cli -regtest -generate 1
bitcoin-cli -regtest getbestblockhash # hash diferente
# reabilita o bloco anterior (se ficar mais longo, vence)
bitcoin-cli -regtest reconsiderblock "$TIP"Fluxo usado em wallets multisig e hardware wallets.
ADDR=$(bitcoin-cli -regtest -rpcwallet=dev getnewaddress)
# cria um PSBT enviando 0.1 BTC pra ADDR
PSBT=$(bitcoin-cli -regtest -rpcwallet=dev walletcreatefundedpsbt \
"[]" "[{\"$ADDR\":0.1}]" | jq -r .psbt)
# inspeciona
bitcoin-cli -regtest decodepsbt "$PSBT"
# assina
SIGNED=$(bitcoin-cli -regtest -rpcwallet=dev walletprocesspsbt "$PSBT" | jq -r .psbt)
# finaliza e extrai a tx pronta
HEX=$(bitcoin-cli -regtest finalizepsbt "$SIGNED" | jq -r .hex)
# broadcast
bitcoin-cli -regtest sendrawtransaction "$HEX"Requer
jqinstalado no host (sudo pacman -S jq).
bitcoin-cli -regtest getblockchaininfo # altura, chain, estado
bitcoin-cli -regtest getblockcount # só altura
bitcoin-cli -regtest getbestblockhash # hash do tip
bitcoin-cli -regtest getblock <hash> # detalhes de um blocobitcoin-cli -regtest listwallets
bitcoin-cli -regtest createwallet <name>
bitcoin-cli -regtest loadwallet <name>
bitcoin-cli -regtest getwalletinfo
bitcoin-cli -regtest getnewaddress
bitcoin-cli -regtest getbalance
bitcoin-cli -regtest listunspent # UTXOsbitcoin-cli -regtest sendtoaddress <addr> <btc>
bitcoin-cli -regtest gettransaction <txid>
bitcoin-cli -regtest getrawtransaction <txid> true
bitcoin-cli -regtest decoderawtransaction <hex>
bitcoin-cli -regtest listtransactionsbitcoin-cli -regtest generatetoaddress 1 <addr> # 1 bloco pro endereço
bitcoin-cli -regtest -generate 10 # 10 blocos (usa wallet atual)bitcoin-cli -regtest help # lista todos os comandos
bitcoin-cli -regtest help sendtoaddress # detalhes de um comando| Porta | Protocolo | Uso |
|---|---|---|
18443 |
HTTP | JSON-RPC (regtest) |
18444 |
TCP | P2P (regtest) |
Credenciais RPC definidas em bitcoind/bitcoin.conf:
rpcuser=bitcoin
rpcpassword=bitcoin
⚠️ Essas credenciais são apenas pra dev local. Nunca exponha na internet — em regtest já é ruim, em mainnet seria catastrófico.
curl --user bitcoin:bitcoin \
--data-binary '{"jsonrpc":"1.0","method":"getblockchaininfo","params":[]}' \
-H 'content-type: text/plain;' \
http://127.0.0.1:18443/Os dados (blockchain + wallets) vivem no volume nomeado bitcoind-data, então sobrevivem a docker compose down e up normais.
Resetar tudo (apaga volume, começa do bloco 0 e sem wallets):
docker compose down -v
docker compose up -dListar volumes do projeto:
docker volume ls | grep bitcoindO container reinicia em loop
Confira os logs:
docker compose logs bitcoindCausas comuns: erro de sintaxe no bitcoin.conf, flag inválida no command: do compose, ou conflito de porta (18443/18444 já em uso no host).
chown: ... bitcoin.conf: Read-only file system
O entrypoint da imagem faz chown em /home/bitcoin/.bitcoin/* antes de iniciar o bitcoind. Se o bind mount do bitcoin.conf estiver como :ro, o chown falha e o container reinicia em loop.
Fix: no docker-compose.yml, remova o :ro do mount:
volumes:
- ./bitcoind/bitcoin.conf:/home/bitcoin/.bitcoin/bitcoin.conf # sem :roDepois docker compose down && docker compose up -d.
Could not locate RPC credentials ... /root/.bitcoin/bitcoin.conf
Por padrão, docker compose exec entra no container como root — mas o bitcoin.conf está em /home/bitcoin/.bitcoin/, não em /root/.bitcoin/.
Fix: rode o exec como user bitcoin:
docker compose exec --user bitcoin bitcoind bitcoin-cli -regtest getblockchaininfoOu use o alias da seção Acessando o bitcoin-cli, que já inclui --user bitcoin.
`Loading block index...` demora muito
No regtest isso é instantâneo. Se travar, provavelmente o volume ficou corrompido — resete com docker compose down -v.
`error code: -18 Requested wallet does not exist`
Nenhuma wallet está carregada. Rode:
bitcoin-cli -regtest createwallet dev
# ou, se já existe:
bitcoin-cli -regtest loadwallet dev`Insufficient funds` logo depois de minerar
A recompensa coinbase só matura após 100 confirmações. Minere 101 blocos antes de gastar:
bitcoin-cli -regtest -generate 101Porta 18443 ou 18444 já em uso
Outro processo está ocupando a porta. Descubra e encerre:
ss -lntp | grep -E '18443|18444'Ou remapeie no docker-compose.yml (ex: "28443:18443").