Reliably update inputs. Self-healing. Audit Mongo blockheights
This commit is contained in:
parent
a3941f75ef
commit
2ccaf2fce0
@ -9,11 +9,16 @@ logger.log('debug',
|
|||||||
|
|
||||||
db.connect(config.mongodb.uri, config.mongodb.options);
|
db.connect(config.mongodb.uri, config.mongodb.options);
|
||||||
|
|
||||||
db.connection.once('open', () => {
|
|
||||||
if (config.start_node) Bcoin.start();
|
|
||||||
|
|
||||||
Api.listen(config.api.port, () => {
|
db.connection.once('open', () => {
|
||||||
logger.log('debug',
|
// DB Audit returns best height to node
|
||||||
'listening on port 3000');
|
db.blocks.findMissingBlocks((err, lastBestHeight) => {
|
||||||
|
// Pass height to node to start Sync
|
||||||
|
if (config.start_node) Bcoin.start(lastBestHeight);
|
||||||
|
|
||||||
|
Api.listen(config.api.port, () => {
|
||||||
|
logger.log('debug',
|
||||||
|
'listening on port 3000');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,7 +2,6 @@ const Block = require('../../models/block.js');
|
|||||||
const logger = require('../logger');
|
const logger = require('../logger');
|
||||||
const config = require('../../config');
|
const config = require('../../config');
|
||||||
|
|
||||||
const block = new Block();
|
|
||||||
|
|
||||||
let bestBlockHeight = 0;
|
let bestBlockHeight = 0;
|
||||||
|
|
||||||
@ -20,27 +19,48 @@ function bestHeight(height) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getRawBlock(hash, cb) {
|
function getRawBlock(hash, cb) {
|
||||||
return block.getRawBlock(hash, cb);
|
return Block.getRawBlock(hash, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function byHeight(height, cb) {
|
function byHeight(height, cb) {
|
||||||
return block.byHeight(height, cb);
|
return Block.byHeight(height, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopBlocks(cb) {
|
function getTopBlocks(cb) {
|
||||||
return block.last(cb);
|
return Block.last(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getByHash(hash, cb) {
|
function getByHash(hash, cb) {
|
||||||
return block.byHash(hash, cb);
|
return Block.byHash(hash, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLastBlock(cb) {
|
function getLastBlock(cb) {
|
||||||
return block.last(cb)
|
return Block.last(cb)
|
||||||
.limit(1);
|
.limit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the missing block if it exists. Otherwise, return tip.
|
||||||
|
function findMissingBlocks(cb) {
|
||||||
|
logger.log('debug',
|
||||||
|
'Verifying Mongo Blockchain');
|
||||||
|
return Block.getHeights((err, blocks) => {
|
||||||
|
if (err) {
|
||||||
|
return cb(err);
|
||||||
|
}
|
||||||
|
// Blocks are in ascending order
|
||||||
|
let lastGoodHeight = 0;
|
||||||
|
blocks.forEach((block) => {
|
||||||
|
if (lastGoodHeight !== block.height - 1) {
|
||||||
|
return lastGoodHeight;
|
||||||
|
}
|
||||||
|
lastGoodHeight = block.height;
|
||||||
|
});
|
||||||
|
return lastGoodHeight;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
findMissingBlocks,
|
||||||
getRawBlock,
|
getRawBlock,
|
||||||
getTopBlocks,
|
getTopBlocks,
|
||||||
getLastBlock,
|
getLastBlock,
|
||||||
|
|||||||
@ -2,44 +2,45 @@ const Transactions = require('../../models/transaction.js');
|
|||||||
const config = require('../../config');
|
const config = require('../../config');
|
||||||
const logger = require('../logger');
|
const logger = require('../logger');
|
||||||
|
|
||||||
const Txs = new Transactions();
|
|
||||||
const MAX_PAGE_TXS = config.api.max_page_txs;
|
const MAX_PAGE_TXS = config.api.max_page_txs;
|
||||||
|
|
||||||
function getEmptyInputs(cb) {
|
function getEmptyInputs(cb) {
|
||||||
return Txs.getEmptyInputs(cb);
|
return Transactions.getEmptyInputs(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTopTransactions(cb) {
|
function getTopTransactions(cb) {
|
||||||
return Txs.last(cb);
|
return Transactions.last(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTxById(txid, cb) {
|
function getTxById(txid, cb) {
|
||||||
return Txs.byId(txid, cb);
|
return Transactions.byId(txid, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTxByBlock(blockHash, page, limit, cb) {
|
function getTxByBlock(blockHash, page, limit, cb) {
|
||||||
return Txs.byBlockHash(blockHash, cb)
|
return Transactions.byBlockHash(blockHash, cb)
|
||||||
.skip(limit * page);
|
.skip(limit * page);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTxByAddress(address, page, limit, cb) {
|
function getTxByAddress(address, page, limit, cb) {
|
||||||
return Txs.byAddress(address, cb)
|
return Transactions.byAddress(address, cb)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.skip(limit * page);
|
.skip(limit * page);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTxCountByBlock(blockHash, cb) {
|
function getTxCountByBlock(blockHash, cb) {
|
||||||
return Txs.countByBlock(blockHash, cb);
|
return Transactions.countByBlock(blockHash, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTxCountByAddress(address, cb) {
|
function getTxCountByAddress(address, cb) {
|
||||||
return Txs.countByAddress(address, cb);
|
return Transactions.countByAddress(address, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateInput(txid, inputid, value, address) {
|
function updateInput(txid, inputid, value, address) {
|
||||||
return Txs.updateInput(txid, inputid, value, address);
|
return Transactions.updateInput(txid, inputid, value, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Updates empty inputs with prevout addr & value
|
||||||
function auditInputs() {
|
function auditInputs() {
|
||||||
getEmptyInputs(
|
getEmptyInputs(
|
||||||
(err, txs) => {
|
(err, txs) => {
|
||||||
@ -48,9 +49,6 @@ function auditInputs() {
|
|||||||
`No Empty Inputs found: ${err.err}`);
|
`No Empty Inputs found: ${err.err}`);
|
||||||
}
|
}
|
||||||
// For each tx with unmarked inputs
|
// For each tx with unmarked inputs
|
||||||
logger.log('debug',
|
|
||||||
`Found ${txs.length} txs with inputs to update`);
|
|
||||||
|
|
||||||
return txs.forEach((inputTx) => {
|
return txs.forEach((inputTx) => {
|
||||||
inputTx.inputs.forEach((input) => {
|
inputTx.inputs.forEach((input) => {
|
||||||
const txHash = input.prevout.hash;
|
const txHash = input.prevout.hash;
|
||||||
|
|||||||
@ -9,11 +9,12 @@ const db = require('../../lib/db');
|
|||||||
const node = new FullNode(config.bcoin);
|
const node = new FullNode(config.bcoin);
|
||||||
let doneSyncing = false;
|
let doneSyncing = false;
|
||||||
|
|
||||||
function start() {
|
function start(bestBlockHeight) {
|
||||||
node.open()
|
node.open()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
node.connect()
|
node.connect()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
node.reset(bestBlockHeight);
|
||||||
node.startSync();
|
node.startSync();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -31,26 +31,26 @@ const BlockSchema = new Schema({
|
|||||||
BlockSchema.index({ hash: 1 });
|
BlockSchema.index({ hash: 1 });
|
||||||
BlockSchema.index({ height: 1 });
|
BlockSchema.index({ height: 1 });
|
||||||
|
|
||||||
BlockSchema.methods.byHeight = function blockByHeight(height, cb) {
|
BlockSchema.statics.byHeight = function blockByHeight(height, cb) {
|
||||||
return this.model('Block').findOne(
|
return this.model('Block').findOne(
|
||||||
{ height },
|
{ height },
|
||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockSchema.methods.byHash = function byHash(hash, cb) {
|
BlockSchema.statics.byHash = function byHash(hash, cb) {
|
||||||
return this.model('Block').findOne(
|
return this.model('Block').findOne(
|
||||||
{ hash },
|
{ hash },
|
||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockSchema.methods.getRawBlock = function getRawBlock(hash, cb) {
|
BlockSchema.statics.getRawBlock = function getRawBlock(hash, cb) {
|
||||||
return this.model('Block').findOne(
|
return this.model('Block').findOne(
|
||||||
{ hash },
|
{ hash },
|
||||||
{ rawBlock: 1 },
|
{ rawBlock: 1 },
|
||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
BlockSchema.methods.last = function lastBlocks(cb) {
|
BlockSchema.statics.last = function lastBlocks(cb) {
|
||||||
return this.model('Block').find(
|
return this.model('Block').find(
|
||||||
{},
|
{},
|
||||||
cb)
|
cb)
|
||||||
@ -58,4 +58,12 @@ BlockSchema.methods.last = function lastBlocks(cb) {
|
|||||||
.sort({ height: -1 });
|
.sort({ height: -1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BlockSchema.statics.getHeights = function findMissing(cb) {
|
||||||
|
return this.model('Block').find(
|
||||||
|
{},
|
||||||
|
{ height: 1 },
|
||||||
|
cb)
|
||||||
|
.sort({ height: 1 });
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = mongoose.model('Block', BlockSchema);
|
module.exports = mongoose.model('Block', BlockSchema);
|
||||||
|
|||||||
@ -32,24 +32,24 @@ TransactionSchema.index({ 'outputs.address': 1 });
|
|||||||
TransactionSchema.index({ 'inputs.address': 1 });
|
TransactionSchema.index({ 'inputs.address': 1 });
|
||||||
|
|
||||||
|
|
||||||
TransactionSchema.methods.byId = function txById(txid, cb) {
|
TransactionSchema.statics.byId = function txById(txid, cb) {
|
||||||
return this.model('Transaction').findOne(
|
return this.model('Transaction').findOne(
|
||||||
{ hash: txid },
|
{ hash: txid },
|
||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.byHash = function txByHash(hash, cb) {
|
TransactionSchema.statics.byHash = function txByHash(hash, cb) {
|
||||||
return this.byId(hash, cb);
|
return this.byId(hash, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.byBlockHash = function txByBlockHash(hash, cb) {
|
TransactionSchema.statics.byBlockHash = function txByBlockHash(hash, cb) {
|
||||||
return this.model('Transaction').find(
|
return this.model('Transaction').find(
|
||||||
{ block: hash },
|
{ block: hash },
|
||||||
cb)
|
cb)
|
||||||
.limit(MAX_TXS);
|
.limit(MAX_TXS);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.byAddress = function txByAddress(address, cb) {
|
TransactionSchema.statics.byAddress = function txByAddress(address, cb) {
|
||||||
return this.model('Transaction').find(
|
return this.model('Transaction').find(
|
||||||
{
|
{
|
||||||
$or: [
|
$or: [
|
||||||
@ -60,13 +60,13 @@ TransactionSchema.methods.byAddress = function txByAddress(address, cb) {
|
|||||||
.limit(MAX_TXS);
|
.limit(MAX_TXS);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.countByBlock = function txByAddress(hash, cb) {
|
TransactionSchema.statics.countByBlock = function txByAddress(hash, cb) {
|
||||||
return this.model('Transaction').count(
|
return this.model('Transaction').count(
|
||||||
{ block: hash },
|
{ block: hash },
|
||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.countByAddress = function txByAddress(address, cb) {
|
TransactionSchema.statics.countByAddress = function txByAddress(address, cb) {
|
||||||
return this.model('Transaction').count(
|
return this.model('Transaction').count(
|
||||||
{
|
{
|
||||||
$or: [
|
$or: [
|
||||||
@ -76,7 +76,7 @@ TransactionSchema.methods.countByAddress = function txByAddress(address, cb) {
|
|||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.last = function lastTx(cb) {
|
TransactionSchema.statics.last = function lastTx(cb) {
|
||||||
return this.model('Transaction').find(
|
return this.model('Transaction').find(
|
||||||
{},
|
{},
|
||||||
cb)
|
cb)
|
||||||
@ -84,7 +84,7 @@ TransactionSchema.methods.last = function lastTx(cb) {
|
|||||||
.sort({ height: -1 });
|
.sort({ height: -1 });
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.getEmptyInputs = function getEmptyInputs(cb) {
|
TransactionSchema.statics.getEmptyInputs = function getEmptyInputs(cb) {
|
||||||
return this.model('Transaction').find({
|
return this.model('Transaction').find({
|
||||||
'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' },
|
'inputs.prevout.hash': { $ne: '0000000000000000000000000000000000000000000000000000000000000000' },
|
||||||
'inputs.value': 0,
|
'inputs.value': 0,
|
||||||
@ -92,9 +92,7 @@ TransactionSchema.methods.getEmptyInputs = function getEmptyInputs(cb) {
|
|||||||
cb);
|
cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionSchema.methods.updateInput = function updateInput(txid, inputid, value, address) {
|
TransactionSchema.statics.updateInput = function updateInput(txid, inputid, value, address) {
|
||||||
logger.log('debug',
|
|
||||||
`${txid} ${address}value is ${value}`);
|
|
||||||
return this.model('Transaction').findOneAndUpdate(
|
return this.model('Transaction').findOneAndUpdate(
|
||||||
{ _id: txid, 'inputs._id': inputid },
|
{ _id: txid, 'inputs._id': inputid },
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user