Skip to content

Commit

Permalink
Merge pull request bitpay#551 from bitpay/feature/insightui-get-blocks
Browse files Browse the repository at this point in the history
Get Blocks for Insight Ui
  • Loading branch information
micahriggan authored Apr 4, 2018
2 parents dd5b944 + 5255010 commit 226fc0d
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 107 deletions.
1 change: 1 addition & 0 deletions lib/models/block.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ BlockSchema.statics._apiTransform = function(block, options){
nextBlockHash: block.nextBlockHash,
reward: block.reward,
isMainChain: block.mainChain,
transactionCount: block.transactionCount,
minedBy: Block.getPoolInfo(block.minedBy)
};
if(options && options.object){
Expand Down
182 changes: 118 additions & 64 deletions lib/models/transaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const TransactionSchema = new Schema({
fee: Number,
size: Number,
locktime: Number,
wallets: { type: [Schema.Types.ObjectId] },
wallets: { type: [Schema.Types.ObjectId] }
});

TransactionSchema.index({ txid: 1 });
Expand All @@ -27,62 +27,88 @@ TransactionSchema.index({ blockHash: 1 });
TransactionSchema.index({ chain: 1, network: 1, blockTimeNormalized: 1 });
TransactionSchema.index({ wallets: 1 }, { sparse: true });

TransactionSchema.statics.batchImport = async function (params) {
return new Promise(async (resolve) => {
TransactionSchema.statics.batchImport = async function(params) {
return new Promise(async resolve => {
let partition = (array, n) => {
return array.length ? [array.splice(0, n)].concat(partition(array, n)) : [];
return array.length
? [array.splice(0, n)].concat(partition(array, n))
: [];
};
let mintOps = await Transaction.mintCoins(params);
if (mintOps.length){
if (mintOps.length) {
mintOps = partition(mintOps, 100);
mintOps = mintOps.map((mintBatch) => Coin.collection.bulkWrite(mintBatch, { ordered: false }));
mintOps = mintOps.map(mintBatch =>
Coin.collection.bulkWrite(mintBatch, { ordered: false })
);
await Promise.all(mintOps);
}

let spendOps = Transaction.spendCoins(params);
if (spendOps.length){
if (spendOps.length) {
spendOps = partition(spendOps, 100);
spendOps = spendOps.map((spendBatch) => Coin.collection.bulkWrite(spendBatch, {ordered: false}));
spendOps = spendOps.map(spendBatch =>
Coin.collection.bulkWrite(spendBatch, { ordered: false })
);
await Promise.all(spendOps);
}

let txOps = await Transaction.addTransactions(params);
txOps = partition(txOps, 100);
txOps = txOps.map((txBatch) => Transaction.collection.bulkWrite(txBatch, {ordered: false}));
txOps = txOps.map(txBatch =>
Transaction.collection.bulkWrite(txBatch, { ordered: false })
);
await Promise.all(txOps);
resolve();
});
};

TransactionSchema.statics.addTransactions = async function(params){
let { blockHash, blockTime, blockTimeNormalized, chain, height, network, txs } = params;
TransactionSchema.statics.addTransactions = async function(params) {
let {
blockHash,
blockTime,
blockTimeNormalized,
chain,
height,
network,
txs
} = params;
return new Promise(async (resolve, reject) => {
let txids = txs.map((tx) => tx._hash);
let txids = txs.map(tx => tx._hash);
let mintWallets, spentWallets;
try {
mintWallets = await Coin.collection.aggregate([
{
$match: { mintTxid: {$in: txids}, chain, network }
},
{ $unwind: '$wallets' },
{ $group: { _id: '$mintTxid', wallets: { $addToSet: '$wallets' } } }
]).toArray();
spentWallets = await Coin.collection.aggregate([
{
$match: { spentTxid: { $in: txids }, chain, network }
},
{ $unwind: '$wallets' },
{ $group: { _id: '$spentTxid', wallets: { $addToSet: '$wallets' } } }
]).toArray();
} catch (e){
mintWallets = await Coin.collection
.aggregate([
{
$match: { mintTxid: { $in: txids }, chain, network }
},
{ $unwind: '$wallets' },
{ $group: { _id: '$mintTxid', wallets: { $addToSet: '$wallets' } } }
])
.toArray();
spentWallets = await Coin.collection
.aggregate([
{
$match: { spentTxid: { $in: txids }, chain, network }
},
{ $unwind: '$wallets' },
{ $group: { _id: '$spentTxid', wallets: { $addToSet: '$wallets' } } }
])
.toArray();
} catch (e) {
reject(e);
}

let txOps = txs.map((tx, index) => {
let wallets = [];
for (let wallet of mintWallets.concat(spentWallets).filter((wallet) => wallet._id === txids[index])){
for (let walletMatch of wallet.wallets){
if (!wallets.find((wallet) => wallet.toHexString() === walletMatch.toHexString())){
for (let wallet of mintWallets
.concat(spentWallets)
.filter(wallet => wallet._id === txids[index])) {
for (let walletMatch of wallet.wallets) {
if (
!wallets.find(
wallet => wallet.toHexString() === walletMatch.toHexString()
)
) {
wallets.push(walletMatch);
}
}
Expand Down Expand Up @@ -118,29 +144,43 @@ TransactionSchema.statics.addTransactions = async function(params){
});
};

TransactionSchema.statics.mintCoins = async function (params) {
TransactionSchema.statics.mintCoins = async function(params) {
return new Promise(async (resolve, reject) => {
let { chain, height, network, txs, parentChain, forkHeight } = params;
let mintOps = [];
let parentChainCoins = [];
if (parentChain && height < forkHeight) {
parentChainCoins = await Coin.find({ chain: parentChain, network, mintHeight: height, spentHeight: {$gt: -2, $lt: forkHeight} }).lean();
parentChainCoins = await Coin.find({
chain: parentChain,
network,
mintHeight: height,
spentHeight: { $gt: -2, $lt: forkHeight }
}).lean();
}
for (let tx of txs) {
tx._hash = tx.hash;
let txid = tx._hash;
let isCoinbase = tx.isCoinbase();
for (let [index, output] of tx.outputs.entries()) {
let parentChainCoin = parentChainCoins.find((parentChainCoin) => parentChainCoin.mintTxid === txid && parentChainCoin.mintIndex === index);
if (parentChainCoin){
let parentChainCoin = parentChainCoins.find(
parentChainCoin =>
parentChainCoin.mintTxid === txid &&
parentChainCoin.mintIndex === index
);
if (parentChainCoin) {
continue;
}
let address = '';
let scriptBuffer = output.script && output.script.toBuffer();
if (scriptBuffer){
if (scriptBuffer) {
address = output.script.toAddress(network).toString(true);
if (address === 'false' && output.script.classify() === 'Pay to public key') {
let hash = Chain[chain].lib.crypto.Hash.sha256ripemd160(output.script.chunks[0].buf);
if (
address === 'false' &&
output.script.classify() === 'Pay to public key'
) {
let hash = Chain[chain].lib.crypto.Hash.sha256ripemd160(
output.script.chunks[0].buf
);
address = Chain[chain].lib.Address(hash, network).toString(true);
}
}
Expand Down Expand Up @@ -173,26 +213,37 @@ TransactionSchema.statics.mintCoins = async function (params) {
});
}
}
let mintOpsAddresses = mintOps.map((mintOp) => mintOp.updateOne.update.$set.address);
let mintOpsAddresses = mintOps.map(
mintOp => mintOp.updateOne.update.$set.address
);
try {
let wallets = await WalletAddress.collection.find({ chain, network, address: { $in: mintOpsAddresses } }, { batchSize: 100}).toArray();
if (wallets.length){
mintOps = mintOps.map((mintOp) => {
mintOp.updateOne.update.$set.wallets = wallets.filter((wallet) => wallet.address === mintOp.updateOne.update.$set.address).map((wallet) => wallet.wallet);
let wallets = await WalletAddress.collection
.find(
{ chain, network, address: { $in: mintOpsAddresses } },
{ batchSize: 100 }
)
.toArray();
if (wallets.length) {
mintOps = mintOps.map(mintOp => {
mintOp.updateOne.update.$set.wallets = wallets
.filter(
wallet => wallet.address === mintOp.updateOne.update.$set.address
)
.map(wallet => wallet.wallet);
return mintOp;
});
}
resolve(mintOps);
} catch(e){
} catch (e) {
reject(e);
}
});
};

TransactionSchema.statics.spendCoins = function (params) {
TransactionSchema.statics.spendCoins = function(params) {
let { chain, network, height, txs, parentChain, forkHeight } = params;
let spendOps = [];
if (parentChain && height < forkHeight){
if (parentChain && height < forkHeight) {
return spendOps;
}
for (let tx of txs) {
Expand All @@ -212,7 +263,9 @@ TransactionSchema.statics.spendCoins = function (params) {
network
},
update: {
...(config.pruneSpentScripts && height > 0 ? {$unset : { script: null }}: {}),
...(config.pruneSpentScripts && height > 0
? { $unset: { script: null } }
: {}),
$set: {
spentTxid: txid,
spentHeight: height
Expand All @@ -225,27 +278,25 @@ TransactionSchema.statics.spendCoins = function (params) {
return spendOps;
};

TransactionSchema.statics.getTransactions = function (params) {
TransactionSchema.statics.getTransactions = function(params) {
let query = params.query;
return this.collection.aggregate([
{ $match: query },
{
$lookup:
{
from: 'coins',
localField: 'txid',
foreignField: 'spentTxid',
as: 'inputs'
}
$lookup: {
from: 'coins',
localField: 'txid',
foreignField: 'spentTxid',
as: 'inputs'
}
},
{
$lookup:
{
from: 'coins',
localField: 'txid',
foreignField: 'mintTxid',
as: 'outputs'
}
$lookup: {
from: 'coins',
localField: 'txid',
foreignField: 'mintTxid',
as: 'outputs'
}
}
]);
};
Expand All @@ -259,12 +310,15 @@ TransactionSchema.statics._apiTransform = function(tx, options) {
blockTime: tx.blockTime,
blockTimeNormalized: tx.blockTimeNormalized,
coinbase: tx.coinbase,
fee: tx.fee,
fee: tx.fee
};
if(options && options.object) {
if (options && options.object) {
return transform;
}
return JSON.stringify(transform);
};

var Transaction = module.exports = mongoose.model('Transaction', TransactionSchema);
var Transaction = (module.exports = mongoose.model(
'Transaction',
TransactionSchema
));
Loading

0 comments on commit 226fc0d

Please sign in to comment.