/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx, bool fBurnMint) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if(showTransaction(wtx)) { if(fBurnMint && wtx.IsCoinBase()) parts.append(TransactionRecord(hash, nTime, TransactionRecord::BurnMint, "", -nDebit, wtx.GetValueOut())); else if(wtx.IsCoinStake()) // heat: coinstake transaction parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut())); else if(nNet > 0 || wtx.IsCoinBase()) { // // Credit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CBitcoinAddress address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if(wtx.IsCoinBase()) { // Generated by mining sub.type = TransactionRecord::Generated; } else if(ExtractAddress(txout.scriptPubKey, address) && wallet->HaveKey(address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = address.ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } parts.append(sub); } } } else {
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if (showTransaction(wtx)) { if (wtx.IsCoinStake()) // ppcoin: coinstake transaction { int64 showCredit = wtx.GetValueOut(); BOOST_FOREACH(const PAIRTYPE(const uint256, CWalletTx)& hash_tx, wallet->mapWallet) { const CWalletTx &otherTx = hash_tx.second; if (otherTx.hashBlock == wtx.hashBlock && otherTx.IsCoinBase()) { showCredit += otherTx.GetValueOut(); break; } } parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, showCredit)); } else if (nNet > 0 || wtx.IsCoinBase())
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(true); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; char cbuf[256]; if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake()) { // // Credit // for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by CannabisDarkcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CCannabisDarkcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; } if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; } parts.append(sub); } } } else { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) fAllFromMe = fAllFromMe && wallet->IsMine(txin); bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) fAllToMe = fAllToMe && wallet->IsMine(txout); if (fAllFromMe && fAllToMe) { // Payment to self int64_t nChange = wtx.GetChange(); std::string narration(""); mapValue_t::const_iterator mi; for (mi = wtx.mapValue.begin(); mi != wtx.mapValue.end(); ++mi) { if (mi->first.compare(0, 2, "n_") != 0) continue; narration = mi->second; break; }; parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", narration, -(nDebit - nChange), nCredit - nChange)); } else if (fAllFromMe) { // // Debit // int64_t nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to CannabisDarkcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CCannabisDarkcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", "", nNet, 0)); } } return parts; }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(true); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake()) { // // Credit - Calculate Net from CryptoLottery Rob Halford - 4-3-2015-1 // for (auto const& txout : wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; } if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output if (wtx.vout.size()==2) { //Standard POR CoinStake sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; } else { //CryptoLottery - CoinStake - 4-3-2015 sub.type = TransactionRecord::Generated; if (nDebit == 0) { sub.credit = GetMyValueOut(wallet,wtx); sub.RemoteFlag = 1; } else { sub.credit = nNet > 0 ? nNet : GetMyValueOut(wallet,wtx) - nDebit; } hashPrev = hash; } } parts.append(sub); } } } else { bool fAllFromMe = true; for (auto const& txin : wtx.vin) fAllFromMe = fAllFromMe && wallet->IsMine(txin); bool fAllToMe = true; for (auto const& txout : wtx.vout) fAllToMe = fAllToMe && wallet->IsMine(txout); if (fAllFromMe && fAllToMe) { // Payment to self int64_t nChange = wtx.GetChange(); parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); } else if (fAllFromMe) { // // Debit // int64_t nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); } } return parts; }
/** * @brief flush all log records to the file */ void WriteBehindFrontendLogger::FlushLogRecords(void) { std::vector<txn_id_t> committed_txn_list; std::vector<txn_id_t> not_committed_txn_list; std::set<oid_t> modified_tile_group_set; //===--------------------------------------------------------------------===// // Collect the log records //===--------------------------------------------------------------------===// for (auto record : global_queue) { switch (record->GetType()) { case LOGRECORD_TYPE_TRANSACTION_BEGIN: global_peloton_log_record_pool.CreateTransactionLogList( record->GetTransactionId()); break; case LOGRECORD_TYPE_TRANSACTION_COMMIT: committed_txn_list.push_back(record->GetTransactionId()); break; case LOGRECORD_TYPE_TRANSACTION_ABORT: // Nothing to be done for abort break; case LOGRECORD_TYPE_TRANSACTION_END: case LOGRECORD_TYPE_TRANSACTION_DONE: // if a txn is not committed (aborted or active), log records will be // removed here // Note that list is not be removed immediately, it is removed only // after flush and commit. not_committed_txn_list.push_back(record->GetTransactionId()); break; case LOGRECORD_TYPE_WBL_TUPLE_INSERT: case LOGRECORD_TYPE_WBL_TUPLE_DELETE: case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: { // Check the commit information, auto status = CollectTupleRecord(reinterpret_cast<TupleRecord *>(record)); // Delete record if we did not collect it if (status.first == false) { delete record; } // Else, add it to the set of modified tile groups else { auto location = status.second.block; if (location != INVALID_OID) modified_tile_group_set.insert(location); } } break; case LOGRECORD_TYPE_INVALID: default: throw Exception("Invalid or unrecogized log record found"); break; } } // Clear the global queue global_queue.clear(); //===--------------------------------------------------------------------===// // Write out the log records //===--------------------------------------------------------------------===// // If committed txn list is not empty if (committed_txn_list.empty() == false) { //===--------------------------------------------------------------------===// // SYNC 1: Sync the TGs //===--------------------------------------------------------------------===// SyncTileGroups(modified_tile_group_set); //===--------------------------------------------------------------------===// // SYNC 2: Sync the log for TXN COMMIT record //===--------------------------------------------------------------------===// // Write out all the committed log records size_t written_log_record_count = WriteLogRecords(committed_txn_list); // Now, write a committing log entry to file // Piggyback the number of written log records as a "txn_id" in this record WriteTransactionLogRecord(TransactionRecord( LOGRECORD_TYPE_TRANSACTION_COMMIT, written_log_record_count)); //===--------------------------------------------------------------------===// // SYNC 3: Sync the changes to TG headers //===--------------------------------------------------------------------===// // Toggle the commit marks auto tile_group_header_set = ToggleCommitMarks(committed_txn_list); // Sync the TG headers SyncTileGroupHeaders(tile_group_header_set); //===--------------------------------------------------------------------===// // SYNC 4 : Sync the log for TXN DONE record //===--------------------------------------------------------------------===// // Write out a transaction done log record to file WriteTransactionLogRecord( TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE)); } //===--------------------------------------------------------------------===// // Clean up finished transaction log lists //===--------------------------------------------------------------------===// // remove any finished txn logs for (txn_id_t txn_id : not_committed_txn_list) { global_peloton_log_record_pool.RemoveTransactionLogList(txn_id); } // Notify the backend loggers { std::lock_guard<std::mutex> lock(backend_logger_mutex); for (auto backend_logger : backend_loggers) { backend_logger->Commit(); } } }
/** * @brief Recovery system based on log file */ void WriteBehindFrontendLogger::DoRecovery() { // Set log file size log_file_size = GetLogFileSize(log_file_fd); // Go over the log size if needed if (log_file_size > 0) { bool reached_end_of_file = false; // check whether first item is LOGRECORD_TYPE_TRANSACTION_COMMIT // if not, no need to do recovery. // if yes, need to replay all log records before we hit // LOGRECORD_TYPE_TRANSACTION_DONE bool need_recovery = NeedRecovery(); if (need_recovery == true) { TransactionRecord dummy_transaction_record(LOGRECORD_TYPE_INVALID); cid_t current_commit_id = INVALID_CID; // Go over each log record in the log file while (reached_end_of_file == false) { // Read the first byte to identify log record type // If that is not possible, then wrap up recovery LogRecordType log_type = GetNextLogRecordType(log_file, log_file_size); switch (log_type) { case LOGRECORD_TYPE_TRANSACTION_DONE: case LOGRECORD_TYPE_TRANSACTION_COMMIT: { // read but do nothing ReadTransactionRecordHeader(dummy_transaction_record, log_file, log_file_size); } break; case LOGRECORD_TYPE_WBL_TUPLE_INSERT: { TupleRecord insert_record(LOGRECORD_TYPE_WBL_TUPLE_INSERT); ReadTupleRecordHeader(insert_record, log_file, log_file_size); auto insert_location = insert_record.GetInsertLocation(); auto info = SetInsertCommitMark(insert_location); current_commit_id = info.first; } break; case LOGRECORD_TYPE_WBL_TUPLE_DELETE: { TupleRecord delete_record(LOGRECORD_TYPE_WBL_TUPLE_DELETE); ReadTupleRecordHeader(delete_record, log_file, log_file_size); auto delete_location = delete_record.GetDeleteLocation(); auto info = SetDeleteCommitMark(delete_location); current_commit_id = info.first; } break; case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: { TupleRecord update_record(LOGRECORD_TYPE_WBL_TUPLE_UPDATE); ReadTupleRecordHeader(update_record, log_file, log_file_size); auto delete_location = update_record.GetDeleteLocation(); SetDeleteCommitMark(delete_location); auto insert_location = update_record.GetInsertLocation(); auto info = SetInsertCommitMark(insert_location); current_commit_id = info.first; } break; default: reached_end_of_file = true; break; } } // Update latest commit id if (latest_commit_id < current_commit_id) { latest_commit_id = current_commit_id; } // write out a trasaction done log record to file // to avoid redo next time during recovery WriteTransactionLogRecord( TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE)); } // After finishing recovery, set the next oid with maximum oid // observed during the recovery auto &manager = catalog::Manager::GetInstance(); manager.SetNextOid(max_oid); } }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredMOIN, nCredMoinX; wtx.GetCredit(nCredMOIN, nCredMoinX, true); int64_t nCredit = nCredMOIN + nCredMoinX; int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; char cbuf[256]; if (wtx.nVersion == ANON_TXN_VERSION) { if (nNet > 0 && nCredMoinX > 0) { // -- credit TransactionRecord sub(hash, nTime, TransactionRecord::RecvMoinX, "", "", nNet, 0); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) { sub.narration = mi->second; break; }; }; parts.append(sub); return parts; } else if (nNet <= 0) { // -- debit TransactionRecord sub(hash, nTime, TransactionRecord::SendMoinX, "", "", nNet, 0); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) { sub.narration = mi->second; break; } }; parts.append(sub); return parts; }; // continue on }; if (nNet > 0 || wtx.IsCoinBase() || wtx.IsCoinStake()) { // // Credit // for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { const CScript &s = txout.scriptPubKey; CKeyID ckidD = CPubKey(&s[2+1], 33).GetID(); if (wallet->HaveKey(ckidD)) { TransactionRecord sub(hash, nTime); sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; sub.type = TransactionRecord::RecvMoinX; sub.address = CBitcoinAddress(ckidD).ToString(); //sub.address = wallet->mapAddressBook[ckidD] snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; parts.append(sub); }; }; if (wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); sub.idx = parts.size(); // sequence number CTxDestination address; sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsDestMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; }; if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; }; parts.append(sub); } } } else { bool fAllFromMe = true; BOOST_FOREACH(const CTxIn& txin, wtx.vin) { if (wtx.nVersion == ANON_TXN_VERSION && txin.IsAnonInput()) { std::vector<uint8_t> vchImage; txin.ExtractKeyImage(vchImage); CWalletDB walletdb(wallet->strWalletFile, "r"); COwnedAnonOutput oao; if (!walletdb.ReadOwnedAnonOutput(vchImage, oao)) { fAllFromMe = false; break; // display as send/recv moinx }; continue; }; if (wallet->IsMine(txin)) continue; fAllFromMe = false; break; }; bool fAllToMe = true; BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { fAllToMe = false; break; // display as send/recv moinx } opcodetype firstOpCode; CScript::const_iterator pc = txout.scriptPubKey.begin(); if (txout.scriptPubKey.GetOp(pc, firstOpCode) && firstOpCode == OP_RETURN) continue; if (wallet->IsMine(txout)) continue; fAllToMe = false; break; }; if (fAllFromMe && fAllToMe) { // Payment to self int64_t nChange = wtx.GetChange(); std::string narration(""); mapValue_t::const_iterator mi; for (mi = wtx.mapValue.begin(); mi != wtx.mapValue.end(); ++mi) { if (mi->first.compare(0, 2, "n_") != 0) continue; narration = mi->second; break; }; parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", narration, -(nDebit - nChange), nCredit - nChange)); } else if (fAllFromMe) { // // Debit // int64_t nTxFee = nDebit - wtx.GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { const CTxOut& txout = wtx.vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); if (wtx.nVersion == ANON_TXN_VERSION && txout.IsAnonOutput()) { const CScript &s = txout.scriptPubKey; CKeyID ckidD = CPubKey(&s[2+1], 33).GetID(); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; sub.type = TransactionRecord::SendMoinX; sub.address = CBitcoinAddress(ckidD).ToString(); } else { opcodetype firstOpCode; CScript::const_iterator pc = txout.scriptPubKey.begin(); if (txout.scriptPubKey.GetOp(pc, firstOpCode) && firstOpCode == OP_RETURN) continue; if (wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } }; snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; int64_t nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // TransactionRecord sub(hash, nTime, TransactionRecord::Other, "", "", nNet, 0); /* for (unsigned int nOut = 0; nOut < wtx.vout.size(); nOut++) { // display 1st transaction snprintf(cbuf, sizeof(cbuf), "n_%u", nOut); mapValue_t::const_iterator mi = wtx.mapValue.find(cbuf); if (mi != wtx.mapValue.end() && !mi->second.empty()) sub.narration = mi->second; break; }; */ parts.append(sub); } } return parts; }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); int64 nDebit = wtx.GetDebit(); int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; const bool combineOutputs = (wtx.cUnit == 'S'); if (wtx.IsCoinStake()) // ppcoin: coinstake transaction { parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut())); } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // QMap<CScript, TransactionRecord*> outputParts; BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { if (wtx.IsUnpark()) sub.type = TransactionRecord::Unpark; else // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address, wtx.cUnit).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; } if (combineOutputs) { QMap<CScript, TransactionRecord*>::const_iterator it = outputParts.find(txout.scriptPubKey); if (it != outputParts.end()) { TransactionRecord& previous = *it.value(); previous.credit += sub.credit; continue; } } parts.append(sub); if (combineOutputs) outputParts[txout.scriptPubKey] = &parts.back(); } } }
/** * @brief flush all log records to the file */ void WriteBehindFrontendLogger::FlushLogRecords(void) { std::vector<txn_id_t> committed_txn_list; std::vector<txn_id_t> not_committed_txn_list; std::set<oid_t> modified_tile_group_set; //===--------------------------------------------------------------------===// // Collect the log records //===--------------------------------------------------------------------===// size_t global_queue_size = global_queue.size(); for (oid_t global_queue_itr = 0; global_queue_itr < global_queue_size; global_queue_itr++) { if (global_queue[global_queue_itr] == nullptr) { continue; } // FIXME change the interface of write behind logging // switch (global_queue[global_queue_itr]->GetType()) { // case LOGRECORD_TYPE_TRANSACTION_BEGIN: // global_peloton_log_record_pool.CreateTxnLogList( // global_queue[global_queue_itr]->GetTransactionId()); // break; // // case LOGRECORD_TYPE_TRANSACTION_COMMIT: // committed_txn_list.push_back( // global_queue[global_queue_itr]->GetTransactionId()); // break; // // case LOGRECORD_TYPE_TRANSACTION_ABORT: // // Nothing to be done for abort // break; // // case LOGRECORD_TYPE_TRANSACTION_END: // case LOGRECORD_TYPE_TRANSACTION_DONE: // // if a txn is not committed (aborted or active), log records will // be // // removed here // // Note that list is not be removed immediately, it is removed // only // // after flush and commit. // not_committed_txn_list.push_back( // global_queue[global_queue_itr]->GetTransactionId()); // break; // // case LOGRECORD_TYPE_WBL_TUPLE_INSERT: // case LOGRECORD_TYPE_WBL_TUPLE_DELETE: // case LOGRECORD_TYPE_WBL_TUPLE_UPDATE: { // // LogRecord* log_record = global_queue[global_queue_itr].release(); // TupleRecord* tuple_record = // reinterpret_cast<TupleRecord*>(log_record); // // // Check the commit information // auto status = // CollectTupleRecord(std::unique_ptr<TupleRecord>(tuple_record)); // // // Add it to the set of modified tile groups // if (status.first == true) { // auto location = status.second.block; // if (location != INVALID_OID) { // modified_tile_group_set.insert(location); // } // } // // } break; // // case LOGRECORD_TYPE_INVALID: // default: // throw Exception("Invalid or unrecogized log record found"); // break; // } } // Clean up the frontend logger's queue global_queue.clear(); //===--------------------------------------------------------------------===// // Write out the log records //===--------------------------------------------------------------------===// // If committed txn list is not empty if (committed_txn_list.empty() == false) { //===--------------------------------------------------------------------===// // SYNC 1: Sync the TGs //===--------------------------------------------------------------------===// SyncTileGroups(modified_tile_group_set); //===--------------------------------------------------------------------===// // SYNC 2: Sync the log for TXN COMMIT record //===--------------------------------------------------------------------===// // Write out all the committed log records size_t written_log_record_count = WriteLogRecords(committed_txn_list); // Now, write a committing log entry to file // Piggyback the number of written log records as a "txn_id" in this record WriteTransactionLogRecord(TransactionRecord( LOGRECORD_TYPE_TRANSACTION_COMMIT, written_log_record_count)); //===--------------------------------------------------------------------===// // SYNC 3: Sync the changes to TG headers //===--------------------------------------------------------------------===// // Toggle the commit marks auto tile_group_header_set = ToggleCommitMarks(committed_txn_list); // Sync the TG headers SyncTileGroupHeaders(tile_group_header_set); //===--------------------------------------------------------------------===// // SYNC 4 : Sync the log for TXN DONE record //===--------------------------------------------------------------------===// // Write out a transaction done log record to file WriteTransactionLogRecord( TransactionRecord(LOGRECORD_TYPE_TRANSACTION_DONE)); } //===--------------------------------------------------------------------===// // Clean up finished transaction log lists //===--------------------------------------------------------------------===// // remove any finished txn logs for (txn_id_t txn_id : not_committed_txn_list) { global_peloton_log_record_pool.RemoveTxnLogRecordList(txn_id); } // Notify the backend loggers // { // for (auto backend_logger : backend_loggers) { // // FIXME // assert(backend_logger); // // backend_logger->FinishedFlushing(); // } // } }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); int64_t nCredit = wtx.GetCredit(true); int64_t nDebit = wtx.GetDebit(); int64_t nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(), hashPrev = 0; std::map<std::string, std::string> mapValue = wtx.mapValue; if (wtx.IsCoinStake()) { TransactionRecord txrCoinStake = TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut()); CTxDestination address; if (ExtractDestination(wtx.vout[1].scriptPubKey, address)) { txrCoinStake.address = CBitcoinAddress(address).ToString(); } // Stake generation parts.append(txrCoinStake); } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { if(wallet->IsMine(txout)) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated (proof-of-work) sub.type = TransactionRecord::Generated; } if (wtx.IsCoinStake()) { // Generated (proof-of-stake) if (hashPrev == hash) continue; // last coinstake output sub.type = TransactionRecord::Generated; sub.credit = nNet > 0 ? nNet : wtx.GetValueOut() - nDebit; hashPrev = hash; } parts.append(sub); } } }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interfaces::WalletTx& wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.time; CAmount nCredit = wtx.credit; CAmount nDebit = wtx.debit; CAmount nNet = nCredit - nDebit; uint256 hash = wtx.tx->GetHash(); std::map<std::string, std::string> mapValue = wtx.value_map; if (nNet > 0 || wtx.is_coinbase) { // // Credit // for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) { const CTxOut& txout = wtx.tx->vout[i]; isminetype mine = wtx.txout_is_mine[i]; if(mine) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = i; // vout index sub.credit = txout.nValue; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; if (wtx.txout_address_is_mine[i]) { // Received by Fujicoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = EncodeDestination(wtx.txout_address[i]); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.is_coinbase) { // Generated sub.type = TransactionRecord::Generated; } parts.append(sub); } } } else { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; for (isminetype mine : wtx.txin_is_mine) { if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; for (isminetype mine : wtx.txout_is_mine) { if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllToMe > mine) fAllToMe = mine; } if (fAllFromMe && fAllToMe) { // Payment to self CAmount nChange = wtx.change; parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe) { // // Debit // CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { const CTxOut& txout = wtx.tx->vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = nOut; sub.involvesWatchAddress = involvesWatchAddress; if(wtx.txout_is_mine[nOut]) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } if (!boost::get<CNoDestination>(&wtx.txout_address[nOut])) { // Sent to Fujicoin Address sub.type = TransactionRecord::SendToAddress; sub.address = EncodeDestination(wtx.txout_address[nOut]); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); parts.last().involvesWatchAddress = involvesWatchAddress; } } return parts; }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); CAmount nCredit = wtx.GetCredit(ISMINE_ALL); CAmount nDebit = wtx.GetDebit(ISMINE_ALL); CAmount nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) { const CTxOut& txout = wtx.tx->vout[i]; isminetype mine = wallet->IsMine(txout); if(mine) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = i; // vout index sub.credit = txout.nValue; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Dash Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; } parts.append(sub); } } } else { bool fAllFromMeDenom = true; int nFromMe = 0; bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; BOOST_FOREACH(const CTxIn& txin, wtx.tx->vin) { if(wallet->IsMine(txin)) { fAllFromMeDenom = fAllFromMeDenom && wallet->IsDenominated(txin.prevout); nFromMe++; } isminetype mine = wallet->IsMine(txin); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; bool fAllToMeDenom = true; int nToMe = 0; BOOST_FOREACH(const CTxOut& txout, wtx.tx->vout) { if(wallet->IsMine(txout)) { fAllToMeDenom = fAllToMeDenom && CPrivateSend::IsDenominatedAmount(txout.nValue); nToMe++; } isminetype mine = wallet->IsMine(txout); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllToMe > mine) fAllToMe = mine; } if(fAllFromMeDenom && fAllToMeDenom && nFromMe * nToMe) { parts.append(TransactionRecord(hash, nTime, TransactionRecord::PrivateSendDenominate, "", -nDebit, nCredit)); parts.last().involvesWatchAddress = false; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe && fAllToMe) { // Payment to self // TODO: this section still not accurate but covers most cases, // might need some additional work however TransactionRecord sub(hash, nTime); // Payment to self by default sub.type = TransactionRecord::SendToSelf; sub.address = ""; if(mapValue["DS"] == "1") { sub.type = TransactionRecord::PrivateSend; CTxDestination address; if (ExtractDestination(wtx.tx->vout[0].scriptPubKey, address)) { // Sent to Dash Address sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.address = mapValue["to"]; } } else { for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { const CTxOut& txout = wtx.tx->vout[nOut]; sub.idx = parts.size(); if(txout.nValue == CPrivateSend::GetMaxCollateralAmount()) sub.type = TransactionRecord::PrivateSendMakeCollaterals; if(CPrivateSend::IsDenominatedAmount(txout.nValue)) sub.type = TransactionRecord::PrivateSendCreateDenominations; if(nDebit - wtx.tx->GetValueOut() == CPrivateSend::GetCollateralAmount()) sub.type = TransactionRecord::PrivateSendCollateralPayment; } } CAmount nChange = wtx.GetChange(); sub.debit = -(nDebit - nChange); sub.credit = nCredit - nChange; parts.append(sub); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe) { // // Debit // CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { const CTxOut& txout = wtx.tx->vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = nOut; sub.involvesWatchAddress = involvesWatchAddress; if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Dash Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } if(mapValue["DS"] == "1") { sub.type = TransactionRecord::PrivateSend; } CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); parts.last().involvesWatchAddress = involvesWatchAddress; } } return parts; }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64_t nTime = wtx.GetTxTime(); CAmount nCredit = wtx.GetCredit(ISMINE_ALL); CAmount nDebit = wtx.GetDebit(ISMINE_ALL); CAmount nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // for(unsigned int i = 0; i < wtx.tx->vout.size(); i++) { const CTxOut& txout = wtx.tx->vout[i]; isminetype mine = wallet->IsMine(txout); if(mine) { TransactionRecord sub(hash, nTime); CTxDestination address; sub.idx = i; // vout index sub.credit = txout.nValue; sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY; if (ExtractDestination(txout.scriptPubKey, address) && IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; } if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; } parts.append(sub); } } } else { bool involvesWatchAddress = false; isminetype fAllFromMe = ISMINE_SPENDABLE; for (const CTxIn& txin : wtx.tx->vin) { isminetype mine = wallet->IsMine(txin); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllFromMe > mine) fAllFromMe = mine; } isminetype fAllToMe = ISMINE_SPENDABLE; for (const CTxOut& txout : wtx.tx->vout) { isminetype mine = wallet->IsMine(txout); if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true; if(fAllToMe > mine) fAllToMe = mine; } if (fAllFromMe && fAllToMe) { // Payment to self CAmount nChange = wtx.GetChange(); parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "", -(nDebit - nChange), nCredit - nChange)); parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument } else if (fAllFromMe) { // // Debit // CAmount nTxFee = nDebit - wtx.tx->GetValueOut(); for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++) { const CTxOut& txout = wtx.tx->vout[nOut]; TransactionRecord sub(hash, nTime); sub.idx = nOut; sub.involvesWatchAddress = involvesWatchAddress; if(wallet->IsMine(txout)) { // Ignore parts sent to self, as this is usually the change // from a transaction sent back to our own address. continue; } CTxDestination address; if (ExtractDestination(txout.scriptPubKey, address)) { // Sent to Bitcoin Address sub.type = TransactionRecord::SendToAddress; sub.address = CBitcoinAddress(address).ToString(); } else { // Sent to IP, or other non-address transaction like OP_EVAL sub.type = TransactionRecord::SendToOther; sub.address = mapValue["to"]; } CAmount nValue = txout.nValue; /* Add fee to first output */ if (nTxFee > 0) { nValue += nTxFee; nTxFee = 0; } sub.debit = -nValue; parts.append(sub); } } else { // // Mixed debit transaction, can't break down payees // parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, 0)); parts.last().involvesWatchAddress = involvesWatchAddress; } } return parts; }
/* * Decompose CWallet transaction to model transaction records. */ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const CWallet *wallet, const CWalletTx &wtx) { QList<TransactionRecord> parts; int64 nTime = wtx.GetTxTime(); int64 nCredit = wtx.GetCredit(true); //txout int64 nDebit = wtx.GetDebit(); //txin int64 nNet = nCredit - nDebit; uint256 hash = wtx.GetHash(); std::map<std::string, std::string> mapValue = wtx.mapValue; if (showTransaction(wtx)) { if (wtx.IsCoinStake()) // ppcoin: coinstake transaction { parts.append(TransactionRecord(hash, nTime, TransactionRecord::StakeMint, "", -nDebit, wtx.GetValueOut())); } // else if(wtx.IsProposal()) // { // parts.append(TransactionRecord(hash, nTime, TransactionRecord::SubmittedProposal, "", -wtx.GetValueIn(), 0)); // } else if (nNet > 0 || wtx.IsCoinBase()) { // // Credit // BOOST_FOREACH(const CTxOut& txout, wtx.vout) { CTxDestination address; TransactionRecord sub(hash, nTime); sub.idx = parts.size(); // sequence number sub.credit = txout.nValue; if (wtx.IsCoinBase()) { // Generated sub.type = TransactionRecord::Generated; parts.append(sub); } else if (ExtractDestination(txout.scriptPubKey, address)) { if (IsMine(*wallet, address)) { // Received by Bitcoin Address sub.type = TransactionRecord::RecvWithAddress; sub.address = CBitcoinAddress(address).ToString(); parts.append(sub); } } else { // Received by IP connection (deprecated features), or a multisignature or other non-simple transaction sub.type = TransactionRecord::RecvFromOther; sub.address = mapValue["from"]; parts.append(sub); } } } else {