【比特币】自己动手制作山寨币

源代码地址:

https://github.com/imharrywu/fastcoin

构建问题可以参考这个[BGOLD](https://github.com/bitbaba/bitgold)的travis.sh

程序猿朋友可以自己动手编译生成安装包,有问题可以直接加群讨论 161928517(注明:csdn),也欢迎程序猿朋友PullRequest给我,只有知识共享才能促进比特币的繁荣。


可以支持任何算法(sha256,scrypt,x11,x13,nist,grostel,以及这些算法的串联)和参数定制。


目前预先内置了比特币的SHA256莱特币的scypt,以及SHA3-256(KECCAK)


在线编译目前提供三种安装包:

1,linux/unix的daemon程序(带钱包功能)

2,Mac钱包安装包 

3,windows钱包安装包


1、  截图预览

(1) 安装图1

【比特币】自己动手制作山寨币

(2)安装图2

【比特币】自己动手制作山寨币

(3)安装图3

【比特币】自己动手制作山寨币

(4)安装图4

【比特币】自己动手制作山寨币

(5)安装图5

【比特币】自己动手制作山寨币


(6)概览图 已经挖到3个block 奖励了300个FTC

【比特币】自己动手制作山寨币

(7)交易记录图

【比特币】自己动手制作山寨币

(8)点击显示交易细节 显示为挖矿所得 并且还没有确认

【比特币】自己动手制作山寨币

(9)版权页

【比特币】自己动手制作山寨币

(10)调试窗口

【比特币】自己动手制作山寨币


(11)显示已经连接的p2p网络节点 一个在虚拟机里面运行的节点

【比特币】自己动手制作山寨币


(12)2个节点构成的p2p通信网络

【比特币】自己动手制作山寨币


2、 山寨币修改步骤:

(1)迁出最新的比特币源代码

比特币官方代码: https://github.com/bitcoin/bitcoin

山寨币代码地址(紧跟bitcoin更新):https://github.com/imharrywu/fastcoin

git clone https://github.com/imharrywu/fastcoin 


一下修改都是一些代码片段,请用eclipse打开迁出的代码,对照查看。


(2)修改创世块

源文件 chainparams.cpp

[cpp] view plain copy
  1. /** 
  2.  * Build the genesis block. Note that the output of the genesis coinbase cannot 
  3.  * be spent as it did not originally exist in the database. 
  4.  *  
  5.  * CBlock(hash=000000000019d6, ver=1, hashPrevBlock=00000000000000, hashMerkleRoot=4a5e1e, nTime=1231006505, nBits=1d00ffff, nNonce=2083236893, vtx=1) 
  6.  *   CTransaction(hash=4a5e1e, ver=1, vin.size=1, vout.size=1, nLockTime=0) 
  7.  *     CTxIn(COutPoint(000000, -1), coinbase 04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73) 
  8.  *     CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B) 
  9.  *   vMerkleTree: 4a5e1e 
  10.  */  
  11.   
  12. // HarryWu, generate genesis block by genesis.py as following:  
  13. //  
  14. // localhost genesis # python genesis.py \  
  15. //                            -t $(date +%s) \  
  16. //                            -z "shanghai stock index closed at 2343.57, on 24th Sept., 2014" \  
  17. //                            -a SHA256 \  
  18. //                            -p 049e02fa9aa3c19a3b112a58bab503c5caf797972f5cfe1006275aa5485a01b48f9f648bc5380ee1e82dc6f474c8e0f7e2f6bbd0de9355f92496e3ea327ccb19cc \  
  19. //                            -v 10000000000  
  20. // Raw block data: 04ffff001d01043b7368616e676861692073746f636b20696e64657820636c6f73656420617420323334332e35372c206f6e203234746820536570742e2c2032303134  
  21. // algorithm: SHA256  
  22. // merkle hash: 1c395aad7fab156523a095a869d3fcdf3249a8a97c8d7337adb4f33d826da32b  
  23. // pszTimestamp: shanghai stock index closed at 2343.57, on 24th Sept., 2014  
  24. // pubkey: 049e02fa9aa3c19a3b112a58bab503c5caf797972f5cfe1006275aa5485a01b48f9f648bc5380ee1e82dc6f474c8e0f7e2f6bbd0de9355f92496e3ea327ccb19cc  
  25. // time: 1411650667  
  26. // bits: 0x1d00ffff  
  27. // Searching for genesis hash..  
  28. //  
  29. // nonce: 1456993276  
  30. // genesis hash: 000000004df0288b461e17d9a20e557fd296861c604f1944eb9e2cca866af0a5  
  31.   
  32. const char* pszTimestamp = "shanghai stock index closed at 2343.57, on 24th Sept., 2014";  
  33. CMutableTransaction txNew;  
  34. txNew.vin.resize(1);  
  35. txNew.vout.resize(1);  
  36. txNew.vin[0].scriptSig = CScript() << 0x1d00ffff << CScriptNum(4) << vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));  
  37. txNew.vout[0].nValue = nGenesisSubsidy * COIN;  
  38. txNew.vout[0].scriptPubKey = CScript() << ParseHex("049e02fa9aa3c19a3b112a58bab503c5caf797972f5cfe1006275aa5485a01b48f9f648bc5380ee1e82dc6f474c8e0f7e2f6bbd0de9355f92496e3ea327ccb19cc") << OP_CHECKSIG;  
  39. genesis.vtx.push_back(txNew);  
  40. genesis.hashPrevBlock = 0;  
  41. genesis.hashMerkleRoot = genesis.BuildMerkleTree();  
  42. genesis.nVersion = 1;  
  43. genesis.nTime    = 1411666331;  
  44. genesis.nBits    = 0x1d00ffff;  
  45. genesis.nNonce   = 2056985438;  
  46.   
  47. hashGenesisBlock = genesis.GetHash();  
  48. assert(hashGenesisBlock == uint256("0x0000000061b1aca334b059920fed7bace2336ea4d23d63428c7aee04da49e942"));  
  49. assert(genesis.hashMerkleRoot == uint256("0x7bf229f629a6666596c1ce57117c28d1d29299e8a5303347929bd70847c49adb"));  


