Blockchain watcher safety adjustments (#411)

* Fix a failed block potentially being skipped. Up retry sleep to 2 minutes, up number of failed requests to 10 to give blockchain more time to recover.

* Fix non-transaction vouts causing issues.

* Wrap whole scan function in try. Reduce retry time to 1 minute.
This commit is contained in:
William O'Beirne 2019-03-28 11:35:45 -04:00 committed by GitHub
parent bbd9d90350
commit 15f960aec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 25 additions and 20 deletions

View File

@ -17,9 +17,9 @@ export interface BlockChainInfo {
export interface ScriptPubKey {
asm: string;
hex: string;
reqSigs: number;
type: string;
addresses: string[];
reqSigs?: number;
addresses?: string[];
}
export interface VIn {

View File

@ -11,7 +11,7 @@ import log from "../log";
let blockScanTimeout: any = null;
let notifiers = [] as Notifier[];
let consecutiveBlockFailures = 0;
const MAXIMUM_BLOCK_FAILURES = 5;
const MAXIMUM_BLOCK_FAILURES = 10;
const MIN_BLOCK_CONF = parseInt(env.MINIMUM_BLOCK_CONFIRMATIONS, 10);
export async function start() {
@ -38,7 +38,7 @@ function initScan() {
store.subscribe(() => {
const { startingBlockHeight } = store.getState();
if (startingBlockHeight !== null && prevHeight !== startingBlockHeight) {
console.info(`Starting block scan at block ${startingBlockHeight}`);
log.info(`Starting block scan at block ${startingBlockHeight}`);
clearTimeout(blockScanTimeout);
scanBlock(startingBlockHeight);
prevHeight = startingBlockHeight;
@ -47,22 +47,23 @@ function initScan() {
}
async function scanBlock(height: number) {
const highestBlock = await node.getblockcount();
// Try again in 5 seconds if the next block isn't ready
if (height > highestBlock - MIN_BLOCK_CONF) {
blockScanTimeout = setTimeout(() => {
scanBlock(height);
}, 5000);
return;
}
// Process the block
try {
// Fetch the current block height, try again in 5 seconds if the next
// block doesn't meet our confirmation requirement
const highestBlock = await node.getblockcount();
if (height > highestBlock - MIN_BLOCK_CONF) {
blockScanTimeout = setTimeout(() => {
scanBlock(height);
}, 5000);
return;
}
// Process the block, then try the next one
const block = await node.getblock(String(height), 2); // 2 == full blocks
log.info(`Processing block #${block.height}...`);
notifiers.forEach(n => n.onNewBlock && n.onNewBlock(block));
consecutiveBlockFailures = 0;
scanBlock(height + 1);
} catch(err) {
log.warn(`Failed to fetch block ${height}: ${extractErrMessage(err)}`);
consecutiveBlockFailures++;
@ -74,13 +75,12 @@ async function scanBlock(height: number) {
process.exit(1);
}
else {
log.warn('Attempting to fetch again shortly...');
await sleep(5000);
log.warn('Attempting to fetch again in 60 seconds...');
await sleep(60000);
}
// Try same block again
scanBlock(height);
}
// Try next block
scanBlock(height + 1);
}
function initNotifiers() {

View File

@ -42,6 +42,11 @@ export default class ContributionNotifier implements Notifier {
block.tx.forEach(tx => {
tx.vout.forEach(vout => {
// Some vouts are not transactions with addresses, ignore those
if (!vout.scriptPubKey.addresses) {
return;
}
// Addresses is an array because of multisigs, but we'll never
// generate one, so all of our addresses will only have addresses[0]
const to = vout.scriptPubKey.addresses[0];