主页 > imtoken官方app > 从原理到例子,他用区块链技术做了一个COIN客户端
从原理到例子,他用区块链技术做了一个COIN客户端
本文来自作者李佳在GitChat上的分享《手动制作自己的COIN客户端:区块链核心代码解读》
基础和设计
2008年初,中本聪团队发表了一篇名为《比特币:一种点对点电子现金系统》的学术论文。之所以选择在金融危机之年出版,或许并没有什么深意。他认为,传统货币最根本的问题是信任。银行必须让人们相信它可以帮助我们管理我们的资金,但它是在用金钱制造信贷泡沫,而通货膨胀会使人们的财富缩水。
首先,中本聪将比特币定义为一个点对点的电子现金系统,目的很明确:希望这个系统不依赖于任何中心,比如中央银行,所以这个系统必须是分布式系统。
区块链的概念最早是在中本聪设计比特币系统时提出的,也是区块链技术实施和使用最成功的时候。比特币是一个商业场景,而区块链是实现这个商业场景的技术基础。要了解区块链,我们先来看看下图所示的区块链项目的基本运行机制。
去中心化的重要性
主要是为了安全和信任,互联网从一开始到现在的集群服务模式无非是业务逻辑的需要和数据的可靠性,所以安全和信任是最重要的。之前的模式都是基于B/S或者C/S,比如微信支付。当用户A向用户B付款时,其实是A发起请求,然后微信支付系统网关确认,然后将A的钱转到B的账户。
在此期间,如果微信支付网关服务器出现问题,所有用户都会受到影响。一旦被黑客攻击,数据很容易被修改;在分布式网络中,可以理解为一种CDN机制,比如Nginx做数据缓存,当有100个CDN时,如果中间的部分服务器丢失数据或者被黑客攻击,不会影响到服务整个网络,因为中心有调度机制,可以快速切换到节点上新的或者可靠的CDN。
在分布式系统中,世界上的每个节点既是客户端又是服务器,除非有超过 50.1% 的节点同时被篡改。如果超过这个值,说明调度系统无法正常分析出哪个是真正的服务器。因此,在去中心化机制中,所有数据都是透明的,不属于任何中心服务器或客户端。每个人都是节点上的贡献者和维护者。
可能有人会问,服务器上的数据本来我们是看不到的,现在所有的数据都安装在本地了,是不是说明客户端已经有数据了,是不是比较不安全呢,其实是的,不过这也是一个区块链项目的属性,所有数据都是加密的。
重要概念
接下来,我们看一下区块链中的重要概念。
P2P 协议
P2P是一种分布式网络,网络的参与者共享自己拥有的部分硬件资源(处理能力、存储能力、网络连接能力)。Peer) 直接,无需通过中间实体。该网络的参与者既是资源(服务和内容)提供者(服务器),又是资源(服务和内容)获取者(客户)。
它有两个特点,一是没有中心服务器,二是用户之间相互连接,共享文件或通讯。
共识机制
共识机制是如何在所有记账节点之间达成共识来选择和确定记录的真实性和有效性。最长的区块链是全网公认的,因为它上面的工作量最大。如果要修改一个区块中的交易信息,则必须修改该区块以及所有后续区块的信息。这种共识机制不仅可以作为身份识别的手段,还可以避免虚假交易和信息篡改。
智能合约
智能合约主要基于区块链系统中可信且不可变的数据,自动执行一些预先定义好的规则和条款,例如自动记录新区块。方便、快捷、智能。
非对称加密
非对称加密,即在加密和解密过程中使用“密钥对”。“密钥对”中的两个密钥具有非对称特性,即在信息传输过程中,发送方的密钥对信息进行加密,而接收方收到信息后,只能通过另一对配对密钥来解密信息.
非对称加密使任何参与者更容易达成共识,最大限度地减少价值交换中的摩擦边界,并且在透明数据后也实现匿名,保护个人隐私。
采矿基础
在区块链网络中,数据以文件的形式永久记录,我们称之为块。区块是一些或所有最新比特币交易的一组记录,这些交易尚未被其他先前的区块记录。一个区块可以被认为是城市记录员记录簿(房地产所有权变更记录)或证券交易所总账中的单页。
在绝大多数情况下,新区块被添加到记录的末尾(以比特币的名义:区块链),并且一旦写入,就永远无法更改或删除。每个块记录在它创建之前发生的所有事件。
块结构如下图所示。
每个区块包括一些或所有最近的交易、对前一个区块的引用以及其他数据。它还包括挖矿难度的答案——这个答案对每个区块都是唯一的。如果没有正确的答案,新块就不能发送到网络——“挖掘”的过程本质上是“解决”当前块的竞赛。每个区块中的数学问题很难解决,但一旦找到有效的解决方案,其他网络节点就很容易验证解决方案的正确性。一个给定的块可能有多个有效解,但对于要求解的区域的块,只需要一个解。
因为每解决一个区块,都会获得一个新生成的比特币奖励,并且每个区块都包含一条记录,而记录中的比特币地址就是有权获得比特币奖励的地址。这条记录被称为生产交易或 Coinbase 交易,它通常是每个区块的第一笔交易。每个区块产生的比特币数量为 50,每 210,000 个区块(约 4 年)减半。
发送者在网络上广播比特币交易,所有试图解决区块的矿工节点收集这些交易的记录,并将它们添加到矿工节点正在解决的区块中。
挖矿难度由比特币网络自动调整,以达到平均每小时解决 6 个区块的目标。每 2016 个区块(约两周)后,所有客户端将实际新区块数量与目标数量进行比较,并根据差异的百分比调整目标哈希值,以增加(或减少)出块难度。
共识机制
共识机制是区块链应用项目稳定性的重要属性,实际上没有一种机制是完美的。
主要包括以下几种模式,很多项目使用混合机制。下面的例子也是通过POS+POW的方式进行的。
POW:工作证明,工作证明。
比特币在出块过程中使用了 POW 机制。一个满足要求的区块Hash由N个前导零组成,零的个数取决于网络的难度值。要得到一个合理的 Block Hash 需要大量的试算,计算时间取决于机器的哈希运算速度。当一个节点提供了一个合理的 Block Hash 值时,就意味着该节点确实经历了大量的计算尝试。当然,无法得到计算次数的绝对值,因为找到一个合理的 Hash 是概率事件。当一个节点拥有全网n%的算力时,该节点有n/100的概率找到Block Hash。
POS:权益证明,权益证明。
POS,也称为权益证明,类似于存储在银行中的财产。该模型会根据您持有数字货币的数量和时间为您分配相应的利息。
简而言之,它是一个根据您持有的货币数量和时间向您支付利息的系统。在 PoS POS 模式中,有一个术语叫做币龄,每种币每天产生 1 个币龄。有100个硬币,总共持有30天。那么,你的币龄为 3000。此时,如果你发现了一个 POS 区块,你的币龄将被清为 0。
每清空 365 个币,你会从区块中获得 0.05 个利息币(假设利息可以理解为年利率 5%),那么本例中,利息 = 3000 * 5% / 365 = 0.41个硬币,这个很有意思,持币有利息。
DPOS:委托权益证明,委托权益证明。
比特股的DPoS机制,中文名称为股份授权证明机制(也称受托人机制),其原理是让每个持有比特股的人都可以投票,产生101个代表,我们可以理解为101个超级节点或矿池,这101个超级节点的权利是完全平等的。
从某种角度来看,DPOS有点像议会制或人民代表大会制。如果代表未能履行职责(轮到他们时,未能生成块),他们将从列表中删除,网络会选举新的超级节点来替换它们。DPOS的出现主要得益于矿机的产生。不了解或不关心比特币的人使用了大量的计算能力。类似于演唱会的黄牛,他们囤了很多票,根本不关心演唱会的内容。
PBFT:Practical Byzantine Fault Tolerance,一种实用的拜占庭容错算法。
PBFT是一种状态机副本复制算法,即将一个服务建模为一个状态机,将状态机复制到分布式系统的不同节点中。状态机的每个副本都保存着服务的状态,也实现了服务的运行。
所有副本的集合用大写字母R表示,每个副本用0到|R|-1的整数表示。为了描述方便,假设|R|=3f+1,其中f是可能失败的最大副本数。虽然可以有超过 3f+1 个副本,但是额外的副本除了降低性能之外并没有提高可靠性。
以上主要是目前主流的共识算法。
从时间上看,这个顺序也是按照共识算法从诞生到流行的顺序来确定的。
对于 POW,比特币直接变成现实并投入使用。POS的存在主要来自经济考虑和创新。最后,由于专业矿工和矿机的存在,社区对这种去中心化算法存在实质性的中心化担忧,即传闻有60%到70%的算力集中在中国。
所以后来出现了DPOS,不需要太多额外的算力来分配矿池产出的权益。但要说能起到替代的作用,DPOS单独代替POW,POS或者POW+POS的可能性不大,毕竟存在是合理的。每种算法在特定的时间段内都有自己的考量和意义,无论是技术还是业务。
如果跳出技术人员的视角,结合更多的政治经济思维方式,可能会有更多的共识算法,比如共识方式结合类似PPP的概念,不仅可以达到惩罚恶意的性质人,也未必能以最高的效率达到节省算力的目的。
至于算法的选择,这里引用季万达总裁的一句话作为结论。
总之,共识的最佳设计就是模块化,比如 Notary。共识算法的选择与应用场景高度相关。可信环境使用Paxos或Raft,许可联盟可以使用PBFT,非授权链可以是POW、POS、Ripple共识等,根据交易对手信任程度,自由选择共识机制,这就是真正的最优。
侧链
侧链是相对于主链的概念。英语是侧链。侧链概念的提出主要是为了实现比特币等数字资产在多个区块链之间的转移。简而言之,侧链是一种使货币能够在两个区块链之间移动的机制。侧链是为了综合实现加密货币金融生态的目标,而不是像其他加密货币那样排斥现有系统。使用侧链,我们可以轻松建立各种智能金融合约、股票、期货、衍生品等。
侧链的产生
最初,侧链的出现是为了弥补比特币区块链运行中的一些问题,比如比特币区块链是单一的原生数字资产,不能与任何其他资产进行交换,而比特币区块链由于其共识机制强、交易慢等,这就需要比特币区块链考虑是否进行技术升级,以满足人们对区块链的更多需求。
但是,比特币区块链对整个系统的完整性和安全性要求很高。比特币系统本身的升级改造需要非常严格的验证和安全的升级方式。为了满足更多更新的需求,需要一条辅助区块链。
首先,可以通过虚拟方式将比特币转移到侧链。然后,可以根据相应的需求开发不同的侧链,帮助比特币区块链或主链实现其他需求。它不需要经常更新主链。
同时,侧链完成操作后,侧链中的资产可以随时转回比特币区块链或主链,从而实现资产的安全返还。因此需要开发侧链。
侧链原理
要实现侧链,首先要清楚地了解侧链的用途。当实现主链暂时无法满足的新需求时,主链上的资产可以无缝转移到侧链上,而侧链上的资产并不是新的独立货币,因为如果每条侧链引入一个新的数字货币,那么在从主链到侧链的资产兑换过程中,将不得不处理大量的汇率转换问题。. 因此,侧链和主链使用统一的数字货币。货币的发行机制和自身的安全性由主链整体维护。侧链只需要专注于技术创新。
从实现的角度来看,当资产从 A 区块链转移到 B 区块链时,我们在 A 链上创建一个锁定资产的交易,然后在 B 链上创建一个交易,交易的输入包含用于解锁侧链中等价资产的加密证明凭证。逆向操作是先通过交易锁定B链中的资产,然后解锁A链中等值的资产,实现不同区块链的货币转移。
A链称为主链,B链称为侧链。在某些模型中,两条链可以点对点处理。从概念上讲,我们打算将资产从(初始)主链转移到侧链,可能转移到其他侧链,最终回到主链,保留初始资产。通常,我们将主链视为比特币系统,将侧链视为其他区块链之一。
当然,侧链中的硬币也可以在侧链之间转移,不仅是比特币系统;但是比特币运行基本原理,由于任何最初从比特币系统中移出的硬币都可以移回,因此无论变成什么,它仍然是比特币。
要完成资产转移方法的实现,有一个难点,就是侧链如何知道资产已经完全锁定在主链上。反向传输也需要考虑这个问题。正如我们上面所说,我们需要使用加密证明证书。而这个证明机制其实就是使用了比特币区块链中提到的SPV证明。SPV证明是一种简单的支付验证,可以轻而易举地验证某笔支付的安全性,而无需获取整个区块链数据。
我们还是以比特币区块链为主链来解释。首先,主链硬币被发送到主链上的特定输出。此特定输出包含侧链信息的特殊地址。然后使用侧链中的 SPV 证明来验证支付是否可靠,并且不存在双花等安全问题,然后在侧链中会产生一个来自主链的输入。该资产可以在链中自由使用。
在两条链之间转移资产的过程中,我们需要两个等待期来同步两条链。
叉
因为区块链是去中心化的数据结构,所以它们在副本之间并不总是一致的。块可能在不同的时间到达不同的节点,从而导致节点具有不同的区块链视角。解决方案是每个节点总是选择并尝试扩展代表最大累积工作量证明的区块链,即具有最长或最大累积难度的链。
节点通过累加每个区块中记录的难度来获得构建链所需的工作量证明总量。只要所有节点选择累积难度最长的区块链,整个比特币网络最终都会收敛到一个一致的状态。分叉是不同区块链之间发生的暂时差异。当更多的块被添加到一个分叉中时,这个问题就会得到解决。
手动制作自己的硬币
主要是基于比特币方式创建自己的COIN。接下来,我们将了解基本的环境要求和编译工具。
环境要求:Windows 10。
编译环境:使用交叉编译环境(由于Windows编译环境比较麻烦,我们提供VMware镜像包文件,用户可以一键导入使用镜像包。为了保证编译速度,建议使用 4G 或更多内存进行编译)。
当前编译环境为最新版本。如果要升级编译组件,建议使用官网的OpenSSL和二维码进行升级。
书写工具:崇高。
制作过程如下图所示。
举一个具体的例子,我们使用一个已有的项目进行解读,最终的钱包图如下图所示。
注:以上TCO项目为公网开源项目,与本教程无关。具体代码地址可以通过GitHub下载或查看。
创世区块修改
使用 Sublime 打开 SRC 目录下的 chainparams.cpp 文件。从第156行开始,具体代码如下。
const char* pszTimestamp = "shanghai stock index closed at 2343.57, on 24th Sept., 2014";
CMutableTransaction txNew;
txNew.vin.resize(1);
txNew.vout.resize(1);
txNew.vin[0].scriptSig = CScript() << 0x1d00ffff << CScriptNum(4) << vector((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
txNew.vout[0].nValue = nGenesisSubsidy * COIN;
txNew.vout[0].scriptPubKey = CScript() << ParseHex("049e02fa9aa3c19a3b112a58bab503c5caf797972f5cfe1006275aa5485a01b48f9f648bc5380ee1e82dc6f474c8e0f7e2f6bbd0de9355f92496e3ea327ccb19cc") << OP_CHECKSIG;
genesis.vtx.push_back(txNew);
genesis.hashPrevBlock.SetNull();
genesis.hashMerkleRoot = genesis.BuildMerkleTree();
genesis.nVersion = 1;
genesis.nTime = 1411666331;//创世时间
genesis.nBits = 0x1d00ffff;
genesis.nNonce = 2056985438;
hashGenesisBlock = genesis.GetHash();
assert(hashGenesisBlock == uint256S("0x0000000061b1aca334b059920fed7bace2336ea4d23d63428c7aee04da49e942"));
assert(genesis.hashMerkleRoot == uint256S("0x7bf229f629a6666596c1ce57117c28d1d29299e8a5303347929bd70847c49adb"));
第一步是将 genesis.nNonce、hashGenesisBlock 和 genesis.hashMerkleRoot 设置为 0,然后编译。编译生成EXE应用程序后,运行钱包文件后会提示程序错误。这时候没关系。我们打开C盘APPDATA查看一下。到Debug文件中,会记录信息,然后将上述三个值的信息以相同的格式写入chainparams.cpp文件。
修改网络幻数
网络的魔数非常重要,直接关系到区块网络的安全。
具体代码如下。
CMainParams() {
strNetworkID = "main"; /**
* The message start string is designed to be unlikely to occur in normal data.
* The characters are rarely used upper ASCII, not valid as UTF-8, and produce
* a large 4-byte int at any alignment.
*/
pchMessageStart[0] = 0x90; //这个前缀内容可以进行修改
pchMessageStart[1] = 0x0d;
pchMessageStart[2] = 0xf0;
pchMessageStart[3] = 0x0d;
vAlertPubKey = ParseHex("04e01590abdc5967eb550413fcf04bbd7cead46f13579b58d52ea2f08d71a1a94196c476cd4fa60c30b51737fe3d9c8c88a04a6bec2282ebb1f22286130a153b85");
nDefaultPort = 9999;
bnProofOfWorkLimit = ~arith_uint256(0) >> 8;
nSubsidyHalvingInterval = 210000;
nEnforceBlockUpgradeMajority = 750;
nRejectBlockOutdatedMajority = 950;
nToCheckBlockUpgradeMajority = 1000;
nMinerThreads = 1; // 0 for all available cpus.
nTargetTimespan = 60 * 60; // re-targeting every one hour
nTargetSpacing = 1 * 60; // do new pow every 1 minutes.
nGenesisSubsidy = 100;
例如,比特币的幻数是 0xd9b48ef9 的值。当用户进行事务或连接时,用户可以通过抓包软件分析查看当前网络包前缀的内容,所以这个值非常重要。一方面,它可以区分不同的链。另一方面,类信息便于调试器捕获和调试数据。
修改前缀地址
具体代码如下。
前缀地址是指用户支付地址的前缀。一般建议修改,具体修改对照表。
用户可以访问这里进行对接转换。
修改网络连接端口
具体代码如下。
nDefaultPort = 19999; //建议用户进行修改,
bnProofOfWorkLimit = ~arith_uint256(0) >> 1;
nEnforceBlockUpgradeMajority = 51;
nRejectBlockOutdatedMajority = 75;
nToCheckBlockUpgradeMajority = 100;
nMinerThreads = 0;
nTargetTimespan = 14 * 24 * 60 * 60; //! two weeks
nTargetSpacing = 10 * 60;
修改种子连接数
打开chainparams.cpp文件,从第240行开始,具体代码如下。
//vSeeds.push_back(CDNSSeedData("alexykot.me", "testnet-seed.alexykot.me"));
//vSeeds.push_back(CDNSSeedData("bitcoin.petertodd.org", "testnet-seed.bitcoin.petertodd.org"));
//vSeeds.push_back(CDNSSeedData("bluematt.me", "testnet-seed.bluematt.me"));
//vSeeds.push_back(CDNSSeedData("bitcoin.schildbach.de", "testnet-seed.bitcoin.schildbach.de"));
用户可以删除注释。该功能主要用于种子节点。最好选择VPS或云主机。同时,确保服务器必须每天 7X24 小时开启。推荐使用二级域名方式。
修改工作模式机制
打开源文件miner.cpp比特币运行基本原理,核心代码如下。
while (true) {
nNonce++; // Write the last 4 bytes of the block header (the nonce) to a copy of
// the double-SHA256 state, and compute the result.
//CHash256(hasher).Write((unsigned char*)&nNonce, 4).Finalize((unsigned char*)phash);
*phash = pblock->ComputePowHash(nNonce); // Return the nonce if the hash has at least some zero bits,
// caller will check if it has enough to reach the target
if (((uint16_t*)phash)[15] == 0) return true; // If nothing found after trying for a while, return -1
if ((nNonce & 0xfff) == 0) return false;
}
}CBlockTemplate* CreateNewBlockWithKey(CReserveKey& reservekey){
CPubKey pubkey; if (!reservekey.GetReservedKey(pubkey)) return NULL;
CScript scriptPubKey = CScript() << ToByteVector(pubkey) << OP_CHECKSIG; return CreateNewBlock(scriptPubKey);
}
在函数BitcoinMiner()中新建一个区块,设置时间戳,获取内存池中的最新交易,调用ScanHash()搜索随机数。
注意:独立挖矿的条件可以在chainparams.cpp中设置。
挖矿代码如下。
void static BitcoinMiner(CWallet *pwallet){
LogPrintf("FastCoinMiner startedn");
SetThreadPriority(THREAD_PRIORITY_LOWEST);
RenameThread("fastcoin-miner"); // Each thread has its own key and counter
CReserveKey reservekey(pwallet); unsigned int nExtraNonce = 0; try { while (true) { if (Params().MiningRequiresPeers()) { // Busy-wait for the network to come online so we don't waste time mining
// on an obsolete chain. In regtest mode we expect to fly solo.
while (vNodes.empty())
MilliSleep(1000);
} //
// Create new block
//
unsigned int nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
CBlockIndex* pindexPrev = chainActive.Tip(); auto_ptr pblocktemplate(CreateNewBlockWithKey(reservekey)); if (!pblocktemplate.get())
{
LogPrintf("Error in FastCoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining threadn"); return;
}
CBlock *pblock = &pblocktemplate->block;
IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
LogPrintf("Running FastCoinMiner with %u transactions in block (%u bytes)n", pblock->vtx.size(),
::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION)); //
// Search
//
int64_t nStart = GetTime();
arith_uint256 hashTarget = arith_uint256().SetCompact(pblock->nBits);
uint256 hash; uint32_t nNonce = 0; while (true) { // Check if something found
if (ScanHash(pblock, nNonce, &hash))
{ if (UintToArith256(hash) <= hashTarget)
{ // Found a solution
pblock->nNonce = nNonce;
assert(hash == pblock->GetHash());
SetThreadPriority(THREAD_PRIORITY_NORMAL);
LogPrintf("FastCoinMiner:n");
LogPrintf("proof-of-work found n hash: %s ntarget: %sn", hash.GetHex(), hashTarget.GetHex());
ProcessBlockFound(pblock, *pwallet, reservekey);
SetThreadPriority(THREAD_PRIORITY_LOWEST); // In regression test mode, stop mining after a block is found.
if (Params().MineBlocksOnDemand()) throw boost::thread_interrupted(); break;
}
}
代码中预设的Hash算法(sha256、scrypt等)可以通过区块版本来区分,所以在scanhash中调用ComputePowHash时,可以选择不同的POW算法,甚至可以将这些算法串联起来. 加密。
修改奖励制度
修改挖矿奖励的到期时间,源码请访问main.h。
static const int COINBASE_MATURITY = 14;
修改交易确认区块推荐值,源码请访问qt/transactionrecord.h。核心代码如下。
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;
修改难度设置
修改难度配置,请访问源文件chainparams.cpp。核心代码如下。
class CMainParams : public CChainParams { public:
CMainParams() {
networkID = CBaseChainParams::MAIN;
strNetworkID = "main";
pchMessageStart[0] = 0x90;
pchMessageStart[1] = 0x0d;
pchMessageStart[2] = 0xf0;
pchMessageStart[3] = 0x0d;
vAlertPubKey = ParseHex("04e01590abdc5967eb550413fcf04bbd7cead46f13579b58d52ea2f08d71a1a94196c476cd4fa60c30b51737fe3d9c8c88a04a6bec2282ebb1f22286130a153b85");
nDefaultPort = 9999;
bnProofOfWorkLimit = ~uint256(0) >> 32;
nSubsidyHalvingInterval = 210000;
nEnforceBlockUpgradeMajority = 750;
nRejectBlockOutdatedMajority = 950;
nToCheckBlockUpgradeMajority = 1000;
nMinerThreads = 1; // 0 for all available cpus
nTargetTimespan = 60 * 60; // re-targeting every one hour
nTargetSpacing = 1 * 60;
nGenesisSubsidy = 100; ‘
下面解释以下重要代码。
A.bnProofOfWorkLimit=~uint256(0) >> 32;为大整数(256位),前32位为0,该参数表示全网允许的最低难度,低于此的区块困难不会被挖掘。
B.nGenesisSubsidy = 100;代表初始补贴,第一块比特币的奖励是50 BTC。
C.nSubsidyHavlingInterval = 210000; 该参数决定了比特币奖励(补贴、挖矿奖励)将减半的区块数。这个参数结合初始奖励(比如比特币50)基本可以估算出全网的总币产出(比如比特币的2100万),这个初始奖励也可以配置,如图B所示。比如比特币,一个比例级数求和公式可以计算出总金额50(1/(1 - 0.5))*210000=2100万比特币。
以上两个参数是在查询区块奖励时使用的。详情请查看 main.cpp 中的 GetBlockValue(height, fee)。
代币总量请查看 srcmain.cpp 中第 951 行的代码。
D. 难度调整周期请参考以下两段代码。
nTargetTimespan = 60 * 60; // re-targeting every one hour, 60 blocksnTargetSpacing = 1 * 60; // expect 1 block/minute
这里的设置是60分钟(3600秒,因为预计60秒出1个区块,那么60个区块后计算新难度,否则使用前一个区块的难度),重新评估难度,挖矿下一个区块可能需要使用新的难度设置。
修改界面
用户可以通过 QT 进行设计。主要文件请访问srcqt,语言包文件为srcqtlocale。
接下来我们看看POS和POW模式切换修改。
取消POS挖矿的币量代码如下。
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight){ int64 nRewardCoinYear;
nRewardCoinYear = MAX_MINT_PROOF_OF_STAKE; if(nHeight < YEARLY_BLOCKCOUNT)
nRewardCoinYear = 10 * MAX_MINT_PROOF_OF_STAKE;
else if(nHeight < (2 * YEARLY_BLOCKCOUNT))
nRewardCoinYear = 8 * MAX_MINT_PROOF_OF_STAKE; else if(nHeight < (3 * YEARLY_BLOCKCOUNT))
nRewardCoinYear = 6 * MAX_MINT_PROOF_OF_STAKE; else if(nHeight < (4 * YEARLY_BLOCKCOUNT))
nRewardCoinYear = 4 * MAX_MINT_PROOF_OF_STAKE;
else if(nHeight < (5 * YEARLY_BLOCKCOUNT))
nRewardCoinYear = 2 * MAX_MINT_PROOF_OF_STAKE;
int64 nSubsidy = nCoinAge * nRewardCoinYear / 365;
if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%dn", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
return nSubsidy;}
修改为:
int64 GetProofOfStakeReward(int64 nCoinAge, unsigned int nBits, unsigned int nTime, int nHeight){ int64 nSubsidy = 0;
if (fDebug && GetBoolArg("-printcreation")) printf("GetProofOfStakeReward(): create=%s nCoinAge=%"PRI64d" nBits=%dn", FormatMoney(nSubsidy).c_str(), nCoinAge, nBits);
return nSubsidy;}
也就是POS利息变成0。如果还想用POW+POS,这些代码不用修改就可以修改。
特别声明:本教程从技术角度进行讲解和讲解。任何个人或组织不得通过教程的内容进行一些金融或硬币活动。注:投资有风险,入市需谨慎。没有应用程序的区块链项目是一种高风险行为。