风一样的回忆

新浪微薄腾讯微薄

最新碎语:从未遇见一位没亏过钱的富人,却遇见许多从未亏掉一毛钱的穷人

您的位置:风一样的回忆 >钱包wallet> [原创]打造自己的山寨币系统(二)

[原创]打造自己的山寨币系统(二)

上次我们把比特币中的所有文件名及内容都改成了我们的新币newcoin。但是这还远远不够。
why? 因为所有的内核参数还是比特币的,所以即使运行了客户端,也会同步之前的比特币数据。
现在是时候进入代码的内部,探寻比特币的奥秘,并做一些真正属于我们的改动。

修改区块链参数

首先我们需要进入chainparams.cpp

cd /opt/src/newcoin/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表示的种子文件的位置,我们还没有种子文件的域名,可以先注释掉。

        // vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be"));
        // vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me"));
        // vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org"));
        // vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com"));
        // vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org"));
         base58Prefixes[PUBKEY_ADDRESS] = list_of(0);
        base58Prefixes[SCRIPT_ADDRESS] = list_of(5);
        base58Prefixes[SECRET_KEY] =     list_of(128);
        base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x88)(0xB2)(0x1E);
        base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x88)(0xAD)(0xE4);

        // convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main));

注意有几处相同的上述内容都要注释

修改奖励机制

修改挖矿奖励的成熟时间  main.h 中改成14

/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
static const int COINBASE_MATURITY = 14;

修改交易确认块数推荐值 位置:/opt/src/newcoin/src/qt/transactionrecord.h

/** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has
    multiple outputs.
 */
class TransactionRecord
{
public:
    enum Type
    {
        Other,
        Generated,
        SendToAddress,
        SendToOther,
        RecvWithAddress,
        RecvFromOther,
        SendToSelf
    };

    /** Number of confirmation recommended for accepting a transaction */
    static const int RecommendedNumConfirmations = 2;

修改难度配置:位置:/opt/src/newcoin/src/chainparams.cpp ,将原来的1值改成32

bnProofOfWorkLimit=~uint256(0) >> 32;

添加一个每个块的奖励个数

找到  nSubsidyHalvingInterval = 210000; 这行上面添加 nGenesisSubsidy = 100; 
还需要修改 txNew.vout[0].nValue = nGenesisSubsidy * COIN;[大概141行]
继续修改 chainparams.h 添加GenesisSubsidy的定义,找到49行添加
 int GenesisSubsidy() const { return nGenesisSubsidy; }
 找到91行 添加下面代码:
 int nGenesisSubsidy;
 继续修改 main.cpp ,找到1238行:修改成下面代码
 CAmount nSubsidy = Params().GenesisSubsidy()* COIN;

难度调节周期  

nTargetTimespan = 60 * 60; // re-targeting every one hour, 60 blocks
nTargetSpacing = 1 * 60;  // expect 1 block/minute

挖取创始块

现在我们开挖,打开main.cpp

sudo gedit main.cpp

我们在这一行后面

CBlock &block = const_cast<CBlock&>(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

进入到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();

保存。现在我们已经得到了我们的初始块,别忘了将main.cpp中我们刚才填加的代码删掉,这样我们就完全构建出了一套属于我们的电子币系统。并且不会出现像比特币那样挖不着的情况。(毕竟是我们自己的,想挖多少就挖多少。哈哈哈)

你也可以将上面的程序额外运行两次,并把得到的hash值和各参数填入到Testnet和Regtest中去。

下面我们返回newcoin文件夹中,重新编译,并删除原来的文件目录(非常重要)

cd ..
sudo make
rm -rf ~/.newcoin

然后运行起来。如果一切顺利的话,程序会运行起来,然后我们就可以得到下面的程序

---

转载请注明本文标题和链接:《[原创]打造自己的山寨币系统(二)

分享到:

发表评论

路人甲 表情
看不清楚?点图切换 Ctrl+Enter快速提交