(3)修改网络协议魔数

源文件 chainparams.cpp

[cpp] view plain copy
  1. class CMainParams : public CChainParams {  
  2. public:  
  3.     CMainParams() {  
  4.         networkID = CBaseChainParams::MAIN;  
  5.         strNetworkID = "main";  
  6.         /**  
  7.          * The message start string is designed to be unlikely to occur in normal data. 
  8.          * The characters are rarely used upper ASCII, not valid as UTF-8, and produce 
  9.          * a large 4-byte int at any alignment. 
  10.          */  
  11.         pchMessageStart[0] = 0x90;  
  12.         pchMessageStart[1] = 0x0d;  
  13.         pchMessageStart[2] = 0xf0;  
  14.         pchMessageStart[3] = 0x0d;  

0xgoodcafe(好咖啡的意思),大家可以自己选择,但是也有一些基本建议,看上面那个英文注释就好了,就是和某些常用的字符集可用字段不要冲突。

另外:对应的修改TESTNET和REGTESTNET的参数


(4)修改地址前缀

源文件 chainparams.cpp

[cpp] view plain copy
  1. base58Prefixes[PUBKEY_ADDRESS] = list_of(35); // F prefix  
  2. base58Prefixes[SCRIPT_ADDRESS] = list_of(65); // T prefix  
  3. base58Prefixes[SECRET_KEY] =     list_of(45); // 7 prefix  
  4. base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x88)(0xEE)(0x35);  
  5. base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x88)(0xEE)(0x45);  

有一个wiki的对照表可以用来悬在公钥和脚本地址的前缀,但是这个表不使用私钥等(因为长度不一样,规律不一样)。


(5)修改网络端口

源文件 chainparams.cpp

