02-twister: twister核心源码分析

02-twister: twister核心源码分析交易结构classCTransaction{public:staticconstintCURRENT_VERSION=1;intnVersion;//版本CScriptmessage;//推文CScriptuserNa

交易结构


class CTransaction
{ 
   
public:
    static const int CURRENT_VERSION=1;
    int nVersion; // 版本
    CScript message; // 推文
    CScript userName; // 用户名
    CScript pubKey; // 公钥, 用于验证
    unsigned int nNonce; 
	// 成员函数略
};



交易输入和输出

class CTxIn
{ 
   
public:
    COutPoint prevout;
    CScript scriptSig;
    unsigned int nSequence;
};

class CTxOut
{ 
   
public:
    int64 nValue;
    CScript scriptPubKey;
};

区块头

/** Nodes collect new transactions into a block, hash them into a hash tree, * and scan through nonce values to make the block's hash satisfy proof-of-work * requirements. When they solve the proof-of-work, they broadcast the block * to everyone and the block is added to the block chain. The first transaction * in the block is a special one that creates a new coin owned by the creator * of the block. */
class CBlockHeader
{ 
   
public:
    // header
    static const int CURRENT_VERSION=2;
    int nVersion; // 版本
    int nHeight; // 高度
    uint256 hashPrevBlock; // 上一个区块hash
    uint256 hashMerkleRoot; 
    unsigned int nTime; // 区块时间
    unsigned int nBits; // 挖矿难度相关
    unsigned int nNonce; // 挖矿随机数
};

区块

class CBlock : public CBlockHeader
{ 
   
public:
    // network and disk
    std::vector<CTransaction> vtx; // 交易
    // memory only
    mutable std::vector<uint256> vMerkleTree; // 默克尔树
};

挖矿PoW

// 启动矿工线程
void GenerateBitcoins(bool fGenerate, CWallet* pwallet)
{ 
   
    static boost::thread_group* minerThreads = NULL;

    int nThreads = GetArg("-genproclimit", -1);
    if (nThreads < 0) { 
   
        if (Params().NetworkID() == CChainParams::REGTEST)
            nThreads = 1;
        else
            nThreads = boost::thread::hardware_concurrency();
    }

    if (minerThreads != NULL)
    { 
   
        minerThreads->interrupt_all();
        delete minerThreads;
        minerThreads = NULL;
    }

    if (nThreads == 0 || !fGenerate)
        return;

    minerThreads = new boost::thread_group();
    for (int i = 0; i < nThreads; i++)
        minerThreads->create_thread(boost::bind(&BitcoinMiner, pwallet)); // 启动矿工线程
}

// 开始挖矿
void static BitcoinMiner(CWallet *pwallet)
{ 
   
    printf("BitcoinMiner started\n");
    SetThreadPriority(THREAD_PRIORITY_LOWEST);
    RenameThread("twister-miner");

    // Each thread has its own salt and counter
    std::vector<unsigned char> salt(4);
    RAND_bytes(salt.data(), sizeof(salt));
    unsigned int nExtraNonce = 0;

    try { 
    loop { 
   
        if (Params().NetworkID() != CChainParams::REGTEST) { 
   
            // 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 = nTransactionsUpdated;
        CBlockIndex* pindexPrev = pindexBest;

        // 创建区块模板, 包含了交易, nonce为0
        auto_ptr<CBlockTemplate> pblocktemplate(CreateNewBlock(salt));
        if (!pblocktemplate.get())
            return;
        CBlock *pblock = &pblocktemplate->block;
        IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);

        printf("Running BitcoinMiner with %"PRIszu" transactions in block (%u bytes)\n", pblock->vtx.size(),
               ::GetSerializeSize(*pblock, SER_NETWORK, PROTOCOL_VERSION));


        // 开始挖矿
        //
        // Search
        //
        int64 nStart = GetTime();
        uint256 hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
        uint256 hash;
        loop
        { 
   
            unsigned int nHashesDone = 0;

            do { 
   
                pblock->nNonce++;
                hash = pblock->GetPoWHash();

                if ((pblock->nNonce & 0xff) == 0) { 
   
                    boost::this_thread::interruption_point();
                }
                if (pindexPrev != pindexBest)
                    break;

            } while( hash > hashTarget &&
                     (pblock->nNonce & 0xfff) != 0 );
            nHashesDone = 0xffff+1;

            // Check if something found
            if (hash <= hashTarget)  // 判断nonce的hash是否满足条件
            { 
   
                // Found a solution
                SetThreadPriority(THREAD_PRIORITY_NORMAL);
                CheckWork(pblock, *pwalletMain);
                SetThreadPriority(THREAD_PRIORITY_LOWEST);

                // In regression test mode, stop mining after a block is found. This
                // allows developers to controllably generate a block on demand.
                if (Params().NetworkID() == CChainParams::REGTEST)
                    throw boost::thread_interrupted();

                break;
            }

            // Meter hashes/sec
            static int64 nHashCounter;
            if (nHPSTimerStart == 0)
            { 
   
                nHPSTimerStart = GetTimeMillis();
                nHashCounter = 0;
            }
            else
                nHashCounter += nHashesDone;
            if (GetTimeMillis() - nHPSTimerStart > 4000)
            { 
   
                static CCriticalSection cs;
                { 
   
                    LOCK(cs);
                    if (GetTimeMillis() - nHPSTimerStart > 4000)
                    { 
   
                        dHashesPerSec = 1000.0 * nHashCounter / (GetTimeMillis() - nHPSTimerStart);
                        nHPSTimerStart = GetTimeMillis();
                        nHashCounter = 0;
                        static int64 nLogTime;
                        if (GetTime() - nLogTime > 30 * 60)
                        { 
   
                            nLogTime = GetTime();
                            printf("hashmeter %6.0f khash/s\n", dHashesPerSec/1000.0);
                        }
                    }
                }
            }

            // Check for stop or if block needs to be rebuilt
            boost::this_thread::interruption_point();
            if (vNodes.empty() && Params().NetworkID() != CChainParams::REGTEST)
                break;
            if (pblock->nNonce >= 0xffff0000)
                break;
            if (nTransactionsUpdated != nTransactionsUpdatedLast && GetTime() - nStart > 60)
                break;
            if (pindexPrev != pindexBest)
                break;

            // Update nTime every few seconds
            UpdateTime(*pblock, pindexPrev);
            if (TestNet())
            { 
   
                // Changing pblock->nTime can change work required on testnet:
                hashTarget = CBigNum().SetCompact(pblock->nBits).getuint256();
            }
        }
    } }
    catch (boost::thread_interrupted)
    { 
   
        printf("BitcoinMiner terminated\n");
        throw;
    }
}



// 创建一个新的区块
CBlockTemplate* CreateNewBlock(std::vector<unsigned char> &salt)
{ 
   
    // Create new block
    auto_ptr<CBlockTemplate> pblocktemplate(new CBlockTemplate());
    if(!pblocktemplate.get())
        return NULL;
    CBlock *pblock = &pblocktemplate->block; // pointer for convenience

    // 区块奖励
    // Create coinbase tx
    CTransaction txNew;
    if( !CreateSpamMsgTx(txNew, salt) )
        return NULL;

    // Add our coinbase tx as first transaction
    pblock->vtx.push_back(txNew);

    // Largest block you're willing to create:
    unsigned int nBlockMaxSize = GetArg("-blockmaxsize", MAX_BLOCK_SIZE_GEN/2);
    // Limit to betweeen 1K and MAX_BLOCK_SIZE-1K for sanity:
    nBlockMaxSize = std::max((unsigned int)1000, std::min((unsigned int)(MAX_BLOCK_SIZE-1000), nBlockMaxSize));

    // How much of the block should be dedicated to high-priority transactions,
    // included regardless of the fees they pay
    unsigned int nBlockPrioritySize = GetArg("-blockprioritysize", DEFAULT_BLOCK_PRIORITY_SIZE);
    nBlockPrioritySize = std::min(nBlockMaxSize, nBlockPrioritySize);

    // Minimum block size you want to create; block will be filled with free transactions
    // until there are no more or the block reaches this size:
    unsigned int nBlockMinSize = GetArg("-blockminsize", 0);
    nBlockMinSize = std::min(nBlockMaxSize, nBlockMinSize);

    // 收集内存池中的交易,打包进区块中
    // Collect memory pool transactions into the block
    { 
   
        LOCK2(cs_main, mempool.cs);
        CBlockIndex* pindexPrev = pindexBest;
        CCoinsViewCache view(*pcoinsTip, true);

        // Priority order to process transactions
        list<COrphan> vOrphan; // list memory doesn't move
        map<uint256, vector<COrphan*> > mapDependers;

        // Collect transactions into block
        uint64 nBlockSize = 1000; // 一个区块最大 1000字节
        uint64 nBlockTx = 0;

        // 一个区块里面只允许一个用户发一条推文?
        // Avoid duplicate usernames within the same block
        set<uint256> uniqueUsers;

        // 遍历内存池
        for (map<uint256, CTransaction>::iterator mi = mempool.mapTx.begin(); mi != mempool.mapTx.end(); ++mi)
        { 
   
            CTransaction& tx = (*mi).second;
            if (tx.IsSpamMessage()) // 如果是垃圾推文(空的)
                continue;

            // This should never happen (unless replacement); all transactions in the memory are new
            CTransaction txOld;
            uint256 hashBlock = 0;
            if( GetTransaction(tx.GetUsername(), txOld, hashBlock) ) { 
   
                if( !verifyDuplicateOrReplacementTx(tx, false, true) ) { 
   
                    printf("CreateNewBlock: mempool transaction already exists (%s)\n",
                           tx.GetUsername().c_str());
                    continue;
                }
            }

            if( uniqueUsers.count(tx.GetUsernameHash()) ) { 
   
                printf("CreateNewBlock() : duplicate username (%s)\n", 
                       tx.GetUsername().c_str());
                continue;
            }
            uniqueUsers.insert(tx.GetUsernameHash());

            // 如果区块大小超过限制, 则跳过
            // Size limits
            unsigned int nTxSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
            if (nBlockSize + nTxSize >= nBlockMaxSize)
                continue;

            // Added
            pblock->vtx.push_back(tx); // 添加当前交易到区块中
            nBlockSize += nTxSize;  // 区块大小
            ++nBlockTx; // 区块数加1
        }

        nLastBlockTx = nBlockTx;
        nLastBlockSize = nBlockSize;
        printf("CreateNewBlock(): total size %"PRI64u"\n", nBlockSize);

        // 填充区块头
        // Fill in header
        pblock->hashPrevBlock  = pindexPrev->GetBlockHash();
        pblock->nHeight        = pindexPrev->nHeight + 1;
        UpdateTime(*pblock, pindexPrev);
        pblock->nBits          = GetNextWorkRequired(pindexPrev, pblock); // 挖矿的难度
        pblock->nNonce         = 0; // 此处暂时填0, 后面需要进行pow挖矿, 找出合适的nonce

        CBlockIndex indexDummy(*pblock);
        indexDummy.pprev = pindexPrev;
        indexDummy.nHeight = pindexPrev->nHeight + 1;
        CCoinsViewCache viewNew(*pcoinsTip, true);
        CValidationState state;
        if (!ConnectBlock(*pblock, state, &indexDummy, viewNew, true))
            throw std::runtime_error("CreateNewBlock() : ConnectBlock failed");
    }

    return pblocktemplate.release(); // 返回创建好的区块(模板)
}

今天的文章02-twister: twister核心源码分析分享到此就结束了,感谢您的阅读。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/61704.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注