Skip to content

Commit 9810dc3

Browse files
committed
Moved the CalculateDeniabilizaitonCycles to the API too.
1 parent 2d53c14 commit 9810dc3

File tree

4 files changed

+91
-7
lines changed

4 files changed

+91
-7
lines changed

src/interfaces/wallet.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ class Wallet
151151
WalletValueMap value_map,
152152
WalletOrderForm order_form) = 0;
153153

154+
virtual std::pair<unsigned int, bool> calculateDeniabilizationCycles(const COutPoint& outpoint) = 0;
155+
154156
virtual util::Result<CTransactionRef> createDeniabilizationTransaction(const std::set<COutPoint>& inputs,
155157
unsigned int confirm_target,
156158
unsigned int deniabilization_cycles,

src/wallet/interfaces.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ class WalletImpl : public Wallet
295295
LOCK(m_wallet->cs_wallet);
296296
m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form));
297297
}
298+
std::pair<unsigned int, bool> calculateDeniabilizationCycles(const COutPoint& outpoint) override
299+
{
300+
LOCK(m_wallet->cs_wallet); // TODO - Do we need a lock here?
301+
return CalculateDeniabilizationCycles(*m_wallet, outpoint);
302+
}
298303
util::Result<CTransactionRef> createDeniabilizationTransaction(const std::set<COutPoint>& inputs,
299304
unsigned int confirm_target,
300305
unsigned int deniabilization_cycles,

src/wallet/spend.cpp

Lines changed: 77 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,13 +1337,83 @@ CAmount CalculateDeniabilizationFeeEstimate(const CTxDestination& shared_destina
13371337
return deniabilizationFee;
13381338
}
13391339

1340-
util::Result<CreatedTransactionResult> CreateDeniabilizationTransaction(
1341-
CWallet& wallet,
1342-
const std::set<COutPoint>& inputs,
1343-
unsigned int confirm_target,
1344-
unsigned int deniabilization_cycles,
1345-
bool sign,
1346-
bool& insufficient_amount)
1340+
std::pair<unsigned int, bool> CalculateDeniabilizationCycles(CWallet& wallet, const COutPoint& outpoint)
1341+
{
1342+
LOCK(wallet.cs_wallet);
1343+
auto walletTx = wallet.GetWalletTx(outpoint.hash);
1344+
if (!walletTx) {
1345+
return std::make_pair(0, false);
1346+
}
1347+
auto tx = walletTx->tx;
1348+
1349+
if (tx->IsCoinBase()) {
1350+
// this is a block reward tx, so we tag it as such
1351+
return std::make_pair(0, true);
1352+
}
1353+
1354+
// an deniabilized coin is one we sent to ourselves
1355+
// all txIn should belong to our wallet
1356+
if (tx->vin.empty()) {
1357+
return std::make_pair(0, false);
1358+
}
1359+
for (const auto& txIn : tx->vin) {
1360+
if (InputIsMine(wallet, txIn) == ISMINE_NO) {
1361+
return std::make_pair(0, false);
1362+
}
1363+
}
1364+
1365+
// all txOut should belong to our wallet
1366+
Assert(outpoint.n < tx->vout.size());
1367+
uint n = 0;
1368+
for (const auto& txOut : tx->vout) {
1369+
if (wallet.IsMine(txOut) == ISMINE_NO) {
1370+
Assert(n != outpoint.n);
1371+
return std::make_pair(0, false);
1372+
}
1373+
n++;
1374+
}
1375+
1376+
uint uniqueTxOutCount = 0;
1377+
for (const auto& txOut : tx->vout) {
1378+
// check if it's a valid destination
1379+
CTxDestination txOutDestination;
1380+
if (!ExtractDestination(txOut.scriptPubKey, txOutDestination)) {
1381+
continue;
1382+
}
1383+
1384+
// don't count outputs that match any input addresses (eg it's change output)
1385+
bool matchesInput = false;
1386+
for (const auto& txIn : tx->vin) {
1387+
auto prevWalletTx = wallet.GetWalletTx(txIn.prevout.hash);
1388+
if (prevWalletTx && prevWalletTx->tx->vout[txIn.prevout.n].scriptPubKey == txOut.scriptPubKey) {
1389+
matchesInput = true;
1390+
break;
1391+
}
1392+
}
1393+
if (matchesInput) {
1394+
continue;
1395+
}
1396+
1397+
uniqueTxOutCount++;
1398+
}
1399+
1400+
// we consider two or more unique outputs an "deniabilization" of the coin
1401+
uint deniabilizationCycles = uniqueTxOutCount >= 2 ? 1 : 0;
1402+
1403+
// all txIn and txOut are from our wallet
1404+
// however if we have multiple txIn this was either an initial deniabilization of multiple UTXOs or the user manually merged deniabilized UTXOs
1405+
// in either case we don't need to recurse into parent transactions and we can return the calculated cycles
1406+
if (tx->vin.size() > 1) {
1407+
return std::make_pair(deniabilizationCycles, false);
1408+
}
1409+
1410+
const auto& txIn = tx->vin[0];
1411+
// now recursively calculate the deniabilization cycles of the input
1412+
auto inputStats = CalculateDeniabilizationCycles(wallet, txIn.prevout);
1413+
return std::make_pair(inputStats.first + deniabilizationCycles, inputStats.second);
1414+
};
1415+
1416+
util::Result<CreatedTransactionResult> CreateDeniabilizationTransaction(CWallet& wallet, const std::set<COutPoint>& inputs, unsigned int confirm_target, unsigned int deniabilization_cycles, bool sign, bool& insufficient_amount)
13471417
{
13481418
if (inputs.empty()) {
13491419
return util::Error{_("Inputs must not be empty")};

src/wallet/spend.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,13 @@ CAmount CalculateDeniabilizationFeeEstimate(const CTxDestination& shared_destina
249249
*/
250250
CFeeRate CalculateDeniabilizationFeeRate(const CWallet& wallet, unsigned int confirm_target);
251251

252+
/**
253+
* Calculate how many deniabilization cycles have been performed for the given UTXO
254+
* Result.first is the deniabilization cycle count
255+
* Result.second indicates if the transaction chain is from a coinbase transaction (block reward)
256+
*/
257+
std::pair<unsigned int, bool> CalculateDeniabilizationCycles(CWallet& wallet, const COutPoint& outpoint);
258+
252259
/**
253260
* Create a deniabilization transaction with the provided set of inputs (must share the same destination)
254261
* confirm_target is the confirmation target for the deniabilization transaction

0 commit comments

Comments
 (0)