bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const { CDiskTxPos postx; if (!m_db->ReadTxPos(tx_hash, postx)) { return false; } CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION); if (file.IsNull()) { return error("%s: OpenBlockFile failed", __func__); } CBlockHeader header; try { file >> header; if (fseek(file.Get(), postx.nTxOffset, SEEK_CUR)) { return error("%s: fseek(...) failed", __func__); } file >> tx; } catch (const std::exception& e) { return error("%s: Deserialize or I/O error - %s", __func__, e.what()); } if (tx->GetHash() != tx_hash) { return error("%s: txid mismatch", __func__); } block_hash = header.GetHash(); return true; }
CWalletTx& AddTx(CRecipient recipient) { CTransactionRef tx; CReserveKey reservekey(wallet.get()); CAmount fee; int changePos = -1; std::string error; CCoinControl dummy; BOOST_CHECK(wallet->CreateTransaction({recipient}, tx, reservekey, fee, changePos, error, dummy)); CValidationState state; BOOST_CHECK(wallet->CommitTransaction(tx, {}, {}, reservekey, nullptr, state)); CMutableTransaction blocktx; { LOCK(wallet->cs_wallet); blocktx = CMutableTransaction(*wallet->mapWallet.at(tx->GetHash()).tx); } CreateAndProcessBlock({CMutableTransaction(blocktx)}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())); LOCK(wallet->cs_wallet); auto it = wallet->mapWallet.find(tx->GetHash()); BOOST_CHECK(it != wallet->mapWallet.end()); it->second.SetMerkleBranch(chainActive.Tip(), 1); return it->second; }
void CreateCreditAndSpend(const CKeyStore& keystore, const CScript& outscript, CTransactionRef& output, CMutableTransaction& input, bool success = true) { CMutableTransaction outputm; outputm.nVersion = 1; outputm.vin.resize(1); outputm.vin[0].prevout.SetNull(); outputm.vin[0].scriptSig = CScript(); outputm.vout.resize(1); outputm.vout[0].nValue = 1; outputm.vout[0].scriptPubKey = outscript; CDataStream ssout(SER_NETWORK, PROTOCOL_VERSION); ssout << outputm; ssout >> output; assert(output->vin.size() == 1); assert(output->vin[0] == outputm.vin[0]); assert(output->vout.size() == 1); assert(output->vout[0] == outputm.vout[0]); CMutableTransaction inputm; inputm.nVersion = 1; inputm.vin.resize(1); inputm.vin[0].prevout.hash = output->GetHash(); inputm.vin[0].prevout.n = 0; inputm.vout.resize(1); inputm.vout[0].nValue = 1; inputm.vout[0].scriptPubKey = CScript(); bool ret = SignSignature(keystore, *output, inputm, 0, SIGHASH_ALL); assert(ret == success); CDataStream ssin(SER_NETWORK, PROTOCOL_VERSION); ssin << inputm; ssin >> input; assert(input.vin.size() == 1); assert(input.vin[0] == inputm.vin[0]); assert(input.vout.size() == 1); assert(input.vout[0] == inputm.vout[0]); assert(input.vin[0].scriptWitness.stack == inputm.vin[0].scriptWitness.stack); }
bool CMempoolComponent::LoadMempool(void) { const CChainParams &chainparams = Params(); int64_t nExpiryTimeout = Args().GetArg<uint32_t>("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY) * 60 * 60; FILE *filestr = fsbridge::fopen(Args().GetDataDir() / "mempool.dat", "rb"); CAutoFile file(filestr, SER_DISK, CLIENT_VERSION); if (file.IsNull()) { return rLogError("Failed to open mempool file from disk. Continuing anyway"); } int64_t count = 0; int64_t skipped = 0; int64_t failed = 0; int64_t nNow = GetTime(); try { uint64_t version; file >> version; if (version != MEMPOOL_DUMP_VERSION) { return false; } uint64_t num; file >> num; while (num--) { CTransactionRef tx; int64_t nTime; int64_t nFeeDelta; file >> tx; file >> nTime; file >> nFeeDelta; CAmount amountdelta = nFeeDelta; if (amountdelta) { mempool.PrioritiseTransaction(tx->GetHash(), amountdelta); } CValidationState state; if (nTime + nExpiryTimeout > nNow) { LOCK(cs); mempool.AcceptToMemoryPoolWithTime(chainparams, state, tx, true, nullptr, nTime, nullptr, false, 0); if (state.IsValid()) { ++count; } else { ++failed; } } else { ++skipped; } if (GetApp()->ShutdownRequested()) return false; } std::map<uint256, CAmount> mapDeltas; file >> mapDeltas; for (const auto &i : mapDeltas) { mempool.PrioritiseTransaction(i.first, i.second); } } catch (const std::exception &e) { return rLogError("Failed to deserialize mempool data on disk: %s. Continuing anyway", e.what()); } NLogFormat("Imported mempool transactions from disk: %i successes, %i failed, %i expired", count, failed, skipped); return true; }
bool CGovernanceObject::IsCollateralValid(std::string& strError, bool& fMissingConfirmations) const { strError = ""; fMissingConfirmations = false; CAmount nMinFee = GetMinCollateralFee(); uint256 nExpectedHash = GetHash(); CTransactionRef txCollateral; uint256 nBlockHash; // RETRIEVE TRANSACTION IN QUESTION if (!GetTransaction(nCollateralHash, txCollateral, Params().GetConsensus(), nBlockHash, true)) { strError = strprintf("Can't find collateral tx %s", nCollateralHash.ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } if (nBlockHash == uint256()) { strError = strprintf("Collateral tx %s is not mined yet", txCollateral->ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } if (txCollateral->vout.size() < 1) { strError = strprintf("tx vout size less than 1 | %d", txCollateral->vout.size()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } // LOOK FOR SPECIALIZED GOVERNANCE SCRIPT (PROOF OF BURN) CScript findScript; findScript << OP_RETURN << ToByteVector(nExpectedHash); LogPrint("gobject", "CGovernanceObject::IsCollateralValid -- txCollateral->vout.size() = %s, findScript = %s, nMinFee = %lld\n", txCollateral->vout.size(), ScriptToAsmStr(findScript, false), nMinFee); bool foundOpReturn = false; for (const auto& output : txCollateral->vout) { LogPrint("gobject", "CGovernanceObject::IsCollateralValid -- txout = %s, output.nValue = %lld, output.scriptPubKey = %s\n", output.ToString(), output.nValue, ScriptToAsmStr(output.scriptPubKey, false)); if (!output.scriptPubKey.IsPayToPublicKeyHash() && !output.scriptPubKey.IsUnspendable()) { strError = strprintf("Invalid Script %s", txCollateral->ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } if (output.scriptPubKey == findScript && output.nValue >= nMinFee) { foundOpReturn = true; } } if (!foundOpReturn) { strError = strprintf("Couldn't find opReturn %s in %s", nExpectedHash.ToString(), txCollateral->ToString()); LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } // GET CONFIRMATIONS FOR TRANSACTION AssertLockHeld(cs_main); int nConfirmationsIn = 0; if (nBlockHash != uint256()) { BlockMap::iterator mi = mapBlockIndex.find(nBlockHash); if (mi != mapBlockIndex.end() && (*mi).second) { CBlockIndex* pindex = (*mi).second; if (chainActive.Contains(pindex)) { nConfirmationsIn += chainActive.Height() - pindex->nHeight + 1; } } } if ((nConfirmationsIn < GOVERNANCE_FEE_CONFIRMATIONS) && (!instantsend.IsLockedInstantSendTransaction(nCollateralHash) || llmq::quorumInstantSendManager->IsLocked(nCollateralHash))) { strError = strprintf("Collateral requires at least %d confirmations to be relayed throughout the network (it has only %d)", GOVERNANCE_FEE_CONFIRMATIONS, nConfirmationsIn); if (nConfirmationsIn >= GOVERNANCE_MIN_RELAY_FEE_CONFIRMATIONS) { fMissingConfirmations = true; strError += ", pre-accepted -- waiting for required confirmations"; } else { strError += ", rejected -- try again later"; } LogPrintf("CGovernanceObject::IsCollateralValid -- %s\n", strError); return false; } strError = "valid"; return true; }