フォークコインを作るときに、ジェネシスブロックのハッシュ値をマイニングする


以前の記事が自分の勘違いで一切マイニングをしないコードになっていたため、きちんとマイニングするように修正しました。

genesisのpszTimestampやnTime、を書き換えると、起動時にこんな感じのエラーが出る。

coind: chainparams.cpp:152: CMainParams::CMainParams(): Assertion `consensus.hashGenesisBlock == uint256S("00000…0000")' failed

原因はsrc/chainparams.cppのここ

genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1e0ffff0, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
assert(consensus.hashGenesisBlock == uint256S("0x0000…f"));
assert(genesis.hashMerkleRoot == uint256S("0x12345…f"));

もちろんジェネシスブロックのハッシュが変わってるのでassertで落ちてる。
ファイルの頭あたりにあるCreateGenesisBlockの中で力技でマイニングさせるようにする。

差分はこんな感じ。

ヘッダーにarith_uint256.hを追加
  #include "chainparams.h"
  #include "consensus/merkle.h"
+ #include "arith_uint256.h"

  #include "tinyformat.h"
  #include "util.h"
マイニングするコードを追加
static CBlock CreateGenesisBlock(const CScript& pszTimestamp, const CScript& genesisOutputScript, …enesisReward)
{
    CMutableTransaction txNew;
    txNew.nVersion = 1;
    txNew.vin.resize(1);
    txNew.vout.resize(1);
    txNew.vin[0].scriptSig = …………
    txNew.vout[0].nValue = genesisReward;
    txNew.vout[0].scriptPubKey = genesisOutputScript;

    CBlock genesis;
    genesis.nTime    = nTime;
    genesis.nBits    = nBits;
    genesis.nNonce   = nNonce;
    genesis.nVersion = nVersion;

    genesis.vtx.push_back(MakeTransactionRef(std::move(txNew)));
    genesis.hashPrevBlock.SetNull();
    genesis.hashMerkleRoot = BlockMerkleRoot(genesis);
+
+    arith_uint256 hashTarget = arith_uint256().SetCompact(genesis.nBits);
+    std::cout << hashTarget.ToString() << '\n';
+    while (UintToArith256(genesis.GetHash()) > hashTarget) ++genesis.nNonce;
+
     return genesis;
 }

で、これでマイニングが成功すると、動作が帰ってくる。
そのときにnNonceを表示するため、genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1e0ffff0, 1, 50 * COIN);の下に以下のコードを挿入する。

std::cout << "genesis.nTime = " << genesis.nTime << '\n';
std::cout << "genesis.nBits = " << genesis.nBits << '\n';
std::cout << "genesis.nNonce = " << genesis.nNonce << '\n';
std::cout << "genesis.GetHash = " << genesis.GetHash().ToString() << '\n';

これで、coind起動時にマイニングが起動、ジェネシスブロックをマイニングしてそのnNonceを吐き出すようになる。その値をassertに突っ込めば良い。

ちなみに、今回のnBitsである0x1e0ffff0はモナコインから流用した。難易度的にはものすごく簡単なため数秒でマイニングに成功する。