/* * 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 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; }