bool CTxDB::LoadBlockIndex() { if (mapBlockIndex.size() > 0) { // Already loaded once in this session. It can happen during migration // from BDB. return true; } // The block index is an in-memory structure that maps hashes to on-disk // locations where the contents of the block can be found. Here, we scan it // out of the DB and into mapBlockIndex. leveldb::Iterator *iterator = pdb->NewIterator(leveldb::ReadOptions()); // Seek to start key. CDataStream ssStartKey(SER_DISK, CLIENT_VERSION); ssStartKey << make_pair(string("blockindex"), uint256(0)); iterator->Seek(ssStartKey.str()); // Now read each entry. while (iterator->Valid()) { // Unpack keys and values. CDataStream ssKey(SER_DISK, CLIENT_VERSION); ssKey.write(iterator->key().data(), iterator->key().size()); CDataStream ssValue(SER_DISK, CLIENT_VERSION); ssValue.write(iterator->value().data(), iterator->value().size()); string strType; ssKey >> strType; // Did we reach the end of the data to read? if (fRequestShutdown || strType != "blockindex") break; CDiskBlockIndex diskindex; ssValue >> diskindex; uint256 blockHash = diskindex.GetBlockHash(); // Construct block index object CBlockIndex* pindexNew = InsertBlockIndex(blockHash); pindexNew->pprev = InsertBlockIndex(diskindex.hashPrev); pindexNew->pnext = InsertBlockIndex(diskindex.hashNext); pindexNew->nFile = diskindex.nFile; pindexNew->nBlockPos = diskindex.nBlockPos; pindexNew->nHeight = diskindex.nHeight; pindexNew->nMint = diskindex.nMint; pindexNew->nMoneySupply = diskindex.nMoneySupply; pindexNew->nFlags = diskindex.nFlags; pindexNew->nStakeModifier = diskindex.nStakeModifier; pindexNew->prevoutStake = diskindex.prevoutStake; pindexNew->nStakeTime = diskindex.nStakeTime; pindexNew->hashProof = diskindex.hashProof; pindexNew->nVersion = diskindex.nVersion; pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot; pindexNew->nTime = diskindex.nTime; pindexNew->nBits = diskindex.nBits; pindexNew->nNonce = diskindex.nNonce; // Watch for genesis block if (pindexGenesisBlock == NULL && blockHash == (!fTestNet ? hashGenesisBlock : hashGenesisBlockTestNet)) pindexGenesisBlock = pindexNew; if (!pindexNew->CheckIndex()) { delete iterator; return error("LoadBlockIndex() : CheckIndex failed at %d", pindexNew->nHeight); } // ARbit: build setStakeSeen if (pindexNew->IsProofOfStake()) setStakeSeen.insert(make_pair(pindexNew->prevoutStake, pindexNew->nStakeTime)); iterator->Next(); } delete iterator; if (fRequestShutdown) return true; // Calculate nChainTrust vector<pair<int, CBlockIndex*> > vSortedByHeight; vSortedByHeight.reserve(mapBlockIndex.size()); BOOST_FOREACH(const PAIRTYPE(uint256, CBlockIndex*)& item, mapBlockIndex) { CBlockIndex* pindex = item.second; vSortedByHeight.push_back(make_pair(pindex->nHeight, pindex)); } sort(vSortedByHeight.begin(), vSortedByHeight.end()); BOOST_FOREACH(const PAIRTYPE(int, CBlockIndex*)& item, vSortedByHeight) { CBlockIndex* pindex = item.second; pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + pindex->GetBlockTrust(); // ARbit: calculate stake modifier checksum pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex); if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum)) return error("CTxDB::LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016"PRIx64, pindex->nHeight, pindex->nStakeModifier); } // Load hashBestChain pointer to end of best chain if (!ReadHashBestChain(hashBestChain)) { if (pindexGenesisBlock == NULL) return true; return error("CTxDB::LoadBlockIndex() : hashBestChain not loaded"); } if (!mapBlockIndex.count(hashBestChain)) return error("CTxDB::LoadBlockIndex() : hashBestChain not found in the block index"); pindexBest = mapBlockIndex[hashBestChain]; nBestHeight = pindexBest->nHeight; nBestChainTrust = pindexBest->nChainTrust; printf("LoadBlockIndex(): hashBestChain=%s height=%d trust=%s date=%s\n", hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); // ARbit: load hashSyncCheckpoint if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); // Load bnBestInvalidTrust, OK if it doesn't exist CBigNum bnBestInvalidTrust; ReadBestInvalidTrust(bnBestInvalidTrust); nBestInvalidTrust = bnBestInvalidTrust.getuint256(); // Verify blocks in the best chain int nCheckLevel = GetArg("-checklevel", 1); int nCheckDepth = GetArg( "-checkblocks", 2500); if (nCheckDepth == 0) nCheckDepth = 1000000000; // suffices until the year 19000 if (nCheckDepth > nBestHeight) nCheckDepth = nBestHeight; printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel); CBlockIndex* pindexFork = NULL; map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { if (fRequestShutdown || pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) return error("LoadBlockIndex() : block.ReadFromDisk failed"); // check level 1: verify block validity // check level 7: verify block signature too if (nCheckLevel>0 && !block.CheckBlock(true, true, (nCheckLevel>6))) { printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str()); pindexFork = pindex->pprev; } // check level 2: verify transaction index validity if (nCheckLevel>1) { pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos); mapBlockPos[pos] = pindex; BOOST_FOREACH(const CTransaction &tx, block.vtx) { uint256 hashTx = tx.GetHash(); CTxIndex txindex; if (ReadTxIndex(hashTx, txindex)) { // check level 3: checker transaction hashes if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos) { // either an error or a duplicate transaction CTransaction txFound; if (!txFound.ReadFromDisk(txindex.pos)) { printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } else if (txFound.GetHash() != hashTx) // not a duplicate tx { printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str()); pindexFork = pindex->pprev; } } // check level 4: check whether spent txouts were spent within the main chain unsigned int nOutput = 0; if (nCheckLevel>3) { BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent) { if (!txpos.IsNull()) { pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos); if (!mapBlockPos.count(posFind)) { printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str()); pindexFork = pindex->pprev; } // check level 6: check whether spent txouts were spent by a valid transaction that consume them if (nCheckLevel>5) { CTransaction txSpend; if (!txSpend.ReadFromDisk(txpos)) { printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else if (!txSpend.CheckTransaction()) { printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } else { bool fFound = false; BOOST_FOREACH(const CTxIn &txin, txSpend.vin) if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput) fFound = true; if (!fFound) { printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput); pindexFork = pindex->pprev; } } } } nOutput++; } } }
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, const CTransaction& txTo, unsigned int nIn, int nHashType) { CAutoBN_CTX pctx; CScript::const_iterator pc = script.begin(); CScript::const_iterator pend = script.end(); CScript::const_iterator pbegincodehash = script.begin(); opcodetype opcode; valtype vchPushValue; vector<bool> vfExec; vector<valtype> altstack; if (script.size() > 10000) return false; int nOpCount = 0; try { while (pc < pend) { bool fExec = !count(vfExec.begin(), vfExec.end(), false); // // Read instruction // if (!script.GetOp(pc, opcode, vchPushValue)) return false; if (vchPushValue.size() > 520) return false; if (opcode > OP_16 && ++nOpCount > 201) return false; if (opcode == OP_CAT || opcode == OP_SUBSTR || opcode == OP_LEFT || opcode == OP_RIGHT || opcode == OP_INVERT || opcode == OP_AND || opcode == OP_OR || opcode == OP_XOR || opcode == OP_2MUL || opcode == OP_2DIV || opcode == OP_MUL || opcode == OP_DIV || opcode == OP_MOD || opcode == OP_LSHIFT || opcode == OP_RSHIFT) return false; if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) stack.push_back(vchPushValue); else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) switch (opcode) { // // Push value // case OP_1NEGATE: case OP_1: case OP_2: case OP_3: case OP_4: case OP_5: case OP_6: case OP_7: case OP_8: case OP_9: case OP_10: case OP_11: case OP_12: case OP_13: case OP_14: case OP_15: case OP_16: { // ( -- value) CBigNum bn((int)opcode - (int)(OP_1 - 1)); stack.push_back(bn.getvch()); } break; // // Control // case OP_NOP: case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5: case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10: break; case OP_IF: case OP_NOTIF: { // <expression> if [statements] [else [statements]] endif bool fValue = false; if (fExec) { if (stack.size() < 1) return false; valtype& vch = stacktop(-1); fValue = CastToBool(vch); if (opcode == OP_NOTIF) fValue = !fValue; popstack(stack); } vfExec.push_back(fValue); } break; case OP_ELSE: { if (vfExec.empty()) return false; vfExec.back() = !vfExec.back(); } break; case OP_ENDIF: { if (vfExec.empty()) return false; vfExec.pop_back(); } break; case OP_VERIFY: { // (true -- ) or // (false -- false) and return if (stack.size() < 1) return false; bool fValue = CastToBool(stacktop(-1)); if (fValue) popstack(stack); else return false; } break; case OP_RETURN: { return false; } break; // // Stack ops // case OP_TOALTSTACK: { if (stack.size() < 1) return false; altstack.push_back(stacktop(-1)); popstack(stack); } break; case OP_FROMALTSTACK: { if (altstack.size() < 1) return false; stack.push_back(altstacktop(-1)); popstack(altstack); } break; case OP_2DROP: { // (x1 x2 -- ) if (stack.size() < 2) return false; popstack(stack); popstack(stack); } break; case OP_2DUP: { // (x1 x2 -- x1 x2 x1 x2) if (stack.size() < 2) return false; valtype vch1 = stacktop(-2); valtype vch2 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_3DUP: { // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) if (stack.size() < 3) return false; valtype vch1 = stacktop(-3); valtype vch2 = stacktop(-2); valtype vch3 = stacktop(-1); stack.push_back(vch1); stack.push_back(vch2); stack.push_back(vch3); } break; case OP_2OVER: { // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) if (stack.size() < 4) return false; valtype vch1 = stacktop(-4); valtype vch2 = stacktop(-3); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2ROT: { // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) if (stack.size() < 6) return false; valtype vch1 = stacktop(-6); valtype vch2 = stacktop(-5); stack.erase(stack.end()-6, stack.end()-4); stack.push_back(vch1); stack.push_back(vch2); } break; case OP_2SWAP: { // (x1 x2 x3 x4 -- x3 x4 x1 x2) if (stack.size() < 4) return false; swap(stacktop(-4), stacktop(-2)); swap(stacktop(-3), stacktop(-1)); } break; case OP_IFDUP: { // (x - 0 | x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); if (CastToBool(vch)) stack.push_back(vch); } break; case OP_DEPTH: { // -- stacksize CBigNum bn(stack.size()); stack.push_back(bn.getvch()); } break; case OP_DROP: { // (x -- ) if (stack.size() < 1) return false; popstack(stack); } break; case OP_DUP: { // (x -- x x) if (stack.size() < 1) return false; valtype vch = stacktop(-1); stack.push_back(vch); } break; case OP_NIP: { // (x1 x2 -- x2) if (stack.size() < 2) return false; stack.erase(stack.end() - 2); } break; case OP_OVER: { // (x1 x2 -- x1 x2 x1) if (stack.size() < 2) return false; valtype vch = stacktop(-2); stack.push_back(vch); } break; case OP_PICK: case OP_ROLL: { // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) if (stack.size() < 2) return false; int n = CastToBigNum(stacktop(-1)).getint(); popstack(stack); if (n < 0 || n >= stack.size()) return false; valtype vch = stacktop(-n-1); if (opcode == OP_ROLL) stack.erase(stack.end()-n-1); stack.push_back(vch); } break; case OP_ROT: { // (x1 x2 x3 -- x2 x3 x1) // x2 x1 x3 after first swap // x2 x3 x1 after second swap if (stack.size() < 3) return false; swap(stacktop(-3), stacktop(-2)); swap(stacktop(-2), stacktop(-1)); } break; case OP_SWAP: { // (x1 x2 -- x2 x1) if (stack.size() < 2) return false; swap(stacktop(-2), stacktop(-1)); } break; case OP_TUCK: { // (x1 x2 -- x2 x1 x2) if (stack.size() < 2) return false; valtype vch = stacktop(-1); stack.insert(stack.end()-2, vch); } break; // // Splice ops // case OP_CAT: { // (x1 x2 -- out) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); vch1.insert(vch1.end(), vch2.begin(), vch2.end()); popstack(stack); if (stacktop(-1).size() > 520) return false; } break; case OP_SUBSTR: { // (in begin size -- out) if (stack.size() < 3) return false; valtype& vch = stacktop(-3); int nBegin = CastToBigNum(stacktop(-2)).getint(); int nEnd = nBegin + CastToBigNum(stacktop(-1)).getint(); if (nBegin < 0 || nEnd < nBegin) return false; if (nBegin > vch.size()) nBegin = vch.size(); if (nEnd > vch.size()) nEnd = vch.size(); vch.erase(vch.begin() + nEnd, vch.end()); vch.erase(vch.begin(), vch.begin() + nBegin); popstack(stack); popstack(stack); } break; case OP_LEFT: case OP_RIGHT: { // (in size -- out) if (stack.size() < 2) return false; valtype& vch = stacktop(-2); int nSize = CastToBigNum(stacktop(-1)).getint(); if (nSize < 0) return false; if (nSize > vch.size()) nSize = vch.size(); if (opcode == OP_LEFT) vch.erase(vch.begin() + nSize, vch.end()); else vch.erase(vch.begin(), vch.end() - nSize); popstack(stack); } break; case OP_SIZE: { // (in -- in size) if (stack.size() < 1) return false; CBigNum bn(stacktop(-1).size()); stack.push_back(bn.getvch()); } break; // // Bitwise logic // case OP_INVERT: { // (in - out) if (stack.size() < 1) return false; valtype& vch = stacktop(-1); for (int i = 0; i < vch.size(); i++) vch[i] = ~vch[i]; } break; case OP_AND: case OP_OR: case OP_XOR: { // (x1 x2 - out) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); MakeSameSize(vch1, vch2); if (opcode == OP_AND) { for (int i = 0; i < vch1.size(); i++) vch1[i] &= vch2[i]; } else if (opcode == OP_OR) { for (int i = 0; i < vch1.size(); i++) vch1[i] |= vch2[i]; } else if (opcode == OP_XOR) { for (int i = 0; i < vch1.size(); i++) vch1[i] ^= vch2[i]; } popstack(stack); } break; case OP_EQUAL: case OP_EQUALVERIFY: //case OP_NOTEQUAL: // use OP_NUMNOTEQUAL { // (x1 x2 - bool) if (stack.size() < 2) return false; valtype& vch1 = stacktop(-2); valtype& vch2 = stacktop(-1); bool fEqual = (vch1 == vch2); // OP_NOTEQUAL is disabled because it would be too easy to say // something like n != 1 and have some wiseguy pass in 1 with extra // zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001) //if (opcode == OP_NOTEQUAL) // fEqual = !fEqual; popstack(stack); popstack(stack); stack.push_back(fEqual ? vchTrue : vchFalse); if (opcode == OP_EQUALVERIFY) { if (fEqual) popstack(stack); else return false; } } break; // // Numeric // case OP_1ADD: case OP_1SUB: case OP_2MUL: case OP_2DIV: case OP_NEGATE: case OP_ABS: case OP_NOT: case OP_0NOTEQUAL: { // (in -- out) if (stack.size() < 1) return false; CBigNum bn = CastToBigNum(stacktop(-1)); switch (opcode) { case OP_1ADD: bn += bnOne; break; case OP_1SUB: bn -= bnOne; break; case OP_2MUL: bn <<= 1; break; case OP_2DIV: bn >>= 1; break; case OP_NEGATE: bn = -bn; break; case OP_ABS: if (bn < bnZero) bn = -bn; break; case OP_NOT: bn = (bn == bnZero); break; case OP_0NOTEQUAL: bn = (bn != bnZero); break; default: assert(!"invalid opcode"); break; } popstack(stack); stack.push_back(bn.getvch()); } break; case OP_ADD: case OP_SUB: case OP_MUL: case OP_DIV: case OP_MOD: case OP_LSHIFT: case OP_RSHIFT: case OP_BOOLAND: case OP_BOOLOR: case OP_NUMEQUAL: case OP_NUMEQUALVERIFY: case OP_NUMNOTEQUAL: case OP_LESSTHAN: case OP_GREATERTHAN: case OP_LESSTHANOREQUAL: case OP_GREATERTHANOREQUAL: case OP_MIN: case OP_MAX: { // (x1 x2 -- out) if (stack.size() < 2) return false; CBigNum bn1 = CastToBigNum(stacktop(-2)); CBigNum bn2 = CastToBigNum(stacktop(-1)); CBigNum bn; switch (opcode) { case OP_ADD: bn = bn1 + bn2; break; case OP_SUB: bn = bn1 - bn2; break; case OP_MUL: if (!BN_mul(&bn, &bn1, &bn2, pctx)) return false; break; case OP_DIV: if (!BN_div(&bn, NULL, &bn1, &bn2, pctx)) return false; break; case OP_MOD: if (!BN_mod(&bn, &bn1, &bn2, pctx)) return false; break; case OP_LSHIFT: if (bn2 < bnZero || bn2 > CBigNum(2048)) return false; bn = bn1 << bn2.getulong(); break; case OP_RSHIFT: if (bn2 < bnZero || bn2 > CBigNum(2048)) return false; bn = bn1 >> bn2.getulong(); break; case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break; case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break; case OP_NUMEQUAL: bn = (bn1 == bn2); break; case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break; case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break; case OP_LESSTHAN: bn = (bn1 < bn2); break; case OP_GREATERTHAN: bn = (bn1 > bn2); break; case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break; case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break; case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break; case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break; default: assert(!"invalid opcode"); break; } popstack(stack); popstack(stack); stack.push_back(bn.getvch()); if (opcode == OP_NUMEQUALVERIFY) { if (CastToBool(stacktop(-1))) popstack(stack); else return false; } } break; case OP_WITHIN: { // (x min max -- out) if (stack.size() < 3) return false; CBigNum bn1 = CastToBigNum(stacktop(-3)); CBigNum bn2 = CastToBigNum(stacktop(-2)); CBigNum bn3 = CastToBigNum(stacktop(-1)); bool fValue = (bn2 <= bn1 && bn1 < bn3); popstack(stack); popstack(stack); popstack(stack); stack.push_back(fValue ? vchTrue : vchFalse); } break; // // Crypto // case OP_RIPEMD160: case OP_SHA1: case OP_SHA256: case OP_HASH160: case OP_HASH256: { // (in -- hash) if (stack.size() < 1) return false; valtype& vch = stacktop(-1); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); if (opcode == OP_RIPEMD160) RIPEMD160(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA1) SHA1(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_SHA256) SHA256(&vch[0], vch.size(), &vchHash[0]); else if (opcode == OP_HASH160) { uint160 hash160 = Hash160(vch); memcpy(&vchHash[0], &hash160, sizeof(hash160)); } else if (opcode == OP_HASH256) { uint256 hash = Hash(vch.begin(), vch.end()); memcpy(&vchHash[0], &hash, sizeof(hash)); } popstack(stack); stack.push_back(vchHash); } break; case OP_CODESEPARATOR: { // Hash starts after the code separator pbegincodehash = pc; } break; case OP_CHECKSIG: case OP_CHECKSIGVERIFY: { // (sig pubkey -- bool) if (stack.size() < 2) return false; valtype& vchSig = stacktop(-2); valtype& vchPubKey = stacktop(-1); ////// debug print //PrintHex(vchSig.begin(), vchSig.end(), "sig: %s\n"); //PrintHex(vchPubKey.begin(), vchPubKey.end(), "pubkey: %s\n"); // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signature, since there's no way for a signature to sign itself scriptCode.FindAndDelete(CScript(vchSig)); bool fSuccess = CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType); popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKSIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; case OP_CHECKMULTISIG: case OP_CHECKMULTISIGVERIFY: { // ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool) int i = 1; if (stack.size() < i) return false; int nKeysCount = CastToBigNum(stacktop(-i)).getint(); if (nKeysCount < 0 || nKeysCount > 20) return false; nOpCount += nKeysCount; if (nOpCount > 201) return false; int ikey = ++i; i += nKeysCount; if (stack.size() < i) return false; int nSigsCount = CastToBigNum(stacktop(-i)).getint(); if (nSigsCount < 0 || nSigsCount > nKeysCount) return false; int isig = ++i; i += nSigsCount; if (stack.size() < i) return false; // Subset of script starting at the most recent codeseparator CScript scriptCode(pbegincodehash, pend); // Drop the signatures, since there's no way for a signature to sign itself for (int k = 0; k < nSigsCount; k++) { valtype& vchSig = stacktop(-isig-k); scriptCode.FindAndDelete(CScript(vchSig)); } bool fSuccess = true; while (fSuccess && nSigsCount > 0) { valtype& vchSig = stacktop(-isig); valtype& vchPubKey = stacktop(-ikey); // Check signature if (CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)) { isig++; nSigsCount--; } ikey++; nKeysCount--; // If there are more signatures left than keys left, // then too many signatures have failed if (nSigsCount > nKeysCount) fSuccess = false; } while (i-- > 0) popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); if (opcode == OP_CHECKMULTISIGVERIFY) { if (fSuccess) popstack(stack); else return false; } } break; default: return false; } // Size limits if (stack.size() + altstack.size() > 1000) return false; } } catch (...) { return false; } if (!vfExec.empty()) return false; return true; }
static bool verify(const CBigNum& bignum, const CScriptNum& scriptnum) { return bignum.getvch() == scriptnum.getvch() && bignum.getint() == scriptnum.getint(); }
// Let's force this code not to be inlined, in order to actually // test a generic version of the function. This increases the chance // that -ftrapv will detect overflows. NOINLINE void mysetint64(CBigNum& num, int64_t n) { num.setint64(n); }
bool CreateCoinStake( CBlock &blocknew, CKey &key, vector<const CWalletTx*> &StakeInputs, uint64_t &CoinAge, CWallet &wallet, CBlockIndex* pindexPrev ) { int64_t CoinWeight; CBigNum StakeKernelHash; CTxDB txdb("r"); int64_t StakeWeightSum = 0; double StakeValueSum = 0; int64_t StakeWeightMin=MAX_MONEY; int64_t StakeWeightMax=0; uint64_t StakeCoinAgeSum=0; double StakeDiffSum = 0; double StakeDiffMax = 0; CTransaction &txnew = blocknew.vtx[1]; // second tx is coinstake //initialize the transaction txnew.nTime = blocknew.nTime & (~STAKE_TIMESTAMP_MASK); txnew.vin.clear(); txnew.vout.clear(); // Choose coins to use set <pair <const CWalletTx*,unsigned int> > CoinsToStake; int64_t BalanceToStake = wallet.GetBalance(); int64_t nValueIn = 0; //Request all the coins here, check reserve later if ( BalanceToStake<=0 || !wallet.SelectCoinsForStaking(BalanceToStake*2, txnew.nTime, CoinsToStake, nValueIn) ) { LOCK(MinerStatus.lock); MinerStatus.ReasonNotStaking+=_("No coins; "); if (fDebug) LogPrintf("CreateCoinStake: %s",MinerStatus.ReasonNotStaking); return false; } BalanceToStake -= nReserveBalance; if(fDebug2) LogPrintf("\nCreateCoinStake: Staking nTime/16= %d Bits= %u", txnew.nTime/16,blocknew.nBits); for(const auto& pcoin : CoinsToStake) { const CTransaction &CoinTx =*pcoin.first; //transaction that produced this coin unsigned int CoinTxN =pcoin.second; //index of this coin inside it CTxIndex txindex; { LOCK2(cs_main, wallet.cs_wallet); if (!txdb.ReadTxIndex(pcoin.first->GetHash(), txindex)) continue; //error? } CBlock CoinBlock; //Block which contains CoinTx { LOCK2(cs_main, wallet.cs_wallet); if (!CoinBlock.ReadFromDisk(txindex.pos.nFile, txindex.pos.nBlockPos, false)) continue; } // only count coins meeting min age requirement if (CoinBlock.GetBlockTime() + nStakeMinAge > txnew.nTime) continue; if (CoinTx.vout[CoinTxN].nValue > BalanceToStake) continue; { int64_t nStakeValue= CoinTx.vout[CoinTxN].nValue; StakeValueSum += nStakeValue /(double)COIN; //crazy formula... // todo: clean this // todo reuse calculated value for interst CBigNum bn = CBigNum(nStakeValue) * (blocknew.nTime-CoinTx.nTime) / CENT; bn = bn * CENT / COIN / (24 * 60 * 60); StakeCoinAgeSum += bn.getuint64(); } if(blocknew.nVersion==7) { NetworkTimer(); CoinWeight = CalculateStakeWeightV3(CoinTx,CoinTxN,GlobalCPUMiningCPID); StakeKernelHash= CalculateStakeHashV3(CoinBlock,CoinTx,CoinTxN,txnew.nTime,GlobalCPUMiningCPID,mdPORNonce); } else { uint64_t StakeModifier = 0; if(!FindStakeModifierRev(StakeModifier,pindexPrev)) continue; CoinWeight = CalculateStakeWeightV8(CoinTx,CoinTxN,GlobalCPUMiningCPID); StakeKernelHash= CalculateStakeHashV8(CoinBlock,CoinTx,CoinTxN,txnew.nTime,StakeModifier,GlobalCPUMiningCPID); } CBigNum StakeTarget; StakeTarget.SetCompact(blocknew.nBits); StakeTarget*=CoinWeight; StakeWeightSum += CoinWeight; StakeWeightMin=std::min(StakeWeightMin,CoinWeight); StakeWeightMax=std::max(StakeWeightMax,CoinWeight); double StakeKernelDiff = GetBlockDifficulty(StakeKernelHash.GetCompact())*CoinWeight; StakeDiffSum += StakeKernelDiff; StakeDiffMax = std::max(StakeDiffMax,StakeKernelDiff); if (fDebug2) { int64_t RSA_WEIGHT = GetRSAWeightByBlock(GlobalCPUMiningCPID); LogPrintf( "CreateCoinStake: V%d Time %.f, Por_Nonce %.f, Bits %jd, Weight %jd\n" " RSA_WEIGHT %.f\n" " Stk %72s\n" " Trg %72s\n" " Diff %0.7f of %0.7f\n", blocknew.nVersion, (double)txnew.nTime, mdPORNonce, (intmax_t)blocknew.nBits,(intmax_t)CoinWeight, (double)RSA_WEIGHT, StakeKernelHash.GetHex().c_str(), StakeTarget.GetHex().c_str(), StakeKernelDiff, GetBlockDifficulty(blocknew.nBits) ); } if( StakeKernelHash <= StakeTarget ) { // Found a kernel LogPrintf("\nCreateCoinStake: Found Kernel;\n"); blocknew.nNonce= mdPORNonce; vector<valtype> vSolutions; txnouttype whichType; CScript scriptPubKeyOut; CScript scriptPubKeyKernel; scriptPubKeyKernel = CoinTx.vout[CoinTxN].scriptPubKey; if (!Solver(scriptPubKeyKernel, whichType, vSolutions)) { LogPrintf("CreateCoinStake: failed to parse kernel\n"); break; } if (whichType == TX_PUBKEYHASH) // pay to address type { // convert to pay to public key type if (!wallet.GetKey(uint160(vSolutions[0]), key)) { LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key } scriptPubKeyOut << key.GetPubKey() << OP_CHECKSIG; } else if (whichType == TX_PUBKEY) // pay to public key type { valtype& vchPubKey = vSolutions[0]; if (!wallet.GetKey(Hash160(vchPubKey), key) || key.GetPubKey() != vchPubKey) { LogPrintf("CreateCoinStake: failed to get key for kernel type=%d\n", whichType); break; // unable to find corresponding public key } scriptPubKeyOut = scriptPubKeyKernel; } else { LogPrintf("CreateCoinStake: no support for kernel type=%d\n", whichType); break; // only support pay to public key and pay to address } txnew.vin.push_back(CTxIn(CoinTx.GetHash(), CoinTxN)); StakeInputs.push_back(pcoin.first); if (!txnew.GetCoinAge(txdb, CoinAge)) return error("CreateCoinStake: failed to calculate coin age"); int64_t nCredit = CoinTx.vout[CoinTxN].nValue; txnew.vout.push_back(CTxOut(0, CScript())); // First Must be empty txnew.vout.push_back(CTxOut(nCredit, scriptPubKeyOut)); //txnew.vout.push_back(CTxOut(0, scriptPubKeyOut)); LogPrintf("CreateCoinStake: added kernel type=%d credit=%f\n", whichType,CoinToDouble(nCredit)); LOCK(MinerStatus.lock); MinerStatus.KernelsFound++; MinerStatus.KernelDiffMax = 0; MinerStatus.KernelDiffSum = StakeDiffSum; return true; } } LOCK(MinerStatus.lock); MinerStatus.WeightSum = StakeWeightSum; MinerStatus.ValueSum = StakeValueSum; MinerStatus.WeightMin=StakeWeightMin; MinerStatus.WeightMax=StakeWeightMax; MinerStatus.CoinAgeSum=StakeCoinAgeSum; MinerStatus.KernelDiffMax = std::max(MinerStatus.KernelDiffMax,StakeDiffMax); MinerStatus.KernelDiffSum = StakeDiffSum; MinerStatus.nLastCoinStakeSearchInterval= txnew.nTime; return false; }
unsigned int RetargetGPU(const CBlockIndex* pindex, bool output) { /** Get the Last Block Index [1st block back in Channel]. **/ const CBlockIndex* pindexFirst = GetLastChannelIndex(pindex, 2); if (pindexFirst->pprev == NULL) return bnProofOfWorkStart[2].GetCompact(); /** Get Last Block Index [2nd block back in Channel]. **/ const CBlockIndex* pindexLast = GetLastChannelIndex(pindexFirst->pprev, 2); if (pindexLast->pprev == NULL) return bnProofOfWorkStart[2].GetCompact(); /** Get the Block Times with Minimum of 1 to Prevent Time Warps. **/ int64 nBlockTime = ((pindex->nVersion >= 4) ? GetWeightedTimes(pindexFirst, 5) : max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1)); int64 nBlockTarget = nTargetTimespan; /** Get the Chain Modular from Reserves. **/ double nChainMod = GetFractionalSubsidy(GetChainAge(pindexFirst->GetBlockTime()), 0, ((pindex->nVersion >= 3) ? 40.0 : 20.0)) / (pindexFirst->nReleasedReserve[0] + 1); nChainMod = min(nChainMod, 1.0); nChainMod = max(nChainMod, (pindex->nVersion == 1) ? 0.75 : 0.5); /** Enforce Block Version 2 Rule. Chain mod changes block time requirements, not actual mod after block times. **/ if(pindex->nVersion >= 2) nBlockTarget *= nChainMod; /** The Upper and Lower Bound Adjusters. **/ int64 nUpperBound = nBlockTarget; int64 nLowerBound = nBlockTarget; /** Handle for Version 3 Blocks. Mod determined by time multiplied by max / min. **/ if(pindex->nVersion >= 3) { /** If the time is above target, reduce difficulty by modular of one interval past timespan multiplied by maximum decrease. **/ if(nBlockTime >= nBlockTarget) { /** Take the Minimum overlap of Target Timespan to make that maximum interval. **/ uint64 nOverlap = (uint64)min((nBlockTime - nBlockTarget), (nBlockTarget * 2)); /** Get the Mod from the Proportion of Overlap in one Interval. **/ double nProportions = (double)nOverlap / (nBlockTarget * 2); /** Get Mod from Maximum Decrease Equation with Decimal portions multiplied by Propotions. **/ double nMod = 1.0 - (((pindex->nVersion >= 4) ? 0.15 : 0.75) * nProportions); nLowerBound = nBlockTarget * nMod; } /** If the time is below target, increase difficulty by modular of interval of 1 - Block Target with time of 1 being maximum increase **/ else { /** Get the overlap in reference from Target Timespan. **/ uint64 nOverlap = nBlockTarget - nBlockTime; /** Get the mod from overlap proportion. Time of 1 will be closest to mod of 1. **/ double nProportions = (double) nOverlap / nBlockTarget; /** Get the Mod from the Maximum Increase Equation with Decimal portion multiplied by Proportions. **/ double nMod = 1.0 + (nProportions * 0.075); nLowerBound = nBlockTarget * nMod; } } /** Handle for Version 2 Difficulty Adjustments. **/ else { double nBlockMod = (double) nBlockTarget / nBlockTime; nBlockMod = min(nBlockMod, 1.125); nBlockMod = max(nBlockMod, 0.75); /** Calculate the Lower Bounds. **/ nLowerBound = nBlockTarget * nBlockMod; /** Version 1 Blocks Change Lower Bound from Chain Modular. **/ if(pindex->nVersion == 1) nLowerBound *= nChainMod; /** Set Maximum [difficulty] up to 8%, and Minimum [difficulty] down to 50% **/ nLowerBound = min(nLowerBound, (int64)(nUpperBound + (nUpperBound / 8))); nLowerBound = max(nLowerBound, (3 * nUpperBound ) / 4); } /** Get the Difficulty Stored in Bignum Compact. **/ CBigNum bnNew; bnNew.SetCompact(pindexFirst->nBits); /** Change Number from Upper and Lower Bounds. **/ bnNew *= nUpperBound; bnNew /= nLowerBound; /** Don't allow Difficulty to decrease below minimum. **/ if (bnNew > bnProofOfWorkLimit[2]) bnNew = bnProofOfWorkLimit[2]; /** Console Output if Flagged. **/ if(output) { int64 nDays, nHours, nMinutes; GetChainTimes(GetChainAge(pindexFirst->GetBlockTime()), nDays, nHours, nMinutes); printf("RETARGET[GPU] weighted time=%"PRId64" actual time %"PRId64" [%f %%]\n\tchain time: [%"PRId64" / %"PRId64"]\n\treleased reward: %"PRId64" [%f %%]\n\tdifficulty: [%f to %f]\n\tGPU height: %"PRId64" [AGE %"PRId64" days, %"PRId64" hours, %"PRId64" minutes]\n\n", nBlockTime, max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1), (100.0 * nLowerBound) / nUpperBound, nBlockTarget, nBlockTime, pindexFirst->nReleasedReserve[0] / COIN, 100.0 * nChainMod, GetDifficulty(pindexFirst->nBits, 2), GetDifficulty(bnNew.GetCompact(), 2), pindexFirst->nChannelHeight, nDays, nHours, nMinutes); } return bnNew.GetCompact(); }
/** Proof of Stake Retargeting: Modulate Difficulty based on production rate. **/ unsigned int RetargetPOS(const CBlockIndex* pindex, bool output) { /** Get Last Block Index [1st block back in Channel]. **/ const CBlockIndex* pindexFirst = GetLastChannelIndex(pindex, 0); if (pindexFirst->pprev == NULL) return bnProofOfWorkStart[0].GetCompact(); /** Get Last Block Index [2nd block back in Channel]. **/ const CBlockIndex* pindexLast = GetLastChannelIndex(pindexFirst->pprev, 0); if (pindexLast->pprev == NULL) return bnProofOfWorkStart[0].GetCompact(); /** Get the Block Time and Target Spacing. **/ int64 nBlockTime = GetWeightedTimes(pindexFirst, 5); int64 nBlockTarget = STAKE_TARGET_SPACING; /** The Upper and Lower Bound Adjusters. **/ int64 nUpperBound = nBlockTarget; int64 nLowerBound = nBlockTarget; /** If the time is above target, reduce difficulty by modular of one interval past timespan multiplied by maximum decrease. **/ if(nBlockTime >= nBlockTarget) { /** Take the Minimum overlap of Target Timespan to make that maximum interval. **/ uint64 nOverlap = (uint64)min((nBlockTime - nBlockTarget), (nBlockTarget * 2)); /** Get the Mod from the Proportion of Overlap in one Interval. **/ double nProportions = (double)nOverlap / (nBlockTarget * 2); /** Get Mod from Maximum Decrease Equation with Decimal portions multiplied by Propotions. **/ double nMod = 1.0 - (0.15 * nProportions); nLowerBound = nBlockTarget * nMod; } /** If the time is below target, increase difficulty by modular of interval of 1 - Block Target with time of 1 being maximum increase **/ else { /** Get the overlap in reference from Target Timespan. **/ uint64 nOverlap = nBlockTarget - nBlockTime; /** Get the mod from overlap proportion. Time of 1 will be closest to mod of 1. **/ double nProportions = (double) nOverlap / nBlockTarget; /** Get the Mod from the Maximum Increase Equation with Decimal portion multiplied by Proportions. **/ double nMod = 1.0 + (nProportions * 0.075); nLowerBound = nBlockTarget * nMod; } /** Get the Difficulty Stored in Bignum Compact. **/ CBigNum bnNew; bnNew.SetCompact(pindexFirst->nBits); /** Change Number from Upper and Lower Bounds. **/ bnNew *= nUpperBound; bnNew /= nLowerBound; /** Don't allow Difficulty to decrease below minimum. **/ if (bnNew > bnProofOfWorkLimit[0]) bnNew = bnProofOfWorkLimit[0]; if(output) { int64 nDays, nHours, nMinutes; GetChainTimes(GetChainAge(pindexFirst->GetBlockTime()), nDays, nHours, nMinutes); printf("CHECK[POS] weighted time=%"PRId64" actual time =%"PRId64"[%f %%]\n\tchain time: [%"PRId64" / %"PRId64"]\n\tdifficulty: [%f to %f]\n\tPOS height: %"PRId64" [AGE %"PRId64" days, %"PRId64" hours, %"PRId64" minutes]\n\n", nBlockTime, max(pindexFirst->GetBlockTime() - pindexLast->GetBlockTime(), (int64) 1), ((100.0 * nLowerBound) / nUpperBound), nBlockTarget, nBlockTime, GetDifficulty(pindexFirst->nBits, 0), GetDifficulty(bnNew.GetCompact(), 0), pindexFirst->nChannelHeight, nDays, nHours, nMinutes); } return bnNew.GetCompact(); }