Forking Bitcoin Core in 2026
A modern path for chain identity, genesis hashing, and testnet-first discipline.
Score Notes
Why this confidence score?
This score is an editorial signal based on source quality, corroboration, citations, and review status. It is not a guarantee of truth.
2026 Bitcoin Core Forking Guide
A modern, professional guide to forking Bitcoin Core and hashing a new genesis block
This is based on the classic altcoin-cloning pattern: rename the tree, change chain identity, set ports, set magic bytes, change supply/block rules, generate a new genesis block, patch the hash/merkle/nonce, run two nodes, then package releases. The old ABCCoin/Bitcoin 0.8.99 guide focused on chainparams.cpp, message-start bytes, ports, timestamp, nonce, merkle root, checkpoints, address prefixes, subsidy, block timing, and GUI branding. The Devtome scrypt guide added GitHub workflow, dependency setup, testnet-first validation, two-node testing, mainnet genesis generation, and Qt wallet compilation. The secured mining notes add the practical security layer: wallet encryption, wallet.dat handling, signature verification, traffic inspection, and never trusting random binaries from the cryptosphere’s junk drawer. The ASIC/BFGMiner material is useful operational history: external miners, pool behavior, Stratum/getwork bridges, cooling, power, and the eternal truth that mining software is only romantic until hardware starts screaming.
Bitcoin Core 2026 is not Bitcoin 0.8.99. The modern source tree uses CMake, the genesis code lives under src/kernel/chainparams.cpp, chain-base ports live in src/chainparamsbase.cpp, and release engineering is far more serious than “zip the folder and pray.” Bitcoin Core 30.1 was available in January 2026, with source in the official Bitcoin Core repository, and current supported/tested OS targets include Linux kernel 3.17+, macOS 13+, and Windows 10+. (Bitcoin Core)
0. The rule before all rules
Do not accidentally connect your fork to Bitcoin mainnet.
That means you change:
| Area | Must change |
|---|---|
| Network magic | pchMessageStart |
| P2P port | nDefaultPort |
| RPC port | src/chainparamsbase.cpp |
| Genesis block | timestamp, script, time, bits, nonce, merkle, hash |
| Seeds | DNS seeds and fixed seeds |
| Address formats | Base58 prefixes and Bech32 HRP |
| Checkpoints / assume-valid | reset or regenerate |
| Chainwork assumptions | reset |
| Data directory | new datadir name |
| Branding | binary names, UI labels, docs |
The old guides were right about the essentials: unique message bytes, unique ports, unique genesis, unique address prefix. They were wrong only by age. In 2026, blind search-and-replace is how you summon build errors and embarrassment.
1. Pick your source base
Use a stable release tag, not random master, unless you are doing active Core development. Bitcoin Core’s own repository notes that master is regularly built and tested but not guaranteed stable; release tags are the official stable versions. (GitHub)
git clone https://github.com/bitcoin/bitcoin.git mycoin-core
cd mycoin-core
# Example: use a stable tag.
git fetch --tags
git checkout v30.1
git switch -c mycoin-v0.1
Recommended starting posture:
Base: Bitcoin Core v30.1 or current stable tag
Initial target: Linux daemon only
Wallet: off at first
GUI: later
Public launch: only after private testnet survives
Do not start with Windows GUI packaging. That is like learning sword fighting by juggling lawnmower blades.
2. Build stock Bitcoin Core first
Before changing anything, prove your workstation can build unmodified Core.
Bitcoin Core’s current Unix build flow is CMake-based: cmake -B build, cmake --build build, and optionally cmake --install build; the docs also recommend cmake -B build -LH to inspect options. (GitHub)
Ubuntu/Debian baseline:
sudo apt update
sudo apt install -y build-essential cmake python3 libboost-dev git
# Optional wallet / GUI dependencies:
sudo apt install -y libsqlite3-dev qt6-base-dev qt6-tools-dev qt6-l10n-tools \
qt6-tools-dev-tools libgl-dev qt6-wayland libqrencode-dev
Node-only build:
cmake -B build -DENABLE_WALLET=OFF
cmake --build build -j"$(nproc)"
ctest --test-dir build --output-on-failure
Run regtest sanity check:
mkdir -p /tmp/mycoin-stock-test
./build/bin/bitcoind -regtest -datadir=/tmp/mycoin-stock-test -daemon
./build/bin/bitcoin-cli -regtest -datadir=/tmp/mycoin-stock-test getblockchaininfo
./build/bin/bitcoin-cli -regtest -datadir=/tmp/mycoin-stock-test stop
Bitcoin Core’s build docs list package-manager dependencies and optional wallet/IPC/ZMQ/GUI dependency columns; use that as the canonical dependency source, not decade-old forum posts. (GitHub)
3. Define the coin before touching code
Create a docs/coin-spec.md before coding. A fork without a spec is just a compile error with a logo.
# MyCoin Spec v0.1
Name: MyCoin
Ticker: MYC
Daemon: mycoind
CLI: mycoin-cli
GUI: mycoin-qt
Mainnet P2P: 29333
Mainnet RPC: 29332
Testnet P2P: 39333
Testnet RPC: 39332
Regtest P2P: 49333
Regtest RPC: 49332
Block target: 600 seconds
Retarget interval: 2016 blocks
Halving interval: 210000 blocks
Genesis reward: 50 MYC
Coinbase maturity: 100 blocks
Max supply: 21,000,000 MYC unless intentionally changed
Address:
P2PKH prefix: TBD
P2SH prefix: TBD
WIF prefix: TBD
Bech32 HRP: myc
Genesis:
Timestamp: "30/Jun/2026 ..."
nTime: TBD
nBits: 0x1e0fffff for easy development genesis, or harder for public launch
nNonce: TBD
Merkle root: TBD
Genesis hash: TBD
Launch:
No premine unless explicitly disclosed.
No inherited Bitcoin DNS seeds.
No inherited Bitcoin checkpoints.
No inherited Bitcoin assumeutxo data.
Parameter advice:
| Parameter | Conservative default | Why |
|---|---|---|
| Block time | 600 seconds | Boring, stable, compatible with existing assumptions |
| Retarget | 2016 blocks | Proven; not sexy, but sexy breaks chains |
| Halving | 210,000 blocks | Predictable Bitcoin-like schedule |
| Coinbase maturity | 100 | Reduces reorg-spend chaos |
| Starting difficulty | easy for dev, harder for public | Dev needs speed; public needs anti-instamine planning |
A new SHA256d coin is not CPU-democratic. Any public SHA256d fork is born under the shadow of ASICs. Plan for that or accept that your “fair launch” may last twelve seconds and a cough.
4. Rename carefully
Do not global replace bitcoin with mycoin in one shot. Use git grep, review, then patch.
git grep -n "Bitcoin"
git grep -n "bitcoin"
git grep -n "BTC"
git grep -n "bc1"
git grep -n "xpub"
git grep -n "xprv"
Suggested rename targets:
| Old | New example |
|---|---|
| Bitcoin Core | MyCoin Core |
| Bitcoin | MyCoin |
| bitcoin | mycoin |
| BTC | MYC |
| bitcoind | mycoind |
| bitcoin-cli | mycoin-cli |
| bitcoin-qt | mycoin-qt |
.bitcoin | .mycoin |
bitcoin.conf | mycoin.conf |
bc Bech32 HRP | myc |
Do not rename copyright notices, upstream URLs, dependency references, or historical comments unless you know exactly why. Keep MIT license attribution intact. Bitcoin Core itself is MIT licensed. (GitHub)
5. Current file map: old guide names vs 2026 Core
| Classic guide location | 2026-style location |
|---|---|
src/main.cpp genesis / subsidy / validation | src/kernel/chainparams.cpp, src/validation.cpp, src/consensus/* |
makefile.unix | CMake build system |
src/bitcoinrpc.cpp RPC port | src/chainparamsbase.cpp |
base58.h address prefix | src/kernel/chainparams.cpp chain params |
checkpoints.cpp | mostly removed/reworked; use chain params, assume-valid, chainwork, assumeutxo carefully |
bitcoin-qt.pro | CMake / Qt6 build flow |
| IRC seed discovery | DNS seeds / fixed seeds / manual addnode |
Modern Core’s src/kernel/chainparams.cpp contains the genesis construction helpers, including CreateGenesisBlock, the genesis coinbase transaction, block fields, merkle root computation, and the built-in Bitcoin genesis timestamp/script. (GitHub)
6. Patch chain identity
6.1 Main chain params
Edit:
src/kernel/chainparams.cpp
In CMainParams, change:
m_chain_type = ChainType::MAIN;
consensus.nSubsidyHalvingInterval = 210000;
consensus.powLimit = uint256{"00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"};
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60;
consensus.nPowTargetSpacing = 10 * 60;
consensus.fPowAllowMinDifficultyBlocks = false;
consensus.fPowNoRetargeting = false;
consensus.nMinimumChainWork = uint256{};
consensus.defaultAssumeValid = uint256{};
Do not inherit Bitcoin’s nMinimumChainWork or defaultAssumeValid. Those values are trust accelerators for Bitcoin’s historical chain, not magical seasoning.
Current Bitcoin mainnet chain params include halving interval, BIP activation heights, PoW limit, target timespan/spacing, minimum chainwork, assume-valid, message-start bytes, default port, genesis creation, DNS seeds, base58 prefixes, Bech32 HRP, assumeutxo data, chain transaction data, and headers-sync data in the mainnet constructor. (GitHub)
6.2 Message start bytes
Change:
pchMessageStart[0] = 0xa1;
pchMessageStart[1] = 0xcf;
pchMessageStart[2] = 0x7e;
pchMessageStart[3] = 0x42;
Rules:
- Do not use Bitcoin mainnet:
f9 be b4 d9. - Do not use Bitcoin testnet, signet, or regtest bytes.
- Use bytes unlikely to appear in normal data.
- Keep a written derivation, for example: “first four bytes of SHA256d('MyCoin mainnet 2026 genesis')”.
Bitcoin Core comments explicitly describe message-start bytes as rare upper-ASCII bytes designed to be unlikely in normal data. (GitHub)
6.3 P2P port
Change:
nDefaultPort = 29333;
Bitcoin’s mainnet default P2P port is currently set in chain params beside message-start bytes and genesis setup. (GitHub)
6.4 RPC port and data directory
Edit:
src/chainparamsbase.cpp
Patch:
case ChainType::MAIN:
return std::make_unique<CBaseChainParams>("", 29332);
case ChainType::TESTNET:
return std::make_unique<CBaseChainParams>("testnet3", 39332);
case ChainType::REGTEST:
return std::make_unique<CBaseChainParams>("regtest", 49332);
src/chainparamsbase.cpp defines chain selection arguments, regtest/testnet/signet flags, and the base chain params mapping that includes RPC ports like Bitcoin mainnet 8332 and regtest 18443. (GitHub)
7. Address formats
In src/kernel/chainparams.cpp, change:
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1, 50); // example
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1, 85); // example
base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1, 178); // example WIF
base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E}; // change only with full wallet tooling awareness
base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
bech32_hrp = "myc";
Do not pick prefixes casually. Generate sample addresses and verify:
./build/bin/mycoind -regtest -daemon
./build/bin/mycoin-cli -regtest createwallet test
./build/bin/mycoin-cli -regtest getnewaddress
./build/bin/mycoin-cli -regtest stop
Bitcoin Core mainnet sets Base58 P2PKH/P2SH/WIF prefixes and the Bech32 HRP in the main chain params constructor. (GitHub)
8. Seeds and fixed seeds
Remove Bitcoin seeds:
vSeeds.clear();
vFixedSeeds.clear();
Then add yours:
vSeeds.emplace_back("seed1.mycoin.example.");
vSeeds.emplace_back("seed2.mycoin.example.");
For first private tests, use manual nodes:
./build/bin/mycoind -datadir=/tmp/mycoin-node-a -port=29333 -rpcport=29332 -daemon
./build/bin/mycoind -datadir=/tmp/mycoin-node-b -port=29334 -rpcport=29335 \
-connect=127.0.0.1:29333 -daemon
Never ship Bitcoin DNS seeds inside your fork. That is not nostalgia. That is network pollution.
9. Genesis block design
Modern Bitcoin Core has two relevant helpers:
static CBlock CreateGenesisBlock(
const char* pszTimestamp,
const CScript& genesisOutputScript,
uint32_t nTime,
uint32_t nNonce,
uint32_t nBits,
int32_t nVersion,
const CAmount& genesisReward
)
and the Bitcoin-specific overload:
static CBlock CreateGenesisBlock(
uint32_t nTime,
uint32_t nNonce,
uint32_t nBits,
int32_t nVersion,
const CAmount& genesisReward
)
The current source builds the genesis transaction, sets nTime, nBits, nNonce, nVersion, null previous block, computes the merkle root, and returns the block. (GitHub)
Patch the Bitcoin-specific overload or create your own:
static CBlock CreateMyCoinGenesisBlock(
uint32_t nTime,
uint32_t nNonce,
uint32_t nBits,
int32_t nVersion,
const CAmount& genesisReward
)
{
const char* pszTimestamp =
"30/Jun/2026 Example public headline proving no precomputed genesis";
const CScript genesisOutputScript =
CScript() << "02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"_hex
<< OP_CHECKSIG;
return CreateGenesisBlock(
pszTimestamp,
genesisOutputScript,
nTime,
nNonce,
nBits,
nVersion,
genesisReward
);
}
Then in CMainParams:
genesis = CreateMyCoinGenesisBlock(
1782864000, // nTime
0, // nNonce placeholder
0x1e0fffff, // nBits; dev-friendly example
1, // nVersion
50 * COIN // genesis reward
);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256{"PUT_GENESIS_HASH_HERE"});
assert(genesis.hashMerkleRoot == uint256{"PUT_MERKLE_ROOT_HERE"});
Bitcoin Core’s own comment notes that the genesis transaction output cannot be spent because it did not originally exist in the database. (GitHub)
10. Hash the genesis block
10.1 Use a standalone script first
Save as:
tools/genesis_finder.py
#!/usr/bin/env python3
import argparse
import hashlib
import struct
import time
COIN = 100_000_000
def sha256d(data: bytes) -> bytes:
return hashlib.sha256(hashlib.sha256(data).digest()).digest()
def varint(n: int) -> bytes:
if n < 0xfd:
return bytes([n])
if n <= 0xffff:
return b"\xfd" + struct.pack("<H", n)
if n <= 0xffffffff:
return b"\xfe" + struct.pack("<I", n)
return b"\xff" + struct.pack("<Q", n)
def push_data(data: bytes) -> bytes:
if len(data) < 0x4c:
return bytes([len(data)]) + data
if len(data) <= 0xff:
return b"\x4c" + bytes([len(data)]) + data
if len(data) <= 0xffff:
return b"\x4d" + struct.pack("<H", len(data)) + data
return b"\x4e" + struct.pack("<I", len(data)) + data
def target_from_bits(bits: int) -> int:
exponent = bits >> 24
mantissa = bits & 0xFFFFFF
if exponent <= 3:
return mantissa >> (8 * (3 - exponent))
return mantissa << (8 * (exponent - 3))
def make_coinbase_tx(timestamp: str, reward_sats: int, pubkey_hex: str, bits: int) -> bytes:
# Matches Bitcoin Core's historical genesis scriptSig structure:
# 04 <nBits little-endian> 01 04 <timestamp push>
script_sig = (
b"\x04"
+ struct.pack("<I", bits)
+ b"\x01\x04"
+ push_data(timestamp.encode("utf-8"))
)
pubkey = bytes.fromhex(pubkey_hex)
script_pubkey = push_data(pubkey) + b"\xac" # <pubkey> OP_CHECKSIG
tx = b""
tx += struct.pack("<i", 1) # version
tx += varint(1) # input count
tx += b"\x00" * 32 # prevout hash
tx += struct.pack("<I", 0xffffffff) # prevout index
tx += varint(len(script_sig)) + script_sig
tx += struct.pack("<I", 0xffffffff) # sequence
tx += varint(1) # output count
tx += struct.pack("<q", reward_sats) # value
tx += varint(len(script_pubkey)) + script_pubkey
tx += struct.pack("<I", 0) # locktime
return tx
def make_header(version: int, merkle_raw: bytes, ntime: int, bits: int, nonce: int) -> bytes:
return (
struct.pack("<i", version)
+ b"\x00" * 32
+ merkle_raw
+ struct.pack("<III", ntime, bits, nonce)
)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--timestamp", required=True)
parser.add_argument("--time", type=int, default=int(time.time()))
parser.add_argument("--bits", default="0x1e0fffff")
parser.add_argument("--version", type=int, default=1)
parser.add_argument("--reward", type=int, default=50)
parser.add_argument(
"--pubkey",
required=True,
help="Compressed or uncompressed public key hex; no 0x prefix.",
)
parser.add_argument("--start-nonce", type=int, default=0)
parser.add_argument("--max-nonce", type=int, default=0xffffffff)
args = parser.parse_args()
bits = int(args.bits, 16) if args.bits.startswith("0x") else int(args.bits)
reward_sats = args.reward * COIN
tx = make_coinbase_tx(args.timestamp, reward_sats, args.pubkey, bits)
merkle_raw = sha256d(tx)
merkle_display = merkle_raw[::-1].hex()
target = target_from_bits(bits)
print(f"timestamp : {args.timestamp}")
print(f"nTime : {args.time}")
print(f"nBits : 0x{bits:08x}")
print(f"target : {target:064x}")
print(f"merkle root : {merkle_display}")
print("searching...")
for nonce in range(args.start_nonce, args.max_nonce + 1):
header = make_header(args.version, merkle_raw, args.time, bits, nonce)
block_hash_raw = sha256d(header)
block_hash_int = int.from_bytes(block_hash_raw[::-1], "big")
if nonce % 100000 == 0:
print(f"nonce {nonce}: {block_hash_raw[::-1].hex()}")
if block_hash_int <= target:
print("\nFOUND")
print(f"nNonce : {nonce}")
print(f"genesis hash : {block_hash_raw[::-1].hex()}")
print(f"merkle root : {merkle_display}")
return
raise SystemExit("No valid nonce found. Increase time, loosen nBits, or use a faster miner.")
if __name__ == "__main__":
main()
Make executable:
chmod +x tools/genesis_finder.py
Run with a real public key:
python3 tools/genesis_finder.py \
--timestamp "30/Jun/2026 Example public headline proving no precomputed genesis" \
--time "$(date +%s)" \
--bits 0x1e0fffff \
--reward 50 \
--pubkey 02aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
For development, 0x1e0fffff is practical. For Bitcoin’s original 0x1d00ffff, expect billions of hashes on average. Python is a chisel, not a tunnel boring machine.
10.2 Patch the result
Take the script output:
nNonce : 123456
genesis hash : 00000abc...
merkle root : deadbeef...
Patch:
genesis = CreateMyCoinGenesisBlock(1782864000, 123456, 0x1e0fffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256{"00000abc..."});
assert(genesis.hashMerkleRoot == uint256{"deadbeef..."});
Also ensure:
consensus.powLimit = uint256{"00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"};
The genesis target implied by nBits must be equal to or harder than powLimit.
11. Reset historical Bitcoin assumptions
In CMainParams, do not ship Bitcoin historical data:
consensus.nMinimumChainWork = uint256{};
consensus.defaultAssumeValid = uint256{};
m_assumeutxo_data = {};
chainTxData = ChainTxData{
.nTime = 0,
.tx_count = 0,
.dTxRate = 0.0,
};
vSeeds.clear();
vFixedSeeds.clear();
Bitcoin’s current chain params include Bitcoin-specific assumeutxo snapshots, chain transaction counts, default assume-valid blocks, and minimum chainwork. Those are performance assumptions for Bitcoin, not universal truths. (GitHub)
12. BIP activation heights
For a new chain, do not inherit Bitcoin’s historical heights:
consensus.BIP34Height = 1;
consensus.BIP65Height = 1;
consensus.BIP66Height = 1;
consensus.CSVHeight = 1;
consensus.SegwitHeight = 1;
Use height 1 or a deliberately scheduled activation height. Height 1 means “active after genesis,” which is usually sane for a modern fork. The exact values must be tested; consensus mistakes here are chain-splitting mistakes.
Version-bits deployments should be either disabled, already active where appropriate, or scheduled clearly. Do not leave Bitcoin deployment windows pretending your chain lived through Bitcoin’s history.
13. Subsidy and money supply
Find subsidy logic:
git grep -n "GetBlockSubsidy"
git grep -n "nSubsidyHalvingInterval"
git grep -n "50 * COIN"
git grep -n "MAX_MONEY"
Keep Bitcoin-like economics unless you have a reason:
consensus.nSubsidyHalvingInterval = 210000;
If you change supply, document it mathematically:
Block reward: 50 MYC
Halving every: 210,000 blocks
Block target: 600 seconds
Approx first halving: 4 years
Total approximate supply: 21,000,000 MYC
No hidden premine. No “developer reserve” buried in code while the README says “fair.” That is not engineering. That is a slow confession.
14. Regtest first
Bitcoin Core regtest is explicitly a special chain where blocks can be solved instantly and is intended for regression testing and app development. (GitHub)
Build:
cmake -B build -DENABLE_WALLET=ON
cmake --build build -j"$(nproc)"
Run:
DATADIR=/tmp/mycoin-regtest
mkdir -p "$DATADIR"
./build/bin/mycoind -regtest -datadir="$DATADIR" -daemon
./build/bin/mycoin-cli -regtest -datadir="$DATADIR" createwallet miner
ADDR=$(./build/bin/mycoin-cli -regtest -datadir="$DATADIR" getnewaddress)
./build/bin/mycoin-cli -regtest -datadir="$DATADIR" generatetoaddress 101 "$ADDR"
./build/bin/mycoin-cli -regtest -datadir="$DATADIR" getblockchaininfo
./build/bin/mycoin-cli -regtest -datadir="$DATADIR" getbalances
./build/bin/mycoin-cli -regtest -datadir="$DATADIR" stop
If this fails, stop. Do not proceed to testnet. Do not “just launch and fix later.” Chains remember your sins.
15. Two-node private mainnet test
Node A:
mkdir -p /tmp/mycoin-a
./build/bin/mycoind \
-datadir=/tmp/mycoin-a \
-port=29333 \
-rpcport=29332 \
-listen=1 \
-daemon
Node B:
mkdir -p /tmp/mycoin-b
./build/bin/mycoind \
-datadir=/tmp/mycoin-b \
-port=29334 \
-rpcport=29335 \
-connect=127.0.0.1:29333 \
-daemon
Inspect:
./build/bin/mycoin-cli -datadir=/tmp/mycoin-a -rpcport=29332 getblockchaininfo
./build/bin/mycoin-cli -datadir=/tmp/mycoin-a -rpcport=29332 getpeerinfo
./build/bin/mycoin-cli -datadir=/tmp/mycoin-b -rpcport=29335 getblockchaininfo
./build/bin/mycoin-cli -datadir=/tmp/mycoin-b -rpcport=29335 getpeerinfo
Expected:
blocks: 0
headers: 0
bestblockhash: your genesis hash
connections: 1
chain: main
16. Mining reality in 2026
The old guides used internal CPU mining commands like setgenerate true. That era is gone for normal public mining. Use generatetoaddress for regtest. For a public SHA256d chain, plan external mining infrastructure.
Minimum public-mining stack:
mycoind full node
Stratum server / pool software
ASIC-compatible SHA256d work distribution
Block template RPC
Monitoring
Explorer
Seed node
Faucet or launch distribution tooling
Historic material around getwork/Stratum bridges and BFGMiner is useful context, but modern deployment should avoid extinct getwork assumptions except for museum-grade hardware. The ASIC guide’s practical lesson still stands: mining is an operations stack, not just a binary.
17. Cross-builds and reproducible releases
Use the depends system for controlled dependencies and cross-compilation. Bitcoin Core’s depends README describes it as a system for building/caching dependencies and supporting cross-compilation; CMake must be pointed at the generated toolchain file to use those libraries. (GitHub)
Linux native depends build:
make -C depends -j"$(nproc)"
cmake -B build --toolchain depends/x86_64-pc-linux-gnu/toolchain.cmake
cmake --build build -j"$(nproc)"
Windows cross-build example:
sudo apt install -y g++-mingw-w64-x86-64-posix
make -C depends HOST=x86_64-w64-mingw32ucrt -j"$(nproc)"
cmake -B build-win \
--toolchain depends/x86_64-w64-mingw32ucrt/toolchain.cmake
cmake --build build-win -j"$(nproc)"
Bitcoin Core also maintains Guix tooling for bootstrappable/reproducible builds; the Guix docs explain that it helps audit and reproduce the toolchain instead of blindly trusting binary downloads, and the default build command is ./contrib/guix/guix-build from a clean repository. (GitHub)
Release checklist:
Signed source tag
Signed checksums
Reproducible build notes
Linux tarball
Windows installer/zip
macOS app/dmg if supported
Release notes
Known issues
Seed node list
Explorer URL
Mining pool URL
Bootstrap instructions
18. Security baseline
Borrow the old mining-security mentality, modernize the tooling:
Never distribute unsigned binaries.
Never download miners from random mirrors.
Use hardware-backed signing keys if possible.
Keep release builders clean.
Separate hot node keys from cold treasury keys.
Encrypt wallets.
Back up wallet descriptors/seeds.
Do not keep launch funds on the seed node.
Monitor P2P ports.
Log peer counts, orphan rates, rejects, stale blocks.
The secured mining notes were right in spirit: verify files, protect wallet material, watch unexpected network activity, and avoid running untrusted miner/wallet binaries.
19. Minimum test matrix
Before public release:
| Test | Required result |
|---|---|
| Clean build | Linux daemon builds from fresh clone |
| Unit tests | pass |
| Functional tests | pass or consciously forked |
| Regtest mining | can mine 101 blocks |
| Two-node sync | nodes connect and agree |
| Restart | nodes reload same chain |
| Reorg | short reorg works |
| Address generation | prefixes correct |
| Send transaction | tx confirms |
| Coinbase maturity | enforced |
| Difficulty retarget | behaves after interval |
| Fresh datadir | starts from genesis |
| Bad Bitcoin peer | rejected / does not cross-connect |
| DNS seeds | your seeds only |
| Release binary | hash matches signed checksum |
20. Common failure modes
| Symptom | Likely cause |
|---|---|
assert(consensus.hashGenesisBlock...) fails | wrong nonce, timestamp, bits, reward, output script, or endian mismatch |
| Merkle assert fails | timestamp/script/reward changed after hashing |
| Node connects to Bitcoin peers | message bytes / seeds / ports not fully changed |
| Address still starts with Bitcoin format | base58 or Bech32 HRP not changed |
| Blocks never mine | nBits too hard, powLimit mismatch, no miner |
| Nodes connect but disagree | different genesis or consensus params |
| Wallet crashes | prefix/descriptors/GUI rename broke assumptions |
| Build fails after rename | overzealous search-and-replace |
| Public chain gets instantly dominated | SHA256d ASIC economics ignored |
21. The 2026 clean fork sequence
# 1. Clone stable Core.
git clone https://github.com/bitcoin/bitcoin.git mycoin-core
cd mycoin-core
git checkout v30.1
git switch -c mycoin-v0.1
# 2. Build untouched.
cmake -B build -DENABLE_WALLET=OFF
cmake --build build -j"$(nproc)"
ctest --test-dir build --output-on-failure
# 3. Create spec.
mkdir -p docs tools
$EDITOR docs/coin-spec.md
# 4. Rename carefully.
git grep -n "Bitcoin\|bitcoin\|BTC\|bc1"
# 5. Patch chain params.
$EDITOR src/kernel/chainparams.cpp
$EDITOR src/chainparamsbase.cpp
# 6. Generate genesis.
$EDITOR tools/genesis_finder.py
python3 tools/genesis_finder.py --timestamp "..." --time "$(date +%s)" \
--bits 0x1e0fffff --reward 50 --pubkey YOUR_PUBLIC_KEY_HEX
# 7. Patch genesis hash, merkle, nonce.
$EDITOR src/kernel/chainparams.cpp
# 8. Rebuild.
rm -rf build
cmake -B build -DENABLE_WALLET=ON
cmake --build build -j"$(nproc)"
# 9. Regtest.
./build/bin/mycoind -regtest -daemon
./build/bin/mycoin-cli -regtest createwallet miner
ADDR=$(./build/bin/mycoin-cli -regtest getnewaddress)
./build/bin/mycoin-cli -regtest generatetoaddress 101 "$ADDR"
./build/bin/mycoin-cli -regtest stop
# 10. Two-node private mainnet.
# Start node A and B with separate datadirs and ports.
22. Final professional standard
A credible 2026 Bitcoin Core fork ships with:
A public spec
A clean source tree
A unique genesis block
Unique network identity
No inherited Bitcoin seeds
No hidden premine
Signed releases
Reproducible build path
Working seed nodes
Working explorer
Working miner/pool path
Clear launch docs
Clear risk disclosure
The classics taught the mechanics. The modern era demands discipline. Anyone can fork code; fewer can launch a network that survives first contact with miners, wallets, users, and reality.