bool VerifyPosTx(CAccountViewCache &accView, const CBlock *pBlock, CTransactionDBCache &txCache, CScriptDBViewCache &scriptCache, bool bNeedRunTx) { // LogPrint("INFO", "VerifyPoxTx begin\n"); uint64_t maxNonce = SysCfg().GetBlockMaxNonce(); //cacul times if (pBlock->GetNonce() > maxNonce) { return ERRORMSG("Nonce is larger than maxNonce"); } if (pBlock->GetHashMerkleRoot() != pBlock->BuildMerkleTree()) { return ERRORMSG("hashMerkleRoot is error"); } CAccountViewCache view(accView, true); CScriptDBViewCache scriptDBView(scriptCache, true); CAccount account; CRewardTransaction *prtx = (CRewardTransaction *) pBlock->vptx[0].get(); if (view.GetAccount(prtx->account, account)) { if(!CheckSignScript(pBlock->SignatureHash(), pBlock->GetSignature(), account.PublicKey)) { if (!CheckSignScript(pBlock->SignatureHash(), pBlock->GetSignature(), account.MinerPKey)) { // LogPrint("ERROR", "block verify fail\r\n"); // LogPrint("ERROR", "block hash:%s\n", pBlock->GetHash().GetHex()); // LogPrint("ERROR", "signature block:%s\n", HexStr(pBlock->vSignature.begin(), pBlock->vSignature.end())); return ERRORMSG("Verify miner publickey signature error"); } } } else { return ERRORMSG("AccountView have no the accountid"); } //校验reward_tx 版本是否正确 if (prtx->nVersion != nTxVersion2) { return ERRORMSG("CTransaction CheckTransction,tx version is not equal current version, (tx version %d: vs current %d)", prtx->nVersion, nTxVersion2); } if (bNeedRunTx) { int64_t nTotalFuel(0); uint64_t nTotalRunStep(0); for (unsigned int i = 1; i < pBlock->vptx.size(); i++) { shared_ptr<CBaseTransaction> pBaseTx = pBlock->vptx[i]; if (uint256() != txCache.IsContainTx(pBaseTx->GetHash())) { return ERRORMSG("VerifyPosTx duplicate tx hash:%s", pBaseTx->GetHash().GetHex()); } CTxUndo txundo; CValidationState state; if (CONTRACT_TX == pBaseTx->nTxType) { LogPrint("vm", "tx hash=%s VerifyPosTx run contract\n", pBaseTx->GetHash().GetHex()); } pBaseTx->nFuelRate = pBlock->GetFuelRate(); if (!pBaseTx->ExecuteTx(i, view, state, txundo, pBlock->GetHeight(), txCache, scriptDBView)) { return ERRORMSG("transaction UpdateAccount account error"); } nTotalRunStep += pBaseTx->nRunStep; if(nTotalRunStep > MAX_BLOCK_RUN_STEP) { return ERRORMSG("block total run steps exceed max run step"); } nTotalFuel += pBaseTx->GetFuel(pBlock->GetFuelRate()); LogPrint("fuel", "VerifyPosTx total fuel:%d, tx fuel:%d runStep:%d fuelRate:%d txhash:%s \n",nTotalFuel, pBaseTx->GetFuel(pBlock->GetFuelRate()), pBaseTx->nRunStep, pBlock->GetFuelRate(), pBaseTx->GetHash().GetHex()); } if(nTotalFuel != pBlock->GetFuel()) { return ERRORMSG("fuel value at block header calculate error"); } if (view.GetAccount(prtx->account, account)) { //available acc // cout << "check block hash:" << pBlock->SignatureHash().GetHex() << endl; // cout << "check signature:" << HexStr(pBlock->vSignature) << endl; // cout <<"account miner"<< account.ToString()<< endl; if(account.GetAccountPos(pBlock->GetHeight()) <= 0 || !account.IsMiner(pBlock->GetHeight())) return ERRORMSG("coindays of account dismatch, can't be miner, account info:%s", account.ToString()); } else { LogPrint("ERROR", "AccountView have no the accountid\r\n"); return false; } } uint256 prevblockhash = pBlock->GetHashPrevBlock(); const uint256 targetHash = CBigNum().SetCompact(pBlock->GetBits()).getuint256(); //target hash difficult uint64_t posacc = account.GetAccountPos(pBlock->GetHeight()); /* arith_uint256 bnNew; bnNew.SetCompact(pBlock->nBits); string timeFormat = DateTimeStrFormat("%Y-%m-%d %H:%M:%S", pBlock->nTime); LogPrint("coinday","height:%.10d, account:%-10s, coinday:%.10ld, difficulty=%.8lf, time=%-20s, interval=%d\n", pBlock->nHeight, account.regID.ToString(), posacc/COIN/SysCfg().GetIntervalPos(), CaculateDifficulty(bnNew.GetCompact()), timeFormat, pBlock->nTime-chainActive[pBlock->nHeight-1]->nTime); */ if (posacc == 0) { return ERRORMSG("Account have no pos"); } uint256 adjusthash = GetAdjustHash(targetHash, posacc, pBlock->GetHeight()-1); //adjust nbits //need compute this block proofofwork struct PosTxInfo postxinfo; postxinfo.nVersion = pBlock->GetVersion(); postxinfo.hashPrevBlock = prevblockhash; postxinfo.hashMerkleRoot = account.GetHash(); postxinfo.nValues = account.llValues; postxinfo.nTime = pBlock->GetTime(); postxinfo.nNonce = pBlock->GetNonce(); postxinfo.nHeight = pBlock->GetHeight(); postxinfo.nFuel = pBlock->GetFuel(); postxinfo.nFuelRate = pBlock->GetFuelRate(); uint256 curhash = postxinfo.GetHash(); LogPrint("miner", "Miner account info:%s\n", account.ToString()); LogPrint("miner", "VerifyPosTx block hash:%s, postxinfo:%s\n", pBlock->GetHash().GetHex(), postxinfo.ToString().c_str()); if(pBlock->GetHashPos() != curhash) { return ERRORMSG("PosHash Error: \n" " computer PoS hash:%s \n" " block PoS hash:%s\n", curhash.GetHex(), pBlock->GetHashPos().GetHex()); } if (UintToArith256(curhash) > UintToArith256(adjusthash)) { return ERRORMSG("Account ProofOfWorkLimit error: \n" " pos hash:%s \n" "adjust hash:%s\r\n", curhash.GetHex(), adjusthash.GetHex()); } return true; }
bool CreatePosTx(const CBlockIndex *pPrevIndex, CBlock *pBlock, set<CKeyID>&setCreateKey, CAccountViewCache &view, CTransactionDBCache &txCache, CScriptDBViewCache &scriptCache) { set<CKeyID> setKeyID; setKeyID.clear(); set<CAccount, CAccountComparator> setAcctInfo; { LOCK2(cs_main, pwalletMain->cs_wallet); if((unsigned int)(chainActive.Tip()->nHeight + 1) != pBlock->GetHeight()) return false; pwalletMain->GetKeys(setKeyID, true); // first:get keyID from pwalletMain if (setKeyID.empty()) { return ERRORMSG("CreatePosTx setKeyID empty"); } LogPrint("INFO","CreatePosTx block time:%d\n", pBlock->GetTime()); for(const auto &keyid:setKeyID) { //second:get account by keyID //find CAccount info by keyid if(setCreateKey.size()) { bool bfind = false; for(auto &item: setCreateKey){ if(item == keyid){ bfind = true; break; } } if (!bfind) continue; } CUserID userId = keyid; CAccount acctInfo; if (view.GetAccount(userId, acctInfo)) { // check acctInfo is or not allowed to mining , //available // LogPrint("miner", "account info:regid=%s keyid=%s ncoinday=%lld isMiner=%d\n", acctInfo.regID.ToString(), // acctInfo.keyID.ToString(), acctInfo.GetAccountPos(pBlock->nHeight), acctInfo.IsMiner(pBlock->nHeight)); if (acctInfo.IsRegister() && acctInfo.GetAccountPos(pBlock->GetHeight()) > 0 && acctInfo.IsMiner(pBlock->GetHeight())) { setAcctInfo.insert(std::move(acctInfo)); // LogPrint("miner", "miner account info:%s\n", acctInfo.ToString()); } } } } if (setAcctInfo.empty()) { setCreateKey.clear(); LogPrint("INFO", "CreatePosTx setSecureAcc empty"); return false; } uint64_t maxNonce = SysCfg().GetBlockMaxNonce(); //cacul times uint256 prevblockhash = pPrevIndex->GetBlockHash(); const uint256 targetHash = CBigNum().SetCompact(pBlock->GetBits()).getuint256(); //target hash difficult set<CAccount, CAccountComparator>::iterator iterAcct = setAcctInfo.begin(); for (;iterAcct!=setAcctInfo.end();++iterAcct) { //third: 根据不同的账户 ,去计算挖矿 CAccount &item = const_cast<CAccount&>(*iterAcct); uint64_t posacc = item.GetAccountPos(pBlock->GetHeight()); if (0 == posacc) { //have no pos LogPrint("ERROR", "CreatePosTx posacc zero\n"); continue; } LogPrint("miner", "miner account:%s\n", item.ToString()); // LogPrint("INFO", "target hash:%s\n", targetHash.ToString()); // LogPrint("INFO", "posacc:%d\n", posacc); uint256 adjusthash = GetAdjustHash(targetHash, posacc, pBlock->GetHeight()-1); //adjust nbits // LogPrint("INFO", "adjusthash:%s\n", adjusthash.ToString()); //need compute this block proofofwork struct PosTxInfo postxinfo; postxinfo.nVersion = pBlock->GetVersion(); postxinfo.hashPrevBlock = prevblockhash; postxinfo.hashMerkleRoot = item.GetHash(); postxinfo.nValues = item.llValues; postxinfo.nHeight = pBlock->GetHeight(); postxinfo.nFuel = pBlock->GetFuel(); postxinfo.nFuelRate = pBlock->GetFuelRate(); postxinfo.nTime = pBlock->GetTime(); //max(pPrevIndex->GetMedianTimePast() + 1, GetAdjustedTime()); unsigned int nNonce = 0; for (; nNonce < maxNonce; ++nNonce) { //循环的 更改随机数,计算curhash看是否满足 postxinfo.nNonce = nNonce; pBlock->SetNonce(nNonce); uint256 curhash = postxinfo.GetHash(); if (UintToArith256(curhash) <= UintToArith256(adjusthash)) { CRegID regid; if (pAccountViewTip->GetRegId(item.keyID, regid)) { CRewardTransaction *prtx = (CRewardTransaction *) pBlock->vptx[0].get(); prtx->account = regid; //存矿工的 账户ID prtx->nHeight = pPrevIndex->nHeight+1; pBlock->SetHashMerkleRoot(pBlock->BuildMerkleTree()); pBlock->SetHashPos(curhash); LogPrint("INFO", "find pos tx hash succeed: \n" " pos hash:%s \n" "adjust hash:%s \r\n", curhash.GetHex(), adjusthash.GetHex()); vector<unsigned char> vSign; if (pwalletMain->Sign(item.keyID, pBlock->SignatureHash(), vSign, item.MinerPKey.IsValid())) { LogPrint("INFO", "Create new block hash:%s\n", pBlock->GetHash().GetHex()); LogPrint("miner", "Miner account info:%s\n", item.ToString()); LogPrint("miner", "CreatePosTx block hash:%s, postxinfo:%s\n",pBlock->GetHash().GetHex(), postxinfo.ToString().c_str()); pBlock->SetSignature(vSign); return true; } else { LogPrint("ERROR", "sign fail\r\n"); } } else { LogPrint("ERROR", "GetKey fail or GetVec6 fail\r\n"); } } } } return false; }