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

Shield Activity #416

Merged
merged 30 commits into from
Nov 20, 2024
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
02daacd
During the initial sync, add to the wallet txs that are decrypted by …
panleone Oct 4, 2024
5d6b822
Make getCredit and getDebit return whether all vins/vouts belongs to …
panleone Oct 4, 2024
2d2e8d2
Update HistoricalTx class, to take in account shield data
panleone Oct 4, 2024
4a22816
make toHistoricalTXs take in account shield data
panleone Oct 4, 2024
d03eabe
make the Activity show shielded txs
panleone Oct 4, 2024
4516976
Update broken tests
panleone Oct 4, 2024
0479684
Add missing await
panleone Oct 10, 2024
c9dd54a
Make old wallet resync if load operation is not succesful
panleone Oct 10, 2024
dd37093
Add utils function to reverse and swap endianess
panleone Oct 10, 2024
e9782c9
Simplify logic and fix bug of sent to shield address
panleone Oct 11, 2024
23aea91
Merge branch 'master' into shield_activity_final
panleone Oct 11, 2024
7ae5fb8
Remove unused imports
panleone Oct 11, 2024
5bb43be
Merge remote-tracking branch 'origin' into shield_activity_final
panleone Oct 28, 2024
6e90c82
DebugLog in case of failure
panleone Oct 28, 2024
da9d7bf
Merge branch 'master' into shield_activity_final
panleone Nov 4, 2024
8567bd6
Merge remote-tracking branch 'upstream/master' into shield_activity_f…
panleone Nov 7, 2024
63fb108
apply new lint rules
panleone Nov 7, 2024
7eb8b65
yet another merge commit
panleone Nov 12, 2024
9f7f082
fix: load first the shield from disk
panleone Nov 12, 2024
379f556
fix: Do not use txSelfMap for DELEGATION
panleone Nov 12, 2024
c5e68a0
feat: Use new pivx-shield beta version
panleone Nov 12, 2024
feb837f
Merge remote-tracking branch 'upstream/master' into shield_activity_f…
panleone Nov 12, 2024
17f7b0f
beautify numbers
panleone Nov 12, 2024
7f2ad19
Update E2E tests (new icons)
panleone Nov 12, 2024
9e81bae
remove merge trash
panleone Nov 13, 2024
829449c
regenerate snaphost again again
panleone Nov 19, 2024
371e908
fix infinite await bug
panleone Nov 19, 2024
00145e5
fix: Use block.time instead of mediantime
panleone Nov 19, 2024
98c00ed
handle block at batches of 50
panleone Nov 19, 2024
ead84d0
Merge remote-tracking branch 'upstream/master' into shield_activity_f…
panleone Nov 19, 2024
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
2 changes: 1 addition & 1 deletion cypress/snapshots/html/snapshot.html
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@
<path d="M31.7,10l-18,18c-0.7,0.7-1.8,0.7-2.5,0c0,0,0,0,0,0l-11-11c-0.3-0.3-0.3-0.9,0-1.2c0,0,0,0,0,0l5-5c0.3-0.3,0.9-0.3,1.2,0
c0,0,0,0,0,0l6,6l13-13c0.3-0.3,0.9-0.3,1.3,0l5,5C32.1,9.1,32.1,9.6,31.7,10C31.8,10,31.8,10,31.7,10C31.7,10,31.7,10,31.7,10"></path>
</svg>
</span></span></td></tr><tr><td class="align-middle pr-10px" style="font-size: 12px;"><span style="opacity: 0.5;">09/30/24</span></td><td class="align-middle pr-10px txcode"><a href="https://explorer.duddino.com/tx/163586261d25476a4ce637caf3eadf478a04a91ec8497760a35e478e47f4df9d" target="_blank" rel="noopener noreferrer"><code class="wallet-code text-center active ptr" style="padding: 4px 9px;">Sent to self</code></a></td><td class="align-middle pr-10px"><b style="font-family: &quot;Montserrat Medium&quot;; font-size: 13px; font-weight: 100;"><i class="fa-solid fa-minus" style="padding-right: 5px; color: rgb(249, 60, 76);"></i><span style="font-weight: 300;">0<span style="opacity: 0.55; font-size: 13px">.01</span></span><span style="font-weight: 300; opacity: 0.55;">&nbsp;PIV</span></b></td><td class="text-right pr-10px align-middle"><span class="badge mb-0 badge-purple"><span class="checkIcon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
</span></span></td></tr><tr><td class="align-middle pr-10px" style="font-size: 12px;"><span style="opacity: 0.5;">09/30/24</span></td><td class="align-middle pr-10px txcode"><a href="https://explorer.duddino.com/tx/163586261d25476a4ce637caf3eadf478a04a91ec8497760a35e478e47f4df9d" target="_blank" rel="noopener noreferrer"><code class="wallet-code text-center active ptr" style="padding: 4px 9px;">Sent to self</code></a></td><td class="align-middle pr-10px"><b style="font-family: &quot;Montserrat Medium&quot;; font-size: 13px; font-weight: 100;"><i class="fa-solid fa-recycle" style="padding-right: 5px; color: white;"></i><span style="font-weight: 300;">0<span style="opacity: 0.55; font-size: 13px">.01</span></span><span style="font-weight: 300; opacity: 0.55;">&nbsp;PIV</span></b></td><td class="text-right pr-10px align-middle"><span class="badge mb-0 badge-purple"><span class="checkIcon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<path d="M31.7,10l-18,18c-0.7,0.7-1.8,0.7-2.5,0c0,0,0,0,0,0l-11-11c-0.3-0.3-0.3-0.9,0-1.2c0,0,0,0,0,0l5-5c0.3-0.3,0.9-0.3,1.2,0
c0,0,0,0,0,0l6,6l13-13c0.3-0.3,0.9-0.3,1.3,0l5,5C32.1,9.1,32.1,9.6,31.7,10C31.8,10,31.8,10,31.7,10C31.7,10,31.7,10,31.7,10"></path>
</svg>
Expand Down
104 changes: 68 additions & 36 deletions scripts/dashboard/Activity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import { Database } from '../database.js';
import { HistoricalTx, HistoricalTxType } from '../historical_tx.js';
import { getNameOrAddress } from '../contacts-book.js';
import { getEventEmitter } from '../event_bus';
import { beautifyNumber } from '../misc';

