bitcore-node
Version:
A blockchain indexing node with extended capabilities using bitcore
193 lines • 8.69 kB
JavaScript
"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CoinStorage = exports.CoinModel = void 0;
const Loggify_1 = require("../decorators/Loggify");
const logger_1 = __importDefault(require("../logger"));
const libs_1 = require("../providers/libs");
const utils_1 = require("../utils");
const base_1 = require("./base");
const block_1 = require("./block");
let CoinModel = class CoinModel extends base_1.BaseModel {
constructor(storage) {
super('coins', storage);
this.allowedPaging = [
{ key: 'mintHeight', type: 'number' },
{ key: 'spentHeight', type: 'number' }
];
}
onConnect() {
this.collection.createIndex({ mintTxid: 1, mintIndex: 1 }, { background: true });
this.collection.createIndex({ address: 1, chain: 1, network: 1 }, {
background: true,
partialFilterExpression: {
spentHeight: { $lt: 0 }
}
});
this.collection.createIndex({ address: 1 }, { background: true });
this.collection.createIndex({ chain: 1, network: 1, mintHeight: 1 }, { background: true });
this.collection.createIndex({ spentTxid: 1 }, { background: true, sparse: true });
this.collection.createIndex({ chain: 1, network: 1, spentHeight: 1 }, { background: true });
this.collection.createIndex({ wallets: 1, spentHeight: 1, value: 1, mintHeight: 1 }, { background: true, partialFilterExpression: { 'wallets.0': { $exists: true } } });
this.collection.createIndex({ wallets: 1, spentTxid: 1 }, { background: true, partialFilterExpression: { 'wallets.0': { $exists: true } } });
this.collection.createIndex({ wallets: 1, mintTxid: 1 }, { background: true, partialFilterExpression: { 'wallets.0': { $exists: true } } });
}
async getBalance(params, options = {}) {
let { query } = params;
const result = await this.collection
.aggregate([
{ $match: query },
{
$project: {
value: 1,
status: {
$cond: {
if: { $gte: ['$mintHeight', 0 /* SpentHeightIndicators.minimum */] },
then: 'confirmed',
else: 'unconfirmed'
}
},
_id: 0
}
},
{
$group: {
_id: '$status',
balance: { $sum: '$value' }
}
}
], options)
.toArray();
return result.reduce((acc, cur) => {
acc[cur._id] = cur.balance;
acc.balance += cur.balance;
return acc;
}, { confirmed: 0, unconfirmed: 0, balance: 0 });
}
async getBalanceAtTime(params) {
let { query, time, chain, network } = params;
const [block] = await block_1.BitcoinBlockStorage.collection
.find({
$query: {
chain,
network,
timeNormalized: { $lte: new Date(time) }
}
})
.limit(1)
.sort({ timeNormalized: -1 })
.toArray();
const blockHeight = block.height;
const combinedQuery = Object.assign({}, {
$or: [{ spentHeight: { $gt: blockHeight } }, { spentHeight: { $lt: 0 /* SpentHeightIndicators.minimum */ } }],
mintHeight: { $lte: blockHeight }
}, query);
return this.getBalance({ query: combinedQuery }, { hint: { wallets: 1, spentHeight: 1, value: 1, mintHeight: 1 } });
}
resolveAuthhead(mintTxid, chain, network) {
return this.collection
.aggregate([
{
$match: {
mintTxid: mintTxid.toLowerCase(),
mintIndex: 0,
...(typeof chain === 'string' ? { chain } : {}),
...(typeof network === 'string' ? { network } : {})
}
},
{
$graphLookup: {
from: 'coins',
startWith: '$spentTxid',
connectFromField: 'spentTxid',
connectToField: 'mintTxid',
as: 'authheads',
maxDepth: 1000000,
restrictSearchWithMatch: {
mintIndex: 0
}
}
},
{
$project: {
chain: '$chain',
network: '$network',
authbase: '$mintTxid',
identityOutputs: {
$filter: {
input: '$authheads',
as: 'authhead',
cond: {
$and: [
{
$lte: ['$$authhead.spentHeight', -1]
},
{
$eq: ['$$authhead.chain', '$chain']
},
{
$eq: ['$$authhead.network', '$network']
}
]
}
}
}
}
}
])
.toArray();
}
_apiTransform(coin, options) {
// try to parse coin.address if its 'false' and script exists
if (coin.address == 'false' && coin.script != undefined && coin.script.toString() != '') {
try {
const lib = libs_1.Libs.get(coin.chain).lib;
const address = lib
.Script(coin.script.toString('hex'))
.toAddress(coin.network)
.toString();
if (lib.Address.isValid(address, coin.network)) {
coin.address = address;
// update coin record in db - do it asynchronously as we don't need to wait for result
exports.CoinStorage.collection.updateOne({ _id: coin._id }, { $set: { address: coin.address } });
}
}
catch (e) {
logger_1.default.debug(`Could not parse address on "${coin.chain}:${coin.network}" for coin ${coin.mintTxid}[${coin.mintIndex}]`);
}
}
const transform = {
chain: (0, utils_1.valueOrDefault)(coin.chain, ''),
network: (0, utils_1.valueOrDefault)(coin.network, ''),
coinbase: (0, utils_1.valueOrDefault)(coin.coinbase, false),
mintIndex: (0, utils_1.valueOrDefault)(coin.mintIndex, -1),
spentTxid: (0, utils_1.valueOrDefault)(coin.spentTxid, ''),
mintTxid: (0, utils_1.valueOrDefault)(coin.mintTxid, ''),
mintHeight: (0, utils_1.valueOrDefault)(coin.mintHeight, -1),
spentHeight: (0, utils_1.valueOrDefault)(coin.spentHeight, -4 /* SpentHeightIndicators.error */),
address: (0, utils_1.valueOrDefault)(coin.address, ''),
script: (0, utils_1.valueOrDefault)(coin.script, Buffer.alloc(0)).toString('hex'),
value: (0, utils_1.valueOrDefault)(coin.value, -1),
confirmations: (0, utils_1.valueOrDefault)(coin.confirmations ?? options?.confirmations, -1),
sequenceNumber: (0, utils_1.valueOrDefault)(coin.sequenceNumber, undefined)
};
if (options && options.object) {
return transform;
}
return JSON.stringify(transform);
}
};
exports.CoinModel = CoinModel;
exports.CoinModel = CoinModel = __decorate([
Loggify_1.LoggifyClass
], CoinModel);
exports.CoinStorage = new CoinModel();
//# sourceMappingURL=coin.js.map