分享

更多

   

比特币山寨币有多好做?看这篇文章的长度就行 | Tiny Calf

2018-03-27  三郞


发表于  
实话这篇文章发的有点晚了。直接接触一下代码可能可以从另一个角度去理解比特币的原理,顺便我们还可以创造一下自己的altcoin。

创世块相关

Timestamp

这里的timestamp就是一句随机的话,表明创建创世块创建的时候发生的某个时间,这句话会被一并加入创世块的哈系算法中。其实只是一个象征意义,在代码里能找到创世块的原文,在Bitcore src/chainparams.cppCreateGenesisBlock函数中,原文如下:

const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";

nTime nNonce nBit

nTime这个才是我们通常说的linux时间戳,是创世块开采时候的时间,比特核心代码中为1231006505。我们知道比特币挖矿的原理是寻找某个随机数加上一个固定的算法所得出的值的哈系值,如果前n多位是0,那么就可以算是一个新的区块。挖矿就是寻找这个随机数的过程。n越多,难度久越大,这里的nBit其实就代表了创世块的难度,代码中为0x1d00ffff,而真正生成创世块的随机数就是这个nNounce,代码中为2083236893。这三个参数在代码中直接以函数的参数的形式出现,也在src/chainparams.cpp中:

genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);

这里的50 * COIN其实没什么用,因为创世块的币是没法用的。每个块的奖励其实不在这里设置,后面再讲。

生成创世块

创世块需要两个参数,一个是创世块的hash值hashGenesisBlock,一个是创世块的hashMerkleRoot 。区块链是树状的,需要merkleroot来建立块与块之间的联系。生成创世块我们就需要以上说的 Timestamp,nTime,nBit ,按照指定算法挖矿,得出nNounce,hashMerkleRoot,hashMerkleRoot。有一个python能完成生成创世块的工作,点击这个传送门
得到nNounce,hashMerkleRoot,hashMerkleRoot以后,nNounce还是填入之前的函数参数中,hashMerkleRoot,hashMerkleRoot分别可以在以下代码中找到:

assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));

共识机制相关

SubsidyHalvingInterval

这个是减半周期,我们了解比特币4年减半,但是这里的减半周期单位是块,也就是每过210000个块比特币的产出减半。后面我还会回来说为什么是4年。代码是这样的:

// 位置  /src/chainparams.cpp
consensus.nSubsidyHalvingInterval = 210000;

PowTargetSpacing PowTargetSpacing

PowTargetSpacing是目标难度变更时间,源码为2周。PowTargetSpacing是目标出块时间代码中为10分钟。这两个参数相除,就是难度变化周期2016(单位:块)。总结来说,就是每隔2016个块,挖矿难度会重新定义,以此来动态平衡出块时间。举个实际的例子:在前难度周期中,由于矿工算力过大,没有像预期的一样每十分钟出一个块,那么在下一个难度周期中,会按照上一个周期的算力,增加合适的难度,来保证下一个周期中每个块的出块时间大约是十分钟。那么其实我们的初始难度设置低一点也没有太大影响,最终都会按PowTargetSpacing来决定难度。另外,结合上面的减半周期210000和每十分钟出一个块,我们就得出了4年减半的结论。
这两个参数的源码如下:

// 位置  /src/chainparams.cpp
consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 10 * 60;

Subsidy

这个就是挖矿的初始奖励。代码中为50,结合减半周期,每个周期内的的产出为 50 × 2100000,所以总产出为 50 × 2100000 ×(1 + 1/2 + 1/4 + 1/16 + ...),积分一下,结果就是2100万。

//位置  /src/main.cpp
CAmount nSubsidy = 50 * COIN;

其他非重要参数

// 位置  /src/chainparams.cpp
pchMessageStart[0] = 0xf9;
pchMessageStart[1] = 0xbe;
pchMessageStart[2] = 0xb4;
pchMessageStart[3] = 0xd9;

这个是网络消息头,用来合其他比特币altcoin区分,随便改其他数字就行

// 位置  /src/chainparams.cpp
vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be", true)); // Pieter Wuille, only supports x1, x5, x9, and xd
vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me", true)); // Matt Corallo, only supports x9
vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org")); // Luke Dashjr
vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com", true)); // Christian Decker, supports x1 - xf
vSeeds.push_back(CDNSSeedData("bitcoin.jonasschnelli.ch", "seed.bitcoin.jonasschnelli.ch", true)); // Jonas Schnelli, only supports x1, x5, x9, and xd

这个是比特币的初始固定节点,开启比特币时会自动连接,如果你的altcoin一开始没有的话全部注释就行

// 位置  /src/chainparams.cpp
base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
base58Prefixes[SECRET_KEY] =     std::vector<unsigned char>(1,128);

这三个参数会影响地址生成的校验位,以区分不同的币种,如果你要做altcoin的最好还是要改。

// 位置  /src/chainparams.cpp
checkpointData = (CCheckpointData) {
    {
        { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
        { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
        { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
        {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
        {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
        {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
        {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
        {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
        {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
        {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
        {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
        {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
        {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
    }
};

这个是校验区块链上的固定块是否正确,同样,需要altcoin的话这里注释掉

// 位置 src/util.cpp
#ifdef WIN32
    // Windows
    return GetSpecialFolderPath(CSIDL_APPDATA) / DATA_FILE_NAME;
#else
    fs::path pathRet;
    char* pszHome = getenv("HOME");
    if (pszHome == NULL || strlen(pszHome) == 0)
        pathRet = fs::path("/");
    else
        pathRet = fs::path(pszHome);
#ifdef MAC_OSX
    // Mac
    pathRet /= "Library/Application Support";
    TryCreateDirectory(pathRet);
    return pathRet / DATA_FILE_NAME;
#else
    // Unix
    return pathRet / DATA_FILE_NAME_UNIX;
#endif

这里直接把DATA_FILE_NAME和DATA_FILE_NAME_UNIX换成altcoin名字就行,是默认文件夹名称。

完成

所以按照整篇文章说的,改掉一些数据,就能很容易自己编译自己的altcoin了,具体编译流程可以参照我以前的比特币文章。 但是毕竟,这个技术没什么卵用,自己玩玩就好。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。如发现有害或侵权内容,请点击这里 或 拨打24小时举报电话:4000070609 与我们联系。

    猜你喜欢

    0条评论

    发表

    类似文章 更多
    喜欢该文的人也喜欢 更多