import iCheck from '../../assets/icons/icon-check.svg';
import iHourglass from '../../assets/icons/icon-hourglass.svg';
import { blockCount } from '../global.js';
import { beautifyNumber } from '../misc.js';

const props = defineProps({
title: String,
Expand Down Expand Up @@ -70,6 +70,39 @@ const txMap = computed(() => {
};
});

/**
* Returns the information that we need to show (icon + label + amount) for a self transaction
* @param {number} amount - The net amount of transparent PIVs in a transaction
* @param {number} shieldAmount - The net amount of shielded PIVs in a transaction
*/
function txSelfMap(amount, shieldAmount) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow the design colors/icons

if (shieldAmount == 0 || amount == 0) {
return {
icon: 'fa-recycle',
colour: 'white',
content:
shieldAmount == 0
? translation.activitySentTo
: 'Shield sent to self',
amount: Math.abs(shieldAmount + amount),
};
} else if (shieldAmount > 0) {
return {
icon: 'fa-shield',
colour: 'white',
content: 'Shielding',
amount: shieldAmount,
};
} else if (shieldAmount < 0) {
return {
icon: 'fa-shield',
colour: 'white',
content: 'De-Shielding',
amount: amount,
};
}
}

async function update(txToAdd = 0) {
// Return if wallet is not synced yet
if (!wallet.isSynced) {
Expand Down Expand Up @@ -175,61 +208,39 @@ async function parseTXs(arrTXs) {
// Update the time cache
prevTimestamp = cTx.time * 1000;

let amountToShow = Math.abs(cTx.amount + cTx.shieldAmount);

// Coinbase Transactions (rewards) require coinbaseMaturity confs
const fConfirmed =
blockCount - cTx.blockHeight >=
(cTx.type === HistoricalTxType.STAKE
? cChainParams.current.coinbaseMaturity
: 6);

// Choose the content type, for the Dashboard; use a generative description, otherwise, a TX-ID
// let txContent = props.rewards ? cTx.id : 'Block Reward';

// Format the amount to reduce text size
let formattedAmt = '';
if (cTx.amount < 0.01) {
formattedAmt = beautifyNumber('0.01', '13px');
} else if (cTx.amount >= 100) {
formattedAmt = beautifyNumber(
Math.round(cTx.amount).toString(),
'13px'
);
} else {
formattedAmt = beautifyNumber(`${cTx.amount.toFixed(2)}`, '13px');
}

// For 'Send' TXs: Check if this is a send-to-self transaction
let fSendToSelf = false;
if (cTx.type === HistoricalTxType.SENT) {
fSendToSelf = true;
// Check all addresses to find our own, caching them for performance
for (const strAddr of cTx.receivers) {
// If a previous Tx checked this address, skip it, otherwise, check it against our own address(es)
if (!wallet.isOwnAddress(strAddr)) {
// External address, this is not a self-only Tx
fSendToSelf = false;
}
}
}

// Take the icon, colour and content based on the type of the transaction
let { icon, colour, content } = txMap.value[cTx.type];
const match = content.match(/{(.)}/);
if (match) {
let who = '';
if (fSendToSelf) {
if (cTx.isToSelf && cTx.type !== HistoricalTxType.DELEGATION) {
who = translation.activitySelf;
} else if (cTx.shieldedOutputs) {
who = translation.activityShieldedAddress;
const descriptor = txSelfMap(cTx.amount, cTx.shieldAmount);
icon = descriptor.icon;
colour = descriptor.colour;
content = descriptor.content;
amountToShow = descriptor.amount;
} else {
const arrAddresses = cTx.receivers
let arrAddresses = cTx.receivers
.map((addr) => [wallet.isOwnAddress(addr), addr])
.filter(([isOwnAddress, _]) => {
return cTx.type === HistoricalTxType.RECEIVED
? isOwnAddress
: !isOwnAddress;
})
.map(([_, addr]) => getNameOrAddress(cAccount, addr));
if (cTx.type == HistoricalTxType.RECEIVED) {
arrAddresses = arrAddresses.concat(cTx.shieldReceivers);
}
who =
[
...new Set(
Expand All @@ -240,16 +251,37 @@ async function parseTXs(arrTXs) {
)
),
].join(', ') + '...';
if (
cTx.type == HistoricalTxType.SENT &&
arrAddresses.length == 0
) {
// We sent a shield note to someone, but we cannot decrypt the recipient
// So show a generic "Sent to shield address"
who = translation.activityShieldedAddress;
}
}
content = content.replace(/{.}/, who);
}

// Format the amount to reduce text size
let formattedAmt = '';
if (amountToShow < 0.01) {
formattedAmt = beautifyNumber('0.01', '13px');
} else if (amountToShow >= 100) {
formattedAmt = beautifyNumber(
Math.round(amountToShow).toString(),
'13px'
);
} else {
formattedAmt = beautifyNumber(`${amountToShow.toFixed(2)}`, '13px');
}

newTxs.push({
date: strDate,
id: cTx.id,
content: props.rewards ? cTx.id : content,
formattedAmt,
amount: cTx.amount,
amount: amountToShow,
confirmed: fConfirmed,
icon,
colour,
Expand Down
17 changes: 12 additions & 5 deletions scripts/historical_tx.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,34 @@ export class HistoricalTx {
* @param {HistoricalTxType} type - The type of transaction.
* @param {string} id - The transaction ID.
* @param {Array<string>} receivers - The list of 'output addresses'.
* @param {boolean} shieldedOutputs - If this transaction contains Shield outputs.
* @param {Array<string>} shieldReceivers - The list of decrypted 'shield output addresses'.
* @param {number} time - The block time of the transaction.
* @param {number} blockHeight - The block height of the transaction.
* @param {number} amount - The amount transacted, in coins.
* @param {number} amount - The transparent amount transacted, in coins.
* @param {number} shieldAmount - The shielded amount transacted, in coins.
* @param {boolean} isToSelf - If the transaction is to self.
* @param {boolean} isConfirmed - Whether the transaction has been confirmed.
*/
constructor(
type,
id,
receivers,
shieldedOutputs,
shieldReceivers,
time,
blockHeight,
amount
amount,
shieldAmount,
isToSelf
) {
this.type = type;
this.id = id;
this.receivers = receivers;
this.shieldedOutputs = shieldedOutputs;
this.shieldReceivers = shieldReceivers;
this.time = time;
this.blockHeight = blockHeight;
this.amount = amount;
this.shieldAmount = shieldAmount;
this.isToSelf = isToSelf;
}
}

Expand Down
38 changes: 22 additions & 16 deletions scripts/mempool.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,15 @@ export class Mempool {
* @param {import('./transaction.js').Transaction} tx
*/
getDebit(tx) {
return tx.vin
.filter(
(input) =>
this.getOutpointStatus(input.outpoint) & OutpointState.OURS
)
const filteredVin = tx.vin.filter(
(input) =>
this.getOutpointStatus(input.outpoint) & OutpointState.OURS
);
const debit = filteredVin
.map((i) => this.outpointToUTXO(i.outpoint))
.reduce((acc, u) => acc + (u?.value || 0), 0);
const ownAllVin = tx.vin.length === filteredVin.length;
return { debit, ownAllVin };
}

/**
Expand All @@ -133,17 +135,21 @@ export class Mempool {
getCredit(tx) {
const txid = tx.txid;

return tx.vout
.filter(
(_, i) =>
this.getOutpointStatus(
new COutpoint({
txid,
n: i,
})
) & OutpointState.OURS
)
.reduce((acc, u) => acc + u?.value ?? 0, 0);
const filteredVout = tx.vout.filter(
(_, i) =>
this.getOutpointStatus(
new COutpoint({
txid,
n: i,
})
) & OutpointState.OURS
);
const credit = filteredVout.reduce((acc, u) => acc + u?.value ?? 0, 0);
const ownAllVout = tx.vout.length === filteredVout.length;
return {
credit,
ownAllVout,
};
}

/**
Expand Down
4 changes: 4 additions & 0 deletions scripts/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export function bytesToHex(bytes) {
return Buffer.from(bytes).toString('hex');
}

export function reverseAndSwapEndianess(hex) {
return bytesToHex(hexToBytes(hex).reverse());
}

/**
* Double SHA256 hash a byte array
* @param {Array<number>} buff - Bytes to hash
Expand Down
Loading
Loading