主页 > imtoken怎么退出账号 > 如何以比特币为模型创建自己的山寨币(二)
如何以比特币为模型创建自己的山寨币(二)
如何以比特币为模型创建自己的山寨币(二)
上次我们将比特币中的所有文件名和内容更改为我们的新币 newcoin。但这还不够。为什么?因为所有内核参数都还在比特币中,即使客户端在运行,也会同步之前的比特币数据。现在是深入代码、探索比特币奥秘并做出一些真正属于我们的改变的时候了。
修改区块链参数
首先我们需要输入chainparams.cpp
cd src
sudo gedit chainparams.cpp
然后我们在代码中搜索mapCheckpoints比特币nbits,在第55行,看起来是这样的:
static Checkpoints::MapCheckpoints mapCheckpoints =
boost::assign::map_list_of
( 11111, uint256("0x00223155*****"));
这里会展示一大串数据,是不同区块的哈希值,比特币客户端用来验证之前的区块值是否正确。我们需要将 11111 行的值更改为
( 0, uint256("0x001"));
这里,0 表示块的数量。0后面的uint256代表初始块的hash值。但是我们的新币还没有正式运行?如何得到它的哈希值?我们将在下面讨论如何挖掘创世块。这里我们做一个大胆且绝对错误的推论,让它等于001。
同样,我们也需要在mapCheckpointsTestnet和mapCheckpointsRegtest的同一位置搜索和更改数据。也许他们只有一行,而不是一大串数据。它们代表测试网络的块值。没关系,大胆的把它们都变成(0, uint256("0x001"));。
现在我们回到mapCheckpoints,在之前的数据map下,我们可以看到
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
把上面命令行得到的值替换成上面比特币代码的第一行,第二行填写交易号,估计是10。第三行看情况,先填10000。
使用与上述相同的时间和交易计数数据填写测试和注册测试信息。只需填写平均交易量的一半。
在 mapCheckpointsRegtest 下是 CMainParams 函数。函数中有四行指针代码代表 pchMessageStart。通常用作验证比特币交易的协议。每个数组的值是一个从 0 到 255 的数值,以十六进制形式表示。一旦它们发生变化,就没有人能够将我们的客户连接到比特币。
我们可以在表格中从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 testnetalert.pem -text > genesiscoinbase.hex
这样我们就得到了一系列的 alertkey 和 genesiscoinbase 密钥。我们先打开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字以内)比特币nbits,然后填写。
接下来我们填写创世块的公钥。打开 cat genesiscoinbase.hex,在
txNew.vout[0].scriptPubKey = CScript() << ParseHex("...") << OP_CHECKSIG;
将我们的键值插入 . 同时删除冒号和空格。
接下来,我们需要
assert(hashGenesisBlock == uint256("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
这两行用//注释掉,以免我们找到初始块时报错,影响程序运行。更改后不要忘记保存所有文件。
下图vSeeds指示的torrent文件的位置,我们还没有torrent文件的域名,所以先不要更改。
挖掘创世区块
现在我们挖掘,打开 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
如果我们上一篇文章中的环境已经完全安装好了,应该是几秒钟就可以通过了。然后我们运行我们的程序
cd src/qt
sudo ./newcoin-qt
然后程序会告诉我们把文件目录放在哪里,使用默认设置即可。这时候程序可能运行一段时间就崩溃了。没关系,我们用
tail ~/.newcoin/debug.log
转到调试文件。看看我们是否导出以下值
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填充到刚才的block map中,即uint256("0x001"),把001改成我们之前得到的hashGenesisBlock值,将其填入我们已注释掉的断言中,然后删除该注释。同样,将上述日志中block.nTime和block.nNonce的值填回CMainParams的genesis.nTime和genesis.nNonce。它们位于下面的代码行之上。
hashGenesisBlock = genesis.GetHash();
节省。既然我们已经拿到了我们的初始区块,别忘了删除我们刚刚在main.cpp中添加的代码,这样我们就已经完全构建了一套属于我们的电子货币系统。并且不会出现像比特币一样不能开采的情况。(毕竟是我们自己的,想挖多少挖多少就挖多少。哈哈哈)
也可以将上述程序运行两次,将得到的哈希值和参数填入Testnet和Regtest。
接下来我们回到newcoin文件夹,重新编译,删除原文件目录(很重要)
cd ..
sudo make
rm -rf ~/.newcoin
然后运行它。如果一切顺利,程序就会运行起来,然后我们就可以得到如下程序
不要羡慕上面的数值,既然所有的参数都是我们自己改的,当然我们可以修改main.cpp中的区块数据,从而在短时间内挖到最多的币。
写于 2016 年 4 月 14 日 bysun
随意分享!