Skip to content

Commit

Permalink
feat(sync): prune mempool transactions and coins when conflicting one…
Browse files Browse the repository at this point in the history
…s come in
  • Loading branch information
nitsujlangston committed Nov 28, 2018
1 parent e9f816d commit 18ffda1
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 3 deletions.
8 changes: 6 additions & 2 deletions packages/bitcore-node/src/models/coin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ export enum SpentHeightIndicators {
/**
* The coin is unspent, and no transactions spending it have been seen.
*/
unspent = -2
unspent = -2,
/**
* The coin was minted by a transaction which can no longer confirm.
*/
conflicting = -3,
}

@LoggifyClass
Expand Down Expand Up @@ -72,7 +76,7 @@ class Coin extends BaseModel<ICoin> {

getBalance(params: { query: any }) {
let { query } = params;
query = Object.assign(query, { spentHeight: { $lt: 0 } });
query = Object.assign(query, { spentHeight: { $lt: SpentHeightIndicators.minimum }, mintHeight: { $gt: SpentHeightIndicators.conflicting } });
return this.collection
.aggregate<{ balance: number }>([
{ $match: query },
Expand Down
41 changes: 41 additions & 0 deletions packages/bitcore-node/src/models/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export class Transaction extends BaseModel<ITransaction> {
}) {
const mintOps = await this.getMintOps(params);
const spendOps = this.getSpendOps({ ...params, mintOps });
this.pruneMempool({...params, mintOps, spendOps});

logger.debug('Minting Coins', mintOps.length);
if (mintOps.length) {
Expand Down Expand Up @@ -383,6 +384,46 @@ export class Transaction extends BaseModel<ITransaction> {
return spendOps;
}

async pruneMempool(params: {
txs: Array<Bitcoin.Transaction>;
height: number;
parentChain?: string;
forkHeight?: number;
chain: string;
network: string;
mintOps: Array<any>;
spendOps: Array<any>;
initialSyncComplete: boolean;
[rest: string]: any;
}) {
const { chain, network, spendOps, initialSyncComplete } = params;
if (!initialSyncComplete || !spendOps.length) {
return;
}
const spentCoinsQuery = {
chain, network, spentHeight: SpentHeightIndicators.pending, $or: spendOps.map(spendOp => {
return {
mintTxid: spendOp.updateOne.filter.mintTxid,
mintIndex: spendOp.updateOne.filter.mintIndex,
spentTxid: { $ne: spendOp.updateOne.update.$set.spentTxid }
}
})
};
const spendingCoins = await CoinModel.collection.find(spentCoinsQuery).toArray();
if (spendingCoins.length) {
let prunedTxs = {};
for (const coin of spendingCoins) {
prunedTxs[coin.spentTxid] = true;
}
prunedTxs = Object.keys(prunedTxs);
await Promise.all([
this.collection.update({ txid: { $in: prunedTxs } }, { $set: { blockHeight: SpentHeightIndicators.conflicting } }, { w: 0, j: false, multi: true }),
CoinModel.collection.update({ mintTxid: { $in: prunedTxs } }, { $set: { mintHeight: SpentHeightIndicators.conflicting } }, { w: 0, j: false, multi: true })
]);
}
return;
}

getTransactions(params: { query: any; options: StreamingFindOptions<ITransaction> }) {
let originalQuery = params.query;
const { query, options } = Storage.getFindOptions(this, params.options);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ export class InternalStateProvider implements CSP.IChainStateService {

async streamWalletUtxos(params: CSP.StreamWalletUtxosParams) {
const { wallet, limit, args = {}, stream } = params;
let query: any = { wallets: wallet._id };
let query: any = { wallets: wallet._id, mintHeight: { $gt: SpentHeightIndicators.conflicting } };
if (args.includeSpent !== 'true') {
query.spentHeight = { $lt: SpentHeightIndicators.pending };
}
Expand Down

0 comments on commit 18ffda1

Please sign in to comment.