Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make a support of Qt app to show Platform transfer Tx #6131

Merged
merged 3 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/interfaces/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ struct WalletTx
int64_t time;
std::map<std::string, std::string> value_map;
bool is_coinbase;
bool is_platform_transfer{false};
bool is_denominate;
};

Expand Down
5 changes: 5 additions & 0 deletions src/primitives/transaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ class CTransaction
return nVersion >= SPECIAL_VERSION;
}

bool IsPlatformTransfer() const noexcept
{
return IsSpecialTxVersion() && nType == TRANSACTION_ASSET_UNLOCK;
}

bool HasExtraPayloadField() const noexcept
{
return IsSpecialTxVersion() && nType != TRANSACTION_NORMAL;
Expand Down
4 changes: 4 additions & 0 deletions src/qt/transactiondesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ QString TransactionDesc::toHTML(interfaces::Node& node, interfaces::Wallet& wall
{
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Generated") + "<br>";
}
else if (wtx.is_platform_transfer)
{
strHTML += "<b>" + tr("Source") + ":</b> " + tr("Platform Transfer") + "<br>";
}
else if (wtx.value_map.count("from") && !wtx.value_map["from"].empty())
{
// Online transaction
Expand Down
7 changes: 6 additions & 1 deletion src/qt/transactionrecord.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Wal
auto node = interfaces::MakeNode();
auto& coinJoinOptions = node->coinJoinOptions();

if (nNet > 0 || wtx.is_coinbase)
if (nNet > 0 || wtx.is_coinbase || wtx.is_platform_transfer)
{
//
// Credit
Expand Down Expand Up @@ -74,6 +74,11 @@ QList<TransactionRecord> TransactionRecord::decomposeTransaction(interfaces::Wal
// Generated
sub.type = TransactionRecord::Generated;
}
if (wtx.is_platform_transfer)
{
// Withdrawal from platform
sub.type = TransactionRecord::PlatformTransfer;
}

parts.append(sub);
}
Expand Down
3 changes: 2 additions & 1 deletion src/qt/transactionrecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ class TransactionRecord
CoinJoinCollateralPayment,
CoinJoinMakeCollaterals,
CoinJoinCreateDenominations,
CoinJoinSend
CoinJoinSend,
PlatformTransfer,
};

/** Number of confirmation recommended for accepting a transaction */
Expand Down
29 changes: 21 additions & 8 deletions src/qt/transactiontablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
return tr("Payment to yourself");
case TransactionRecord::Generated:
return tr("Mined");
case TransactionRecord::PlatformTransfer:
return tr("Platform Transfer");

case TransactionRecord::CoinJoinMixing:
return tr("%1 Mixing").arg(QString::fromStdString(gCoinJoinName));
Expand All @@ -443,9 +445,10 @@ QString TransactionTableModel::formatTxType(const TransactionRecord *wtx) const
case TransactionRecord::CoinJoinSend:
return tr("%1 Send").arg(QString::fromStdString(gCoinJoinName));

default:
return QString();
}
case TransactionRecord::Other:
break; // use fail-over here
} // no default case, so the compiler can warn about missing cases
return QString();
}

QVariant TransactionTableModel::txAddressDecoration(const TransactionRecord *wtx) const
Expand Down Expand Up @@ -473,14 +476,20 @@ QString TransactionTableModel::formatTxToAddress(const TransactionRecord *wtx, b
case TransactionRecord::SendToAddress:
case TransactionRecord::Generated:
case TransactionRecord::CoinJoinSend:
case TransactionRecord::PlatformTransfer:
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
case TransactionRecord::SendToOther:
return QString::fromStdString(wtx->strAddress) + watchAddress;
case TransactionRecord::SendToSelf:
return formatAddressLabel(wtx->strAddress, wtx->label, tooltip) + watchAddress;
default:
return tr("(n/a)") + watchAddress;
}
case TransactionRecord::CoinJoinMixing:
case TransactionRecord::CoinJoinCollateralPayment:
case TransactionRecord::CoinJoinMakeCollaterals:
case TransactionRecord::CoinJoinCreateDenominations:
case TransactionRecord::Other:
break; // use fail-over here
} // no default case, so the compiler can warn about missing cases
return tr("(n/a)") + watchAddress;
}

QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
Expand All @@ -491,6 +500,7 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
case TransactionRecord::RecvWithAddress:
case TransactionRecord::SendToAddress:
case TransactionRecord::Generated:
case TransactionRecord::PlatformTransfer:
case TransactionRecord::CoinJoinSend:
case TransactionRecord::RecvWithCoinJoin:
{
Expand All @@ -504,9 +514,11 @@ QVariant TransactionTableModel::addressColor(const TransactionRecord *wtx) const
case TransactionRecord::CoinJoinMakeCollaterals:
case TransactionRecord::CoinJoinCollateralPayment:
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::BAREADDRESS);
default:
case TransactionRecord::SendToOther:
case TransactionRecord::RecvFromOther:
case TransactionRecord::Other:
break;
}
} // no default case, so the compiler can warn about missing cases
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::DEFAULT);
}

Expand All @@ -530,6 +542,7 @@ QVariant TransactionTableModel::amountColor(const TransactionRecord *rec) const
case TransactionRecord::RecvWithCoinJoin:
case TransactionRecord::RecvWithAddress:
case TransactionRecord::RecvFromOther:
case TransactionRecord::PlatformTransfer:
return GUIUtil::getThemedQColor(GUIUtil::ThemedColor::GREEN);
case TransactionRecord::CoinJoinSend:
case TransactionRecord::SendToAddress:
Expand Down
1 change: 1 addition & 0 deletions src/qt/transactionview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ TransactionView::TransactionView(QWidget* parent) :
typeWidget->addItem(tr("%1 Collateral Payment").arg(strCoinJoinName), TransactionFilterProxy::TYPE(TransactionRecord::CoinJoinCollateralPayment));
typeWidget->addItem(tr("To yourself"), TransactionFilterProxy::TYPE(TransactionRecord::SendToSelf));
typeWidget->addItem(tr("Mined"), TransactionFilterProxy::TYPE(TransactionRecord::Generated));
typeWidget->addItem(tr("Platform Transfer"), TransactionFilterProxy::TYPE(TransactionRecord::PlatformTransfer));
typeWidget->addItem(tr("Other"), TransactionFilterProxy::TYPE(TransactionRecord::Other));
typeWidget->setCurrentIndex(settings.value("transactionType").toInt());

Expand Down
1 change: 1 addition & 0 deletions src/wallet/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
result.time = wtx.GetTxTime();
result.value_map = wtx.mapValue;
result.is_coinbase = wtx.IsCoinBase();
result.is_platform_transfer = wtx.IsPlatformTransfer();
// The determination of is_denominate is based on simplified checks here because in this part of the code
// we only want to know about mixing transactions belonging to this specific wallet.
result.is_denominate = wtx.tx->vin.size() == wtx.tx->vout.size() && // Number of inputs is same as number of outputs
Expand Down
15 changes: 12 additions & 3 deletions src/wallet/rpcwallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ static void WalletTxToJSON(interfaces::Chain& chain, const CWalletTx& wtx, UniVa
entry.pushKV("chainlock", chainlock);
if (wtx.IsCoinBase())
entry.pushKV("generated", true);
if (wtx.IsPlatformTransfer())
entry.pushKV("platform-transfer", true);
if (confirms > 0)
{
entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
Expand Down Expand Up @@ -1403,6 +1405,10 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
else
entry.pushKV("category", "generate");
}
else if (wtx.IsPlatformTransfer())
{
entry.pushKV("category", "platform-transfer");
}
else
{
entry.pushKV("category", "receive");
Expand Down Expand Up @@ -1467,7 +1473,8 @@ static RPCHelpMan listtransactions()
"\"receive\" Non-coinbase transactions received.\n"
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
"\"orphan\" Orphaned coinbase transactions received.\n"},
"\"orphan\" Orphaned coinbase transactions received.\n"
"\"platform-transfer\" Platform Transfer transactions received.\n"},
{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
"for all other categories"},
{RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
Expand Down Expand Up @@ -1582,7 +1589,8 @@ static RPCHelpMan listsinceblock()
"\"receive\" Non-coinbase transactions received.\n"
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
"\"orphan\" Orphaned coinbase transactions received.\n"},
"\"orphan\" Orphaned coinbase transactions received.\n"
"\"platform-transfer\" Platform Transfer transactions received.\n"},
{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
"for all other categories"},
{RPCResult::Type::NUM, "vout", "the vout value"},
Expand Down Expand Up @@ -1723,7 +1731,8 @@ static RPCHelpMan gettransaction()
"\"receive\" Non-coinbase transactions received.\n"
"\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
"\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
"\"orphan\" Orphaned coinbase transactions received.\n"},
"\"orphan\" Orphaned coinbase transactions received.\n"
"\"platform-transfer\" Platform Transfer transactions received.\n"},
{RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
{RPCResult::Type::STR, "label", "A comment for the address/transaction, if any"},
{RPCResult::Type::NUM, "vout", "the vout value"},
Expand Down
1 change: 1 addition & 0 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,7 @@ class CWalletTx
void setConfirmed() { m_confirm.status = CWalletTx::CONFIRMED; }
const uint256& GetHash() const { return tx->GetHash(); }
bool IsCoinBase() const { return tx->IsCoinBase(); }
bool IsPlatformTransfer() const { return tx->IsPlatformTransfer(); }
bool IsImmatureCoinBase() const;

// Disable copying of CWalletTx objects to prevent bugs where instances get
Expand Down
23 changes: 21 additions & 2 deletions test/functional/feature_asset_locks.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
get_bip9_details,
hex_str_to_bytes,
)
from test_framework.wallet_util import bytes_to_wif