[cpp] view plain copy
  1. class CMainParams : public CChainParams {  
  2. public:  
  3.     CMainParams() {  
  4.         networkID = CBaseChainParams::MAIN;  
  5.         strNetworkID = "main";  
  6.         /**  
  7.          * The message start string is designed to be unlikely to occur in normal data. 
  8.          * The characters are rarely used upper ASCII, not valid as UTF-8, and produce 
  9.          * a large 4-byte int at any alignment. 
  10.          */  
  11.         pchMessageStart[0] = 0x90;  
  12.         pchMessageStart[1] = 0x0d;  
  13.         pchMessageStart[2] = 0xf0;  
  14.         pchMessageStart[3] = 0x0d;  
  15.         vAlertPubKey = ParseHex("04e01590abdc5967eb550413fcf04bbd7cead46f13579b58d52ea2f08d71a1a94196c476cd4fa60c30b51737fe3d9c8c88a04a6bec2282ebb1f22286130a153b85");  
  16.         nDefaultPort = 9999;  
  17.         bnProofOfWorkLimit = ~uint256(0) >> 32;  

修改了nDefaultPort=9999,比特币默认是8333

另外同时修改一下TESTNET和REGTESTNET的端口配置,一般加10000和20000即可

[cpp] view plain copy
  1. /** 
  2.  * Testnet (v3) 
  3.  */  
  4. class CTestNetParams : public CMainParams {  
  5. public:  
  6.     CTestNetParams() {  
  7.         networkID = CBaseChainParams::TESTNET;  
  8.         strNetworkID = "test";  
  9.         pchMessageStart[0] = 0xC0;  
  10.         pchMessageStart[1] = 0x1d;  
  11.         pchMessageStart[2] = 0xf0;  
  12.         pchMessageStart[3] = 0x0d;  
  13.         vAlertPubKey = ParseHex("045d2d29beffb0a0cbea44f266286ff8b1d11c035538fbb4dadcf6b4073b08f318afea74f01d5a3782e72a22273fb01ab40e99d93adff488236585cc8031323e7c");  
  14.         nDefaultPort = 19999;  

[cpp] view plain copy
  1. /** 
  2.  * Regression test 
  3.  */  
  4. class CRegTestParams : public CTestNetParams {  
  5. public:  
  6.     CRegTestParams() {  
  7.         networkID = CBaseChainParams::REGTEST;  
  8.         strNetworkID = "regtest";  
  9.         pchMessageStart[0] = 0x0b;  
  10.         pchMessageStart[1] = 0xad;  
  11.         pchMessageStart[2] = 0xf0;  
  12.         pchMessageStart[3] = 0x0d;  
  13.         nDefaultPort = 29999;  
  14.         bnProofOfWorkLimit = ~uint256(0) >> 1;  


(6)修改种子网络连接参数

源文件 chainparams.cpp

[cpp] view plain copy
  1. //vSeeds.push_back(CDNSSeedData("bitcoin.sipa.be", "seed.bitcoin.sipa.be"));  
  2. //vSeeds.push_back(CDNSSeedData("bluematt.me", "dnsseed.bluematt.me"));  
  3. //vSeeds.push_back(CDNSSeedData("dashjr.org", "dnsseed.bitcoin.dashjr.org"));  
  4. //vSeeds.push_back(CDNSSeedData("bitcoinstats.com", "seed.bitcoinstats.com"));  
  5. //vSeeds.push_back(CDNSSeedData("bitnodes.io", "seed.bitnodes.io"));  
  6. //vSeeds.push_back(CDNSSeedData("xf2.org", "bitseed.xf2.org"));  
  7.   
  8. base58Prefixes[PUBKEY_ADDRESS] = list_of(35); // F prefix  
  9. base58Prefixes[SCRIPT_ADDRESS] = list_of(65); // T prefix  
  10. base58Prefixes[SECRET_KEY] =     list_of(45); // 7 prefix  
  11. base58Prefixes[EXT_PUBLIC_KEY] = list_of(0x04)(0x88)(0xEE)(0x35);  
  12. base58Prefixes[EXT_SECRET_KEY] = list_of(0x04)(0x88)(0xEE)(0x45);  
  13.   
  14. //convertSeed6(vFixedSeeds, pnSeed6_main, ARRAYLEN(pnSeed6_main));  


如果你有7x24在线的服务器运行节点,那么请在这里加入他们的地址,可以是dns也可以是ip地址(v4,v6,--enable-ipv6)。

如果没有的话,可以考虑和我一样暂时注释掉,在运行时候指定连接参数-addnoe=123.123.123.123 或者-dns -addnode=mynode.domain.com

对应的修改一下TESTNET和REGTESTNET的网络节点地址。

(7)修改工作量机制

源文件 miner.cpp

比特币在函数ScanHash()里面搜索随机数,

[cpp] view plain copy
  1. //  
  2. // ScanHash scans nonces looking for a hash with at least some zero bits.  
  3. // The nonce is usually preserved between calls, but periodically or if the  
  4. // nonce is 0xffff0000 or above, the block is rebuilt and nNonce starts over at  
  5. // zero.  
  6. //  
  7. bool static ScanHash(const CBlockHeader *pblock, uint32_t& nNonce, uint256 *phash)  
  8. {  
  9.     // Write the first 76 bytes of the block header to a double-SHA256 state.  
  10.     //CHash256 hasher;  
  11.     //CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);  
  12.     //ss << *pblock;  
  13.     //assert(ss.size() == 80);  
  14.     //hasher.Write((unsigned char*)&ss[0], 76);  
  15.   
  16.     while (true) {  
  17.         nNonce++;  
  18.   
  19.         // Write the last 4 bytes of the block header (the nonce) to a copy of  
  20.         // the double-SHA256 state, and compute the result.  
  21.         //CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);  
  22.   
  23.         *phash = pblock->ComputePowHash(nNonce);  
  24.   
  25.         // Return the nonce if the hash has at least some zero bits,  
  26.         // caller will check if it has enough to reach the target  
  27.         if (((uint16_t*)phash)[15] == 0)  
  28.             return true;  
  29.   
  30.         // If nothing found after trying for a while, return -1  
  31.         if ((nNonce & 0xffff) == 0)  
  32.             return false;  
  33.         if ((nNonce & 0xfff) == 0)  
  34.             boost::this_thread::interruption_point();  
  35.     }  
  36. }  


在函数BitcoinMiner()里面创建新的block,设定时间戳(扰动1),获取mempool里面的最新交易(扰动2),调用ScanHash()搜索随机数(扰动3),直到找到满足条件的hash。

另外比特币的工作量证明的hash同时用作这个block的索引,litecoin里面这2个概念是区分的对待的(sha256的hash作为索引,scrypt出来的pow hash作为工作量证明)。

注意:设置独立挖矿的条件(chainparams.cpp里面设置)

[cpp] view plain copy
  1. fMiningRequiresPeers = !true// See BitcoinMiner() for details.  

挖矿代码:

[cpp] view plain copy
  1. void static BitcoinMiner(CWallet *pwallet)  
  2. {  
  3.     LogPrintf("FastCoinMiner started\n");  
  4.     SetThreadPriority(THREAD_PRIORITY_LOWEST);  
  5.     RenameThread("fastcoin-miner");  
  6.   
  7.     // Each thread has its own key and counter  
  8.     CReserveKey reservekey(pwallet);  
  9.     unsigned int nExtraNonce = 0;  
  10.   
  11.     try {  
  12.         while (true) {  
  13.             if (Params().MiningRequiresPeers()) {  
  14.                 // Busy-wait for the network to come online so we don't waste time mining  
  15.                 // on an obsolete chain. In regtest mode we expect to fly solo.  
  16.                 while (vNodes.empty())  
  17.                     MilliSleep(1000);  
  18.             }  
  19.   
  20.             //  
  21.             // Create new block  
  22.             //  
  23.             unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();  
  24.             CBlockIndex* pindexPrev = chainActive.Tip();  
  25.   
  26.             auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlockWithKey(reservekey));  
  27.             if (!pblocktemplate.get())  
  28.             {  
  29.                 LogPrintf("Error in FastCoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");  
  30.                 return;  
  31.             }  
  32.             CBlock *pblock = &pblocktemplate->block;  
  33.             IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);  
  34.   
  35.             LogPrintf("Running FastCoinMiner with %u transactions in block (%u bytes)\n", pblock->vtx.size(),  
  36.                 ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));  

博主稍作修改,设置了几个预置的hash算法(sha256,scrypt,keccak(即SHA3)),可以通过block的版本号区分,那么在scanhash里面调用ComputePowHash的时候,可以选择不同的pow算法,甚至你可以把这些算法串联起来,以增加算法被**的方攻击性。

看代码吧:

[cpp] view plain copy
  1. uint256 CBlockHeader::ComputePowHash(uint32_t nNonce) const  
  2. {  
  3.     if (nVersion == 1 || nVersion == 2){  
  4.         /** 
  5.          * Use SHA256+SHA256 to make PoW 
  6.          */  
  7.         // Write the first 76 bytes of the block header to a double-SHA256 state.  
  8.         CDoubleSHA256Pow hasher; // TODO: Create a new PowHasher named CPowHash256  
  9.         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);  
  10.         ss << *this;  
  11.         assert(ss.size() == 80);  
  12.         hasher.Write((unsigned char*)&ss[0], 76);  
  13.         uint256 powHash;  
  14.         CDoubleSHA256Pow(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)&powHash);  
  15.         return powHash;  
  16.     }else if (nVersion == 3){  
  17.         /** 
  18.          * Scrypt PoW 
  19.          */  
  20.         CScryptHash256Pow hasher;  
  21.         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);  
  22.         ss << *this;  
  23.         assert(ss.size() == 80);  
  24.         hasher.Write((unsigned char*)&ss[0], 76);  
  25.         uint256 powHash;  
  26.         CScryptHash256Pow(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)&powHash);  
  27.         return powHash;  
  28.     }else if (nVersion == 4){  
  29.         /** 
  30.          *  Scrypt+SHA256 PoW 
  31.          */  
  32.     }else if (nVersion == 5){  
  33.         /** 
  34.          * Keccak(1088,512,256) or Known as SHA3-256(fips202draft) Pow 
  35.          */  
  36.         CKeccak_256 hasher;  
  37.         CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);  
  38.         ss << *this;  
  39.         assert(ss.size() == 80);  
  40.         hasher.Write((unsigned char*)&ss[0], 76);  
  41.         uint256 powHash;  
  42.         CKeccak_256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)&powHash);  
  43.         return powHash;  
  44.     }else{  
  45.         // Abort, unknown block version.  
  46.         assert(false);  
  47.         return ~(uint256)0;  
  48.     }  
  49. }  


