Skip to content

Commit

Permalink
Convert to HistoricalTxs only once (#450)
Browse files Browse the repository at this point in the history
* feat: Convert to historical txs only once

* refactor: remove Wallet::getTransactions()

* bug: dynamically compute confirmed txs
  • Loading branch information
panleone authored Nov 6, 2024
1 parent a612e0f commit 7978531
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 37 deletions.
41 changes: 22 additions & 19 deletions scripts/dashboard/Activity.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ 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';
const props = defineProps({
title: String,
Expand Down Expand Up @@ -85,45 +86,40 @@ async function update(txToAdd = 0) {
// If there are less than 10 txs loaded, append rather than update the list
if (txCount < 10 && txToAdd == 0) txToAdd = 10;
let found = 0;
// Since ECMAScript 2019 .sort is stable.
// https://caniuse.com/mdn-javascript_builtins_array_sort_stable
const orderedTxs = Array.from(wallet.getTransactions()).sort(
(a, b) => a.blockHeight - b.blockHeight
);
const historicalTxs = wallet.getHistoricalTxs();
// For Rewards: aggregate the total amount
if (props.rewards) {
for (const tx of orderedTxs) {
for (const tx of historicalTxs) {
// If this Tx Height is under our last scanned height, we stop
if (tx.blockHeight <= nRewardUpdateHeight) break;
// Only compute rewards
if (!tx.isCoinStake()) continue;
if (tx.type != HistoricalTxType.STAKE) continue;
// Aggregate the total rewards
rewardAmount.value += wallet.toHistoricalTXs([tx])[0].amount;
rewardAmount.value += tx.amount;
}
// Keep track of the scan block height
if (orderedTxs.length) {
nRewardUpdateHeight = orderedTxs[0].blockHeight;
if (historicalTxs.length) {
nRewardUpdateHeight = historicalTxs[0].blockHeight;
}
}
// Prepare the Tx History list
let i = 0;
let found = 0;
while (found < txCount + txToAdd) {
if (orderedTxs.length == 0) {
if (i === historicalTxs.length) {
isHistorySynced.value = true;
break;
}
const tx = orderedTxs.pop();
if (props.rewards && !tx.isCoinStake()) continue;
const tx = historicalTxs[i];
i += 1;
if (props.rewards && tx.type != HistoricalTxType.STAKE) continue;
newTxs.push(tx);
found++;
}
// Convert to MPW's Activity format and render it
const arrTXs = wallet.toHistoricalTXs(newTxs);
await parseTXs(arrTXs);
txCount = found;
await parseTXs(newTxs);
updating.value = false;
}
Expand Down Expand Up @@ -179,6 +175,13 @@ async function parseTXs(arrTXs) {
// Update the time cache
prevTimestamp = cTx.time * 1000;
// 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';
Expand Down Expand Up @@ -247,7 +250,7 @@ async function parseTXs(arrTXs) {
content: props.rewards ? cTx.id : content,
formattedAmt,
amount: cTx.amount,
confirmed: cTx.isConfirmed,
confirmed: fConfirmed,
icon,
colour,
});
Expand Down
5 changes: 1 addition & 4 deletions scripts/historical_tx.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export class HistoricalTx {
* @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 {boolean} isConfirmed - Whether the transaction has been confirmed.
*/
constructor(
type,
Expand All @@ -19,8 +18,7 @@ export class HistoricalTx {
shieldedOutputs,
time,
blockHeight,
amount,
isConfirmed
amount
) {
this.type = type;
this.id = id;
Expand All @@ -29,7 +27,6 @@ export class HistoricalTx {
this.time = time;
this.blockHeight = blockHeight;
this.amount = amount;
this.isConfirmed = isConfirmed;
}
}

Expand Down
8 changes: 8 additions & 0 deletions scripts/mempool.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,14 @@ export class Mempool {
return Array.from(this.#txmap.values());
}

/**
* @param {string} txid - transaction id
* @returns {import('./transaction.js').Transaction | undefined}
*/
getTransaction(txid) {
return this.#txmap.get(txid);
}

/**
* @param blockCount - chain height
*/
Expand Down
55 changes: 41 additions & 14 deletions scripts/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ export class Wallet {
* @type {number}
*/
#lastProcessedBlock = 0;
/**
* Array of historical txs, ordered by block height
* @type HistoricalTx[]
*/
#historicalTxs;

constructor({ nAccount, masterKey, shield, mempool = new Mempool() }) {
this.#nAccount = nAccount;
this.#mempool = mempool;
Expand Down Expand Up @@ -247,6 +253,7 @@ export class Wallet {
}
this.#mempool = new Mempool();
this.#lastProcessedBlock = 0;
this.#historicalTxs = [];
}

/**
Expand Down Expand Up @@ -671,10 +678,6 @@ export class Wallet {
} else if (nAmount < 0) {
type = HistoricalTxType.SENT;
}
const isCoinSpecial = tx.isCoinStake() || tx.isCoinBase();
const isConfirmed =
blockCount - tx.blockHeight >=
(isCoinSpecial ? cChainParams.current.coinbaseMaturity : 6);

histTXs.push(
new HistoricalTx(
Expand All @@ -684,13 +687,38 @@ export class Wallet {
false,
tx.blockTime,
tx.blockHeight,
Math.abs(nAmount),
isConfirmed
Math.abs(nAmount)
)
);
}
return histTXs;
}

/**
* @param {Transaction} tx
*/
#pushToHistoricalTx(tx) {
const historicalTx = this.toHistoricalTXs([tx])[0];
let prevHeight = Number.POSITIVE_INFINITY;
for (const [i, hTx] of this.#historicalTxs.entries()) {
if (
historicalTx.blockHeight <= prevHeight &&
historicalTx.blockHeight >= hTx.blockHeight
) {
this.#historicalTxs.splice(i, 0, historicalTx);
return;
}
prevHeight = hTx.blockHeight;
}
this.#historicalTxs.push(historicalTx);
}

/**
* @returns {HistoricalTx[]}
*/
getHistoricalTxs() {
return this.#historicalTxs;
}
sync = lockableFunction(async () => {
if (this.#isSynced) {
throw new Error('Attempting to sync when already synced');
Expand Down Expand Up @@ -724,7 +752,7 @@ export class Wallet {
const cNet = getNetwork();
const addr = this.getKeyToExport();
let nStartHeight = Math.max(
...this.getTransactions().map((tx) => tx.blockHeight)
...this.#mempool.getTransactions().map((tx) => tx.blockHeight)
);
// Compute the total pages and iterate through them until we've synced everything
const totalPages = await cNet.getNumPages(nStartHeight, addr);
Expand Down Expand Up @@ -1157,6 +1185,7 @@ export class Wallet {
* @param {import('./transaction.js').Transaction} transaction
*/
async addTransaction(transaction, skipDatabase = false) {
const tx = this.#mempool.getTransaction(transaction.txid);
this.#mempool.addTransaction(transaction);
let i = 0;
for (const out of transaction.vout) {
Expand All @@ -1182,6 +1211,11 @@ export class Wallet {
const db = await Database.getInstance();
await db.storeTx(transaction);
}
if (!tx || tx.blockHeight === -1) {
// Do not add unconfirmed txs to history
if (transaction.blockHeight !== -1)
this.#pushToHistoricalTx(transaction);
}
}

/**
Expand Down Expand Up @@ -1225,13 +1259,6 @@ export class Wallet {
.filter((u) => u.value === collateralValue);
}

/**
* @returns {import('./transaction.js').Transaction[]} a list of all transactions
*/
getTransactions() {
return this.#mempool.getTransactions();
}

get balance() {
return this.#mempool.getBalance(blockCount);
}
Expand Down

0 comments on commit 7978531

Please sign in to comment.