llmq_type_test = 106 # LLMQType::LLMQ_TEST_PLATFORM
tiny_amount = int(Decimal("0.0007") * COIN)
Expand Down Expand Up @@ -260,6 +261,8 @@ def run_test(self):

key = ECKey()
key.generate()
privkey = bytes_to_wif(key.get_bytes())
node_wallet.importprivkey(privkey)
pubkey = key.get_pubkey().get_bytes()

self.test_asset_locks(node_wallet, node, pubkey)
Expand Down Expand Up @@ -477,15 +480,31 @@ def test_withdrawal_limits(self, node_wallet, node, pubkey):
self.check_mempool_result(tx=asset_unlock_tx_full, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}})

txid_in_block = self.send_tx(asset_unlock_tx_full)
expected_balance = (Decimal(self.get_credit_pool_balance()) - Decimal(tiny_amount))
node.generate(1)
self.sync_all()
self.log.info("Check txid_in_block was mined...")
self.log.info("Check txid_in_block was mined")
block = node.getblock(node.getbestblockhash())
assert txid_in_block in block['tx']
self.validate_credit_pool_balance(0)

self.log.info(f"Check status of withdrawal and try to spend it")
withdrawal_status = node_wallet.gettransaction(txid_in_block)
assert_equal(withdrawal_status['amount'] * COIN, expected_balance)
assert_equal(withdrawal_status['details'][0]['category'], 'platform-transfer')

spend_withdrawal_hex = node_wallet.createrawtransaction([{'txid': txid_in_block, 'vout' : 0}], { node_wallet.getnewaddress() : (expected_balance - Decimal(tiny_amount)) / COIN})
spend_withdrawal_hex = node_wallet.signrawtransactionwithwallet(spend_withdrawal_hex)['hex']
spend_withdrawal = tx_from_hex(spend_withdrawal_hex)
self.check_mempool_result(tx=spend_withdrawal, result_expected={'allowed': True, 'fees': {'base': Decimal(str(tiny_amount / COIN))}})
spend_txid_in_block = self.send_tx(spend_withdrawal)

node.generate(1)
block = node.getblock(node.getbestblockhash())
assert spend_txid_in_block in block['tx']

self.log.info("Fast forward to the next day to reset all current unlock limits...")
self.slowly_generate_batch(blocks_in_one_day + 1)
self.slowly_generate_batch(blocks_in_one_day)
self.mine_quorum(llmq_type_name="llmq_test_platform", llmq_type=106)

total = self.get_credit_pool_balance()
Expand Down
Loading