(8)修改奖励机制

参考9.3

8.1) 修改挖矿奖励的成熟时间

源代码:main.h

[cpp] view plain copy
  1. /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */  
  2. static const int COINBASE_MATURITY = 14;  


8.2) 修改交易确认块数推荐值

源代码 qt/transactionrecord.h

[cpp] view plain copy
  1. /** UI model for a transaction. A core transaction can be represented by multiple UI transactions if it has 
  2.     multiple outputs. 
  3.  */  
  4. class TransactionRecord  
  5. {  
  6. public:  
  7.     enum Type  
  8.     {  
  9.         Other,  
  10.         Generated,  
  11.         SendToAddress,  
  12.         SendToOther,  
  13.         RecvWithAddress,  
  14.         RecvFromOther,  
  15.         SendToSelf  
  16.     };  
  17.   
  18.     /** Number of confirmation recommended for accepting a transaction */  
  19.     static const int RecommendedNumConfirmations = 2;  


(9)修改难度配置

源文件 chainparams.cpp

[cpp] view plain copy
  1. class CMainParams : public CChainParams {  
  2. public:  
  3.     CMainParams() {  
  4.         networkID = CBaseChainParams::MAIN;  
  5.         strNetworkID = "main";  
  6.         /**  
  7.          * The message start string is designed to be unlikely to occur in normal data. 
  8.          * The characters are rarely used upper ASCII, not valid as UTF-8, and produce 
  9.          * a large 4-byte int at any alignment. 
  10.          */  
  11.         pchMessageStart[0] = 0x90;  
  12.         pchMessageStart[1] = 0x0d;  
  13.         pchMessageStart[2] = 0xf0;  
  14.         pchMessageStart[3] = 0x0d;  
  15.         vAlertPubKey = ParseHex("04e01590abdc5967eb550413fcf04bbd7cead46f13579b58d52ea2f08d71a1a94196c476cd4fa60c30b51737fe3d9c8c88a04a6bec2282ebb1f22286130a153b85");  
  16.         nDefaultPort = 9999;  
  17.         bnProofOfWorkLimit = ~uint256(0) >> 32;  
  18.         nSubsidyHalvingInterval = 210000;  
  19.         nEnforceBlockUpgradeMajority = 750;  
  20.         nRejectBlockOutdatedMajority = 950;  
  21.         nToCheckBlockUpgradeMajority = 1000;  
  22.         nMinerThreads = 1; // 0 for all available cpus.  
  23.         nTargetTimespan = 60 * 60; // re-targeting every one hour  
  24.         nTargetSpacing = 1 * 60;  // do new pow every 1 minutes.  
  25.         nGenesisSubsidy = 100;  


a) bnProofOfWorkLimit=~uint256(0) >> 32;

是一个大整数(256bit)表示,前面32个位数是0,这个参数表示全网允许的最小难度,低于这个难度的block是不会被挖掘的。


b) nGenesisSubsidy = 100;

初始津贴,比特币的第一个块的奖励是50个btc。


c) nSubsidyHavlingInterval = 210000; 

