Skip to content

Commit

Permalink
QT: Carbon copy 0.14-based transaction accounting
Browse files Browse the repository at this point in the history
  • Loading branch information
instagibbs committed Apr 11, 2019
1 parent 6333166 commit 5c6e859
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 137 deletions.
1 change: 1 addition & 0 deletions src/interfaces/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ static WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) EXCLUSIVE_LO
result.txout_address_is_mine.emplace_back(ExtractDestination(txout.scriptPubKey, result.txout_address.back()) ?
IsMine(wallet, result.txout_address.back()) :
ISMINE_NO);
result.txout_is_change.emplace_back(wallet.IsChange(txout));
}
// ELEMENTS: Retrieve unblinded information about outputs
for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i) {
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ struct WalletTx
CTransactionRef tx;
std::vector<isminetype> txin_is_mine;
std::vector<isminetype> txout_is_mine;
std::vector<bool> txout_is_change;
std::vector<CTxDestination> txout_address;
std::vector<isminetype> txout_address_is_mine;
std::vector<CAmount> txout_amounts;
Expand Down
234 changes: 97 additions & 137 deletions src/qt/transactionrecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,54 +36,21 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
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++)
{
isminetype mine = wtx.txout_is_mine[i];
if(mine)
{
TransactionRecord sub(hash, nTime);
CTxDestination address;
sub.idx = i; // vout index
sub.amount = wtx.txout_amounts[i];
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
if (wtx.txout_address_is_mine[i])
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
sub.address = EncodeDestination(wtx.txout_address[i]);
sub.asset = wtx.txout_assets[i];
}
else
{
// Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
sub.type = TransactionRecord::RecvFromOther;
sub.address = mapValue["from"];
sub.asset = wtx.txout_assets[i];
}
if (wtx.is_coinbase)
{
// Generated
sub.type = TransactionRecord::Generated;
sub.asset = wtx.txout_assets[i];
}

parts.append(sub);
}
}
bool involvesWatchAddress = false;
isminetype fAllFromMe = ISMINE_SPENDABLE;
bool any_from_me = false;
std::set<CAsset> assets_issued_to_me_only;
if (wtx.is_coinbase) {
fAllFromMe = ISMINE_NO;
}
else
{
bool involvesWatchAddress = false;
isminetype fAllFromMe = ISMINE_SPENDABLE;
std::set<CAsset> assets_issued_to_me_only;
CAmountMap assets_received_by_me_only;
for (unsigned int i = 0; i < wtx.tx->vout.size(); i++)
{
if (wtx.tx->vout[i].IsFee()) {
continue;
}
const CAsset& asset = wtx.txout_assets[i];
if (assets_received_by_me_only.count(asset) && assets_received_by_me_only.at(asset) < 0) {
// Already known to be received by not-me
Expand All @@ -97,147 +64,140 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(const interface
}
}

any_from_me = false;
for (size_t i = 0; i < wtx.tx->vin.size(); ++i)
{
/* Issuance detection */
isminetype mine = wtx.txin_is_mine[i];
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
if(fAllFromMe > mine) fAllFromMe = mine;
const CAsset& asset = wtx.txin_issuance_asset[i];
const CAmount& asset_amount = wtx.txin_issuance_asset_amount[i];
const CAsset& token = wtx.txin_issuance_token[i];
const CAmount& token_amount = wtx.txin_issuance_token_amount[i];
if (!asset.IsNull()) {
if (assets_received_by_me_only.count(asset) == 0) {
continue;
}
if (asset_amount == assets_received_by_me_only.at(asset)) {
// Special case: collapse the chain of issue, send, receive to just an issue
assets_issued_to_me_only.insert(asset);
continue;
}

TransactionRecord sub(hash, nTime);
sub.involvesWatchAddress = involvesWatchAddress;
sub.asset = asset;
sub.amount = asset_amount;
sub.type = TransactionRecord::IssuedAsset;
parts.append(sub);
}
if (!token.IsNull()) {
if (assets_received_by_me_only.count(token) == 0) {
continue;
if (mine) any_from_me = true;
CAmountMap assets;
assets[wtx.txin_issuance_asset[i]] = wtx.txin_issuance_asset_amount[i];
assets[wtx.txin_issuance_token[i]] = wtx.txin_issuance_token_amount[i];
for (const auto& asset : assets) {
if (!asset.first.IsNull()) {
if (assets_received_by_me_only.count(asset.first) == 0) {
continue;
}
if (asset.second == assets_received_by_me_only.at(asset.first)) {
// Special case: collapse the chain of issue, send, receive to just an issue
assets_issued_to_me_only.insert(asset.first);
continue;
} else {
TransactionRecord sub(hash, nTime);
sub.involvesWatchAddress = involvesWatchAddress;
sub.asset = asset.first;
sub.amount = asset.second;
sub.type = TransactionRecord::IssuedAsset;
parts.append(sub);
}
}
if (token_amount == assets_received_by_me_only.at(asset)) {
// Special case: collapse the chain of issue, send, receive to just an issue
assets_issued_to_me_only.insert(asset);
continue;
}

TransactionRecord sub(hash, nTime);
sub.involvesWatchAddress = involvesWatchAddress;
sub.asset = token;
sub.amount = token_amount;
sub.type = TransactionRecord::IssuedAsset;
parts.append(sub);
}

if (!wtx.txin_issuance_token[i].IsNull()) {
TransactionRecord sub(hash, nTime);
sub.involvesWatchAddress = involvesWatchAddress;
sub.asset = wtx.txin_issuance_token[i];
sub.amount = wtx.txin_issuance_token_amount[i];
sub.type = TransactionRecord::IssuedAsset;
parts.append(sub);
}
}
}

isminetype fAllToMe = ISMINE_SPENDABLE;
for (unsigned int i = 0; i < wtx.txout_is_mine.size(); ++i) {
const isminetype mine = wtx.txout_is_mine[i];
const CTxOut txout = wtx.tx->vout[i];
if (fAllFromMe || !any_from_me) {
for(unsigned int i = 0; i < wtx.tx->vout.size(); i++)
{
const CTxOut& txout = wtx.tx->vout[i];
const CAsset& asset = wtx.txout_assets[i];
if (txout.IsFee()) {
// explicit fee; ignore
continue;
}
if(mine & ISMINE_WATCH_ONLY) involvesWatchAddress = true;
if(fAllToMe > mine) fAllToMe = mine;
}

if (fAllFromMe && fAllToMe)
{
// Payment to self
CAmount nChange = valueFor(wtx.change, ::policyAsset);

parts.append(TransactionRecord(hash, nTime, TransactionRecord::SendToSelf, "",
-(nDebit - nChange) + (nCredit - nChange), ::policyAsset));
parts.last().involvesWatchAddress = involvesWatchAddress; // maybe pass to TransactionRecord as constructor argument
}
else if (fAllFromMe)
{

//
// Debit
//

for (unsigned int nOut = 0; nOut < wtx.tx->vout.size(); nOut++)
{

const CTxOut& txout = wtx.tx->vout[nOut];
const CAsset& asset = wtx.txout_assets[nOut];
if (fAllFromMe && assets_issued_to_me_only.count(asset) == 0) {
// Change is only really possible if we're the sender
// Otherwise, someone just sent bitcoins to a change address, which should be shown

if(wtx.txout_is_mine[nOut] || txout.IsFee())
{
// Ignore parts sent to self, as this is usually the change
// from a transaction sent back to our own address.
continue;
}

// Short-circuit when it's an issuance to self
if (assets_issued_to_me_only.count(asset) != 0) {
if (wtx.txout_is_change[i]) {
continue;
}

//
// Debit
//
TransactionRecord sub(hash, nTime);
sub.idx = nOut;
sub.idx = i;
sub.involvesWatchAddress = involvesWatchAddress;
sub.amount = -wtx.txout_amounts[nOut];
sub.amount = -wtx.txout_amounts[i];
sub.asset = asset;

if (!boost::get<CNoDestination>(&wtx.txout_address[nOut]))
if (!boost::get<CNoDestination>(&wtx.txout_address[i]))
{
// Sent to Bitcoin Address
sub.type = TransactionRecord::SendToAddress;
sub.address = EncodeDestination(wtx.txout_address[nOut]);
sub.address = EncodeDestination(wtx.txout_address[i]);
}
else
{
// Sent to IP, or other non-address transaction like OP_EVAL
sub.type = TransactionRecord::SendToOther;
sub.address = mapValue["to"];
}
if (assets_issued_to_me_only.count(asset)) {
parts.append(sub);
}

isminetype mine = wtx.txout_is_mine[i];
if(mine)
{
//
// Credit
//

TransactionRecord sub(hash, nTime);
CTxDestination address;
sub.idx = i; // vout index
sub.amount = wtx.txout_amounts[i];
sub.involvesWatchAddress = mine & ISMINE_WATCH_ONLY;
if (wtx.txout_address_is_mine[i])
{
// Received by Bitcoin Address
sub.type = TransactionRecord::RecvWithAddress;
sub.address = EncodeDestination(wtx.txout_address[i]);
sub.asset = asset;
}
else
{
// Received by IP connection (deprecated features), or a multisignature or other non-simple transaction
sub.type = TransactionRecord::RecvFromOther;
sub.address = mapValue["from"];
sub.asset = wtx.txout_assets[i];
}
if (wtx.is_coinbase)
{
// Generated
sub.type = TransactionRecord::Generated;
sub.asset = wtx.txout_assets[i];
}
if (assets_issued_to_me_only.count(wtx.txout_assets[i])) {
sub.type = TransactionRecord::IssuedAsset;
}

parts.append(sub);
}
}

if (fAllFromMe) {
for (const auto& tx_fee : GetFeeMap(*wtx.tx)) {
if (!tx_fee.second) continue;

TransactionRecord sub(hash, nTime);
sub.type = TransactionRecord::Fee;
sub.asset = tx_fee.first;
sub.amount = -tx_fee.second;
parts.append(sub);
}
}
else
{
//
// Mixed debit transaction, can't break down payees
//
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, CAsset()));
parts.last().involvesWatchAddress = involvesWatchAddress;
}
}
else
{
//
// Mixed debit transaction, can't break down payees
//
parts.append(TransactionRecord(hash, nTime, TransactionRecord::Other, "", nNet, CAsset()));
parts.last().involvesWatchAddress = involvesWatchAddress;
}

return parts;
Expand Down

0 comments on commit 5c6e859

Please sign in to comment.