The principle of POW mining algorithm and its implementation in bitcoin and Ethereum

Source: Internet
Author: User
Tags diff integer division pow rand

PoW, full name proof of work, that is proof of workload, also known as mining. Most public or virtual currencies, such as Bitcoin and Ethereum, are based on the POW algorithm to implement their consensus mechanism. That is, according to the effective work of mining contribution, to determine the distribution of money.
?

Bitcoin block

?
The Bitcoin block consists of the block size and the list of transactions included in the chunk. The block size is 80 bytes, and its composition includes:
?
4 Bytes: Version number
32 Bytes: The hash value of the previous chunk
32 bytes: Merkle Genhachy Value of the trade list
4 bytes: Current timestamp
4 bytes: Current difficulty value
4 bytes: Random number nonce value
?
This 80-byte chunk header is the input string for the Bitcoin POW algorithm.
The trading list is appended to the block size, where the first deal is a special deal for miners to receive incentives and fees.
?
bitcoin-0.15.1 Source Central block and chunk definition:
?

class CBlockHeader{public:    //版本号    int32_t nVersion;    //上一个区块的哈希值    uint256 hashPrevBlock;    //交易列表的Merkle根哈希值    uint256 hashMerkleRoot;    //当前时间戳    uint32_t nTime;    //当前挖矿难度,nBits越小难度越大    uint32_t nBits;    //随机数Nonce值    uint32_t nNonce;    //其它代码略};class CBlock : public CBlockHeader{public:    //交易列表    std::vector<CTransactionRef> vtx;    //其它代码略};//代码位置src/primitives/block.h

?

Principle of Bitcoin POW algorithm

?
The POW process, which is the process of continuously adjusting the nonce value, doing a double SHA256 hash of the chunk head, making the result satisfy the hash value of a given number of leading 0.
The number of leading 0, depending on the mining difficulty, the number of leading 0, the greater the difficulty of mining.
?
Specific as follows:
?
1. Generate a coin transaction and make a list of transactions with all other transactions prepared to be packaged into chunks, generating merkle Genhachy values.
2, the Merkle Genhachy value, and the chunk header other fields constitute the chunk header, 80 bytes of length of the chunk head as the input of the POW algorithm.
3, constantly change the block head of the random number nonce, the changed block head to do double SHA256 hash, and the current difficulty of the target value to do, if less than the target difficulty, that is, POW completed.
?
The pow-completed chunk is broadcast to the whole network, and the other nodes verify that it conforms to the rule, and if the validation is valid, the other node will receive the chunk and append it to the existing block chain. After that, the next round of mining will be entered.
?
bitcoin-0.15.1 source code in the POW algorithm implementation:

Univalue generateblocks (std::shared_ptr<creservescript> coinbasescript, int ngenerate, uint64_t nMaxTries, BOOL    Keepscript) {static const int ninnerloopcount = 0x10000;    int nheightend = 0;    int nheight = 0;        {//Don ' t keep Cs_main locked LOCK (cs_main);        nheight = Chainactive.height ();    Nheightend = nheight+ngenerate;    } unsigned int nextranonce = 0;    Univalue blockhashes (Univalue::varr); while (Nheight < nheightend) {std::unique_ptr<cblocktemplate> pblocktemplate (Blockassembler (Params ()).        Createnewblock (Coinbasescript->reservescript));        if (!pblocktemplate.get ()) throw Jsonrpcerror (Rpc_internal_error, "couldn ' t create new block");        Cblock *pblock = &pblocktemplate->block;            {LOCK (Cs_main);        Incrementextranonce (Pblock, Chainactive.tip (), nextranonce);        }//Change the random number nonce in the chunk header//make a double SHA256 hash of the changed chunk head//match the target value of the current difficulty, if it is less than the target difficulty, the POW completesuint64_t nmaxtries = 1000000; retry 1 million times while (nmaxtries > 0 && pblock->nnonce < Ninnerloopcount & amp;&! Checkproofofwork (Pblock->gethash (), Pblock->nbits, Params ().            Getconsensus ())) {++pblock->nnonce;        --nmaxtries;        } if (nmaxtries = = 0) {break;        } if (pblock->nnonce = = Ninnerloopcount) {continue;        } std::shared_ptr<const cblock> Shared_pblock = Std::make_shared<const cblock> (*pblock); if (! Processnewblock (Params (), Shared_pblock, True, nullptr)) throw Jsonrpcerror (Rpc_internal_error, "Processnewbloc        K, block not accepted ");        ++nheight; Blockhashes.push_back (Pblock->gethash ().        Gethex ());        Mark script as important because it is used at least for one Coinbase output if the script came from the wallet        if (keepscript) {coinbasescript->keepscript (); }} return blockhashes;} //Code Location Src/rpc/mining.cpp 

?
Create a coin trade in another bitcoin-0.15.1 source code and a new block:
?

Std::unique_ptr<cblocktemplate> blockassembler::createnewblock (const cscript& SCRIPTPUBKEYIN, BOOL    FMINEWITNESSTX) {int64_t Ntimestart = Gettimemicros ();    Resetblock ();    Pblocktemplate.reset (New Cblocktemplate ());    if (!pblocktemplate.get ()) return nullptr; pblock = &pblocktemplate->block;    Pointer for convenience pblock->vtx.emplace_back (); Pblocktemplate->vtxfees.push_back (-1); Updated at end Pblocktemplate->vtxsigopscost.push_back (-1);    Updated at end LOCK2 (Cs_main, Mempool.cs);    cblockindex* Pindexprev = Chainactive.tip ();    nheight = pindexprev->nheight + 1; Version number Pblock->nversion = Computeblockversion (Pindexprev, Chainparams.    Getconsensus ()); if (chainparams.    Mineblocksondemand ()) pblock->nversion = Gargs.getarg ("-blockversion", pblock->nversion);    Current timestamp pblock->ntime = Getadjustedtime ();    Const int64_t nmediantimepast = Pindexprev->getmediantimepast (); Nlocktimecutoff =(Standard_locktime_verify_flags & Locktime_median_time_past)?    Nmediantimepast:pblock->getblocktime (); fincludewitness = iswitnessenabled (Pindexprev, Chainparams.    Getconsensus ()) && fminewitnesstx;    int npackagesselected = 0;    int ndescendantsupdated = 0;    Addpackagetxs (npackagesselected, ndescendantsupdated);    int64_t nTime1 = Gettimemicros ();    NLASTBLOCKTX = NBLOCKTX;    Nlastblockweight = Nblockweight;    Create coins trading cmutabletransaction coinbasetx;    CoinbaseTx.vin.resize (1); Coinbasetx.vin[0].prevout.    SetNull ();    CoinbaseTx.vout.resize (1);    Mining award and Handling fee Coinbasetx.vout[0].scriptpubkey = Scriptpubkeyin; Coinbasetx.vout[0].nvalue = nfees + getblocksubsidy (nheight, Chainparams.    Getconsensus ());    Coinbasetx.vin[0].scriptsig = CScript () << nheight << op_0;    The first deal is a special deal for miners to receive incentives and fees pblock->vtx[0] = Maketransactionref (Std::move (COINBASETX)); Pblocktemplate->vchcoinbasecommitment = Generatecoinbasecommitment (*pblock, Pindexprev, Chainparams.    Getconsensus ());    Pblocktemplate->vtxfees[0] =-nfees; logprintf ("Createnewblock (): Block weight:%u txs:%u fees:%ld sigops%d\n", Getblockweight (*pblock), NBLOCKTX, Nfees, NB    Locksigopscost);    The hash value of the previous chunk Pblock->hashprevblock = Pindexprev->getblockhash (); UpdateTime (pblock, Chainparams.    Getconsensus (), Pindexprev); The current mining difficulty pblock->nbits = getnextworkrequired (Pindexprev, Pblock, Chainparams.    Getconsensus ());    Random number nonce value pblock->nnonce = 0;    PBLOCKTEMPLATE-&GT;VTXSIGOPSCOST[0] = Witness_scale_factor * Getlegacysigopcount (*pblock->vtx[0]);    Cvalidationstate State; if (!  Testblockvalidity (state, Chainparams, *pblock, Pindexprev, False, False)) {Throw Std::runtime_error (strprintf ("%s:    Testblockvalidity failed:%s ", __func__, Formatstatemessage (state));    } int64_t nTime2 = Gettimemicros (); Logprint (Bclog::bench, "Createnewblock () Packages:%.2FMS (%d packages,%d updated descendants), validity:%.2fms (total%.2fms) \ n ", 0.001 * (Ntime1-ntimestart), Npackagesselec    Ted, ndescendantsupdated, 0.001 * (ntime2-ntime1), 0.001 * (Ntime2-ntimestart)); Return Std::move (pblocktemplate);} Code Location Src/miner.cpp

?

Calculation of difficulty in mining of Bitcoin

?
After each 2016 blocks are created, the new difficulty is calculated, and the next 2016 blocks use the new one. The calculation steps are as follows:
?
1. Find the first block of the top 2016 blocks and calculate the time it takes to generate the 2016 blocks.
That is, the time difference between the last block and the first block. The time difference is not less than 3.5 days, less than 56 days.
2, calculate the difficulty sum of the first 2016 blocks, namely the difficulty X total time of a single block.
3, calculate the new difficulty, that is 2016 blocks of difficulty sum/14 days of the number of seconds, get the difficulty value per second.
4, the requirements of new difficulty, the difficulty is not less than the minimum parameter definition of difficulty.
?
bitcoin-0.15.1 source code in the calculation of mining difficulty codes are as follows:
?

Nfirstblocktime is the timestamp of the first block of the top 2016 blocks unsigned int calculatenextworkrequired (const cblockindex* Pindexlast, int64_t Nfirstblocktime, const Consensus::P arams& Params) {if (params.fpownoretargeting) return pindexlast->nbits    ;    Calculate the time taken to generate these 2016 blocks int64_t Nactualtimespan = Pindexlast->getblocktime ()-nfirstblocktime;    Not less than 3.5 days if (Nactualtimespan < PARAMS.NPOWTARGETTIMESPAN/4) Nactualtimespan = PARAMS.NPOWTARGETTIMESPAN/4;     Less than 56 days if (Nactualtimespan > params.npowtargettimespan*4) nactualtimespan = params.npowtargettimespan*4;    Retarget const ARITH_UINT256 bnpowlimit = UintToArith256 (params.powlimit);    arith_uint256 bnnew;    Bnnew.setcompact (pindexlast->nbits);    Calculate the difficulty sum of the first 2016 blocks//The difficulty of a single block * Total time bnnew *= Nactualtimespan;    Calculate the new difficulty//That is 2016 blocks of difficulty sum/14 days of the number of seconds bnnew/= Params.npowtargettimespan;    The smaller the bnnew, the greater the difficulty//bnnew the greater the difficulty, the less difficult the difficulty is not less than the minimum difficulty of the parameter definition if (Bnnew > Bnpowlimit) bnnew = Bnpowlimit; REturn bnnew.getcompact ();} Code Location Src/pow.cpp

?

Ethereum Block

? The
Ethereum block consists of the header and body parts.
?
The header section is as follows:
Parenthash, the parent chunk hash
Unclehash, and the tertiary chunk hash, specifically the RLP hash value of the uncles array in the body. RLP hash, that is, a type of object RLP encoded after the SHA3 hash operation.
Coinbase, miner address. The RLP hash value of the state Trie root node in the
Root,statedb. The RLP hash value of the TX trie root node in the
Txhash,block. The RLP hash value of the receipt trie root node in the
Receipthash,block.
Difficulty, block difficulty, that is, the current mining difficulty.
Number, block ordinal, which is the parent chunk number+1.
Gaslimit, the theoretical upper limit of all gas consumption in a chunk, specified at creation, calculated by the parent chunk gasused and Gaslimit.
Gasused, the sum of the gas consumed by all transaction in the chunk when executed.
time, the current timestamp.
Nonce, random number nonce value.
?
About tert-Blocks:
tert-blocks, or orphaned blocks. Ethereum blocks faster, resulting in solitary blocks. The
Ethereum will give a return to the miners who find the lone block, encouraging the miners to refer to the solitary block in the new block and to make the main chain heavier by referencing the solitary block. In Ethereum, the main chain refers to the heaviest chain.
?
for state Trie, TX Trie, and receipt Trie:
State Trie, all account objects can be inserted into a single merkle-patricatrie (MPT) structure, forming state Trie.
TX Trie:block All the TX objects in transactions, inserted into the MPT structure one by one, to form the TX Trie.
Receipt Trie:block generates RECEIPT arrays after all transaction are executed, and all Receipt are inserted into the MPT structure one by one, forming Receipt Trie.
? The
body member is as follows:
transactions, trade list.
Uncles, a list of referenced tertiary blocks.
?
go-ethereum-1.7.3 Source Central block and chunk definition:
?

type Header struct {    //父区块哈希    ParentHash  common.Hash    //叔区块哈希    UncleHash   common.Hash    //矿工地址    Coinbase    common.Address    //StateDB中state Trie根节点RLP哈希值    Root        common.Hash    //Block中tx Trie根节点RLP哈希值    TxHash      common.Hash    //Block中Receipt Trie根节点的RLP哈希值    ReceiptHash common.Hash    Bloom       Bloom    //区块难度    Difficulty  *big.Int    //区块序号    Number      *big.Int    //区块内所有Gas消耗的理论上限    GasLimit    *big.Int    //区块内所有Transaction执行时消耗的Gas总和    GasUsed     *big.Int    //当前时间戳    Time        *big.Int    Extra       []byte    MixDigest   common.Hash    //随机数Nonce值    Nonce       BlockNonce}type Body struct {    //交易列表    Transactions []*Transaction    //引用的叔区块列表    Uncles       []*Header}//代码位置core/types/block.go

?

The principle of Ethereum POW algorithm

?  The
Ethereum POW algorithm can be expressed as the following formula:
RAND (H, N) <= m/d
?
where Rand () represents a conceptual function that represents a series of complex operations.
where h and n are input, that is, the hash of the chunk header, and the nonce in the header. The
M represents an enormous number, where 2^256-1 is used.
D, which is the block difficulty, the difficulty in the header.
?
Therefore, in the case of H and N, the larger the D, the greater the difficulty of mining, which is the original meaning of difficulty. The
is constantly changing the nonce so that rand (h, N) satisfies rand (h, N) <= M/d, which completes the POW.
?
go-ethereum-1.7.3 code in the POW algorithm implementation:
?

Func (Ethash *ethash) mine (Block *types. Block, id int, seed uint64, Abort Chan struct{}, found Chan *types. Block) {//Extract some data from the header var (header = block. Header () hash = header. Hashnononce (). Bytes ()//target, i.e. M/d, (2^256-1)/difficulty target = new (big. INT). Div (maxUint256, header. Difficulty) Number = header.  Number.uint64 () DataSet = Ethash.dataset (number))//Start generating random nonces until we abort or find a Good one var (attempts = Int64 (0) nonce = seed) Logger: = log. New ("Miner", id) logger.  Trace ("Started Ethash search for new nonces", "seed", Seed) for {select {case <-abort:// Mining terminated, update stats and abort logger.        Trace ("Ethash nonce Search aborted", "attempts", Nonce-seed) Ethash.hashrate.Mark (attempts) return Default://We don't have the to update hash rate on every nonce, so Update after 2^x nonces attempts++ if (attempts% (1 <<)) = = 0 {Etha            Sh.hashrate.Mark (attempts) attempts = 0}//hashimotofull is a series of complex operations represented by Rand (h, N) Digest, Result: = Hashimotofull (DataSet, hash, nonce)//result satisfies rand (h, N) <= m/d if n EW (BIG. INT). SetBytes (Result). CMP (target) <= 0 {//Correct nonce found, create a new header with it header = types. Copyheader (header) header. Nonce = types. Encodenonce (nonce) header. Mixdigest = Common. Bytestohash (Digest)//Seal and return a block (if still needed) select {CAs E found <-block. Withseal (header): Logger.                    Trace ("Ethash nonce found and reported", "attempts", Nonce-seed, "nonce", nonce) case <-abort: Logger. Trace ("Ethash nonce found but discarded", "attEmpts ", Nonce-seed," nonce ", Nonce)} return}//constantly changing the nonce nonce++}}}//Code location consensus/ethash/sealer.go

?

Difficulty calculation of mining in Ethereum

?
Each time the ethereum is mined, it is necessary to calculate the current block difficulty.
There are three different rules for calculating difficulty by version: Calcdifficultybyzantium (Byzantium version), Calcdifficultyhomestead (Homestead version), Calcdifficultyfrontier (Version Frontier). Here, take Calcdifficultyhomestead as an example.
?
When calculating the difficulty, the input is:
Parent_timestamp: Parent Chunk Timestamp
Parent_diff: Parent Block difficulty
Block_timestamp: Current chunk timestamp
Block_number: The ordinal of the current chunk
?
The current block difficulty calculation formula, namely:
?

block_diff = parent_diff+ (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)+ 2^((block_number // 100000) - 2)

?
where//is the integer division operator, a//b, that is, A/b is calculated first, and then the largest integer not greater than A/b is taken.
?
The purpose of adjusting the difficulty, that is, in order to keep the mining time in the 10-19s period, if less than 10s increase mining difficulty, if greater than 19s will reduce the difficulty. In addition, the calculation of the current block difficulty should not be lower than the Ethereum creation block difficulty, that is, 131072.
?
go-ethereum-1.7.3 source code in the calculation of mining difficulty codes are as follows:
?

Func Calcdifficultyhomestead (Time UInt64, parent *types. Header) *big.     Int {//Https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki//algorithm://diff = (Parent_diff + (parent_diff/2048 * MAX (1-(Block_timestamp-parent_timestamp)//Ten, -99))//) + 2^ (periodc ount-2) Bigtime: = new (big. INT). SetUint64 (time) Bigparenttime: = new (BIG). INT). Set (parent. Time)//holds intermediate values to make the Algo easier to read & audit x: = new (big. Int) Y: = new (big. INT)//1-(Block_timestamp-parent_timestamp)//X.sub (Bigtime, Bigparenttime) x.div (x, BIG10) x.sub (big 1, x)//MAX (1-(Block_timestamp-parent_timestamp)// -99) if X.CMP (BIGMINUS99) < 0 {X.set (bigminu S99)}//(Parent_diff + parent_diff//2048 * MAX (1-(Block_timestamp-parent_timestamp)//Ten, -99)) Y.div (PA Rent. difficulty, params. Difficultybounddivisor) X.mul (y, X) x.add (parent. difficulty, X)//MinimUm difficulty can ever be (before exponential factor) if x.cmp (params. Minimumdifficulty) < 0 {X.set (params. minimumdifficulty)}//For the exponential factor Periodcount: = new (big. INT). ADD (parent. Number, BIG1) periodcount.div (Periodcount, Expdiffperiod)//The exponential factor, commonly referred to as "the Bo MB "//diff = diff + 2^ (periodCount-2) if periodcount.cmp (BIG1) > 0 {y.sub (periodcount, Big2) y. Exp (Big2, y, nil) x.add (x, y)} return x}//code location consensus/ethash/consensus.go

?

Postscript

?
The concept of the POW algorithm is simple, that is, the working side submits hard-to-calculate but easy-to-validate calculations, and the other nodes verify the results to make sure that the work has done quite a lot.
But its shortcomings are also obvious: 1, with the node will be the CPU mining upgrade to the GPU, and even mining machine, the number of nodes and the calculation force has gradually imbalance; 2, bitcoin and other networks need to complete trillions times per second hash calculation, a lot of waste of resources.
For this reason, the industry has proposed a substitute for POW such as the POS proof algorithm, that is, require the user to have a certain number of currencies, to participate in determining the next legal block. In addition, it is more difficult to purchase more than half of the currency than 51%, which makes it harder to make malicious attacks.

The principle of POW mining algorithm and its implementation in bitcoin and Ethereum

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.