通过修改创世区块简单制作山寨币

参考:
http://shusunny.github.io/2016/04/13/altcoin_build_1/
http://blog.csdn.net/hacode/article/details/40422535
1.获取源码
https://github.com/bitcoin/bitcoin/
使用版本 0.10 0.12 0.12版本后,客户端不能直接挖矿,所以最新的测试到0.12.我选择0.102.
全文复制于http://shusunny.github.io/2016/04/13/altcoin_build_1/
修正原文一个书写错误,添加一个遗漏,添加一处说明
书写错误:
 openssl ecparam -genkey -name secp256k1 -out genesiscoinbase.pem
 openssl ec -in genesiscoinbase.pem -text > genesiscoinbase.hex
  此处genesiscoinbase.pem原文为testnetalert.pem。 
 遗漏:获得创世区块后,回填的时候nBit也应当回填,
另外,原博主挖矿代码设定的难度值过小,需修改block.nBits = 0x1f00ffff;更大,或者修改最小难度设定
 bnProofOfWorkLimit = ~uint256(0) >> 32


修改区块链参数
首先我们需要进入chainparams.cpp
cd src
sudo gedit chainparams.cpp
然后我们在代码中搜索 mapCheckpoints,在第55行,它大概是这个样子的:
static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x00223155*****"));
这里会显示一大串数据,分别是不同区块的hash值,是比特币客户端用来验证之前区块值是否正确。
而我们需要把11111那一行的数值改为
( 0, uint256("0x001"));
这里,0代表的是第几个区块。0后面的uint256表示的就是初始块的hash值。
可是我们的新币还没有正式运行呢?怎么得到它的hash值呢?我们下面会讲如果挖创始块。这里我们姑且做一个大胆并且绝对错误的推断,让其等于001。
同样的,我们还需要搜索并更改 mapCheckpointsTestnetmapCheckpointsRegtest 同一位置的数据。可能他们只有一行,并非大串数据。他们表示的是测试网络的区块值。
没关系,大胆的把他们全部变成 ( 0, uint256("0x001"));
现在我们返回 mapCheckpoints,在刚才的数据地图的下面,我们可以看到
1397080064, // * UNIX timestamp of last checkpoint block
36544669, // * total number of transactions between genesis and last checkpoint
// (the tx=... number in the SetBestChain debug.log lines)
60000.0 // * estimated number of transactions per day after checkpoint
这里通过英文注释我们可以看到,第一行代表上个检查点的时间,第二行是创始块直到上次检查时的交易数量。第三行表示平均每天的交易量。我们运行
date +%s
将上面命令行得到的值替换到上述bitcoin代码的第一行,第二行交易数量随便填,估且填为10吧。第三行看情况来,先填成10000吧。
将同样的时间和交易数量数据像上面那样填进test和regtest的信息里。平均交易量填一半就好。
mapCheckpointsRegtest下是CMainParams函数。在函数中有四行指针代码表示pchMessageStart。一般作为用来对比特币的交易进行验证的协议(protocol)。其中每个数组的值都是0-255中的数值,以16进制的形式表示。他们一旦改变,任何人都无法将我们的客户端连进比特币的了。
我们可以在 http://numbermonk.com/?all=1 的表中从0-255找到我们喜欢的数字填进去。如果可以的话,再找8个填进CTestNetParams和CRegTestParams。
下面的代码是 vAlertPubKey。所以我们需要更改alert和genesis coinbase的key值。我们用命令行生成一些
openssl ecparam -genkey -name secp256k1 -out alertkey.pem
openssl ec -in alertkey.pem -text > alertkey.hex
openssl ecparam -genkey -name secp256k1 -out testnetalert.pem
openssl ec -in testnetalert.pem -text > testnetalert.hex
openssl ecparam -genkey -name secp256k1 -out genesiscoinbase.pem
openssl ec -in genesiscoinbase.pem -text > genesiscoinbase.hex
这样我们就得到了一系列alertkey和genesiscoinbase key。我们首先打开alertkey cat alertkey.hex。我们把‘pub’和‘ASN1 OID: secp256k1′中间的5行数值去掉冒号和空格填到 vAlertPubKey = ParseHex(“…”);里去。然后我们再用 cat testnetalert.hex把其中的数据填入到CTestNetParams函数中去。
下面我们更改时间标签 pszTimestamp。在这一行
const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
填入任意内容,最好小于90字节。带上时间戳
接下来我们将创始块的 pubkey填进去。打开 cat genesiscoinbase.hex,在
txNew.vout[0].scriptPubKey = CScript() << ParseHex("...") << OP_CHECKSIG;
中插入我们的key值。同样的去掉冒号和空格。
接下来,我们需要将
assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
这两行用//注释掉,以免在我们找初始块的时候报错影响程序运行。所有的文件改完别忘了保存一下。
下面的vSeeds表示的种子文件的位置,我们还没有种子文件的域名,先不要进行改动。
挖取创始块
现在我们开挖,打开main.cpp
sudo gedit main.cpp
我们在这一行后面
CBlock &block = const_cast(Params().GenesisBlock());
以及
// Start new block file
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
这一行前面,加入我们挖创始块的代码
uint256 bnTarget;
bool fNegative;
bool fOverflow;
uint256 hashGenesisBlock;
block.nBits = 0x1f00ffff;
bnTarget.SetCompact(block.nBits, &fNegative, &fOverflow);
LogPrintf("ProofOfWorkLimit %s\n", Params().ProofOfWorkLimit().ToString());
if (fNegative || bnTarget == 0 || fOverflow || bnTarget > Params().ProofOfWorkLimit()) {
error("InitBlockIndex CheckProofOfWork() : nBits below minimum work");
}else {
block.nTime = GetTime();//1231006505;
LogPrintf("block.nTime %d\n", block.nTime);
LogPrintf("bnTarget %s\n", bnTarget.ToString());
block.nNonce = 0;
while (true) {
if (block.nNonce%1000000000 == 0)
LogPrintf("block.nNonce--- %d\n", block.nNonce);
hashGenesisBlock = block.GetHash();
if (hashGenesisBlock <= bnTarget)
break;
block.nNonce++;
}
LogPrintf("block.nNonce******** %d\n", block.nNonce);
LogPrintf("hashGenesisBlock******** %s\n", hashGenesisBlock.ToString());
LogPrintf("hashMerkleRoot******** %s\n", block.hashMerkleRoot.ToString());
}
这段代码是会在我们程序运行的时候不断计算,并在debug.log中导出我们所需要的GenesisBlock的Hash值。保存并返回newcoin文件夹。重新编译
cd ..
make
如果我们上一篇中环境安装完全的话,应该会秒通过。然后我们运行我们的程序
然后程序会通知我们将文件目录放在哪里,用默认的设置就好。这时程序可能会跑一段时间崩溃掉。没关系,我们用
tail ~/.bitcoin/debug.log
进入到debug文件中去。看看我们是否导出了以下数值
2016-04-11 21:16:20 ProofOfWorkLimit 00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
2016-04-11 21:16:20 block.nTime 1460410772
2016-04-11 21:16:20 bnTarget 0000ffff00000000000000000000000000000000000000000000000000000000
2016-04-11 21:16:20 block.nNonce--- 0
2016-04-11 21:16:20 block.nNonce******** 43973
2016-04-11 21:16:20 hashGenesisBlock******** 0000f51a735d0f7da96f10797ad76e00e53614422987f2b6056aaf61857e165e
2016-04-11 21:16:20 hashMerkleRoot******** d5c218da6f5c257709c0d59177ae4527ea5049f15baf26260a071c2e212154ac
2016-04-11 21:16:20 Pre-allocating up to position 0x1000000 in blk00000.dat
2016-04-11 21:16:20 Pre-allocating up to position 0x100000 in rev00000.dat
如果有,那么恭喜你,你已经挖到了创始块,那么让我们返回到chainparams.cpp中,将hashGenesisBlock,hashMerkleRoot填入到刚才的区块地图中,即uint256(“0x001”),将001改为我们前面得到的hashGenesisBlock值,并将其填入已经被我们注释掉的assert中,并把注释去掉。
同样的,将上面log中block.nTime和block.nNonce的值填回到CMainParams的genesis.nTime和genesis.nNonce中去。他们在下面这行代码的上边。
hashGenesisBlock = genesis.GetHash();
最终回填结果为
genesis . nTime = 1460410772;
genesis . nBits = 0x1f00ffff ;
genesis . nNonce = 43973;
hashGenesisBlock = genesis . GetHash ();
assert ( hashGenesisBlock == uint256 ( " 0000f51a735d0f7da96f10797ad76e00e53614422987f2b6056aaf61857e165e " ));
assert ( genesis . hashMerkleRoot == uint256 ( " d5c218da6f5c257709c0d59177ae4527ea5049f15baf26260a071c2e212154ac " ));
保存。现在我们已经得到了我们的初始块, 别忘了将main.cpp中我们刚才填加的代码删掉,这样我们就完全构建出了一套属于我们的电子币系统。并且不会出现像比特币那样挖不着的情况。(毕竟是我们自己的,想挖多少就挖多少。哈哈哈)
你也可以将上面的程序额外运行两次,并把得到的hash值和各参数填入到Testnet和Regtest中去。
下面我们返回newcoin文件夹中, 重新编译,并删除原来的文件目录(非常重要)
cd ..
sudo make
rm -rf ~/.newcoin


你可能感兴趣的:(区块链学习--比特币)