交易结构
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