这个参数决定了多少个block以后比特币的奖励(补贴,挖矿奖励)会减半。这个参数结合初始奖励(比如比特币50)基本可以估算全网总的货币产量(比如比特币的2100万),这个初始津贴也是可以配置的,如2)所示。比如比特币,一个等比数列求和公式就可以计算货币总量 50(1/(1 - 0.5))*210000=2100万btc。
上面2个参数在查询区块奖励的时候用到,请查看main.cpp 的 GetBlockValue(height, fees)找到细节

[cpp] view plain copy
  1. CAmount GetBlockValue(int nHeight, const CAmount& nFees)  
  2. {  
  3.     CAmount nSubsidy = Params().GenesisSubsidy() * COIN;  
  4.   
  5.     int halvings = nHeight / Params().SubsidyHalvingInterval();  
  6.   
  7.     // Force block reward to zero when right shift is undefined.  
  8.     if (halvings >= 64)  
  9.         return nFees;  
  10.   
  11.     // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.  
  12.     nSubsidy >>= halvings;  
  13.   
  14.     return nSubsidy + nFees;  
  15. }  
很多山寨比也是在这里修改货币分布的,比如 nHeight==1 的时候,奖励1000万个,其他块都不予奖励,这个即使预挖模式了吧。

另外,关于货币分布,这里satoshi同学可能已经考虑很多,他为什么设置到很多年以后才矿源枯竭,为什么采取递减的方式,可能都是出于保护区块链的目的(timestampserver)。

d)难度调节周期

nTargetTimespan = 60 * 60; // re-targeting every one hour, 60 blocks
nTargetSpacing = 1 * 60;  // expect 1 block/minute
这里的设置是60分钟(3600秒, 因为预期60秒钟1个block,那么就是60个blocks计算新难度,否则使用上一个block的难度),重新评估难度,下一个块的挖掘可能就要使用新的难度设置了。

比特币的调节周期是 2周/每10分钟,也就是 2 * 7 * 24 * 6 = 2016

参考:http://bitcoindifficulty.com/blog/

https://en.bitcoin.it/wiki/Difficulty

(10) 修改checkpoints检查


(11) 修改界面


github地址


TODO:

1)模板化的山寨币生成,可配置修改部分通过宏或者变量提取出来,用脚本批量替换修改。

2)矿池搭建与节点测试 P2pool  &Poclbm

3)移动支付和网页支付

4)应用生态

5)交易备注

6)复杂交易应用(脚本,非标准交易)


备注:

1)记得加上-checkpoints=0 参数启动,否则,会导致daemon报错,“FastCoin is downloading blocks...”