Skip to content

Commit

Permalink
chain, node: catch critical errors and shut down
Browse files Browse the repository at this point in the history
  • Loading branch information
pinheadmz committed May 6, 2022
1 parent 8d5004e commit 9f5fedf
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 5 deletions.
21 changes: 17 additions & 4 deletions lib/blockchain/chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const Script = require('../script/script');
const {VerifyError} = require('../protocol/errors');
const {OwnershipProof} = require('../covenants/ownership');
const AirdropProof = require('../primitives/airdropproof');
const {CriticalError} = require('../errors');
const thresholdStates = common.thresholdStates;
const {states} = NameState;

Expand Down Expand Up @@ -938,8 +939,10 @@ class Chain extends AsyncEmitter {
const ns = await view.getNameState(this.db, nameHash);

if (ns.isNull()) {
if (!covenant.isClaim() && !covenant.isOpen())
throw new Error('Database inconsistency.');
if (!covenant.isClaim() && !covenant.isOpen()) {
this.emit('abort', 'Unexpected null NameState.');
throw new CriticalError('Database inconsistency.');
}

const name = covenant.get(2);
ns.set(name, height);
Expand Down Expand Up @@ -1835,7 +1838,12 @@ class Chain extends AsyncEmitter {
}

// Save block and connect inputs.
await this.db.save(entry, block, view);
try {
await this.db.save(entry, block, view);
} catch (e) {
this.emit('abort', e.message);
throw new CriticalError(e);
}

// Expose the new state.
this.tip = entry;
Expand Down Expand Up @@ -1894,7 +1902,12 @@ class Chain extends AsyncEmitter {
entry.height, util.hex32(entry.version));
}

await this.db.save(entry, block);
try {
await this.db.save(entry, block);
} catch (e) {
this.emit('abort', e.message);
throw new CriticalError(e);
}

this.logger.warning('Heads up: Competing chain at height %d:'
+ ' tip-height=%d competitor-height=%d'
Expand Down
60 changes: 60 additions & 0 deletions lib/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*!
* errors.js - internal error objects for hsd
* Copyright (c) 2022 The Handshake Developers (MIT License).
* https://github.com/handshake-org/hsd
*/

'use strict';

/**
* @module errors
*/

const assert = require('bsert');

/**
* Critical Error
* An error severe enough to warrant shutting down the node.
* @extends Error
* @param {Block|TX} msg
* @param {String} code - Reject packet code.
* @param {String} reason - Reject packet reason.
* @param {Number} score - Ban score increase
* (can be -1 for no reject packet).
* @param {Boolean} malleated
*/

class CriticalError extends Error {
/**
* Create a verify error.
* @constructor
* @param {Block|TX} msg
* @param {String} code - Reject packet code.
* @param {String} reason - Reject packet reason.
* @param {Number} score - Ban score increase
* (can be -1 for no reject packet).
* @param {Boolean} malleated
*/

constructor(err) {
super();

this.type = 'CriticalError';

if (err instanceof Error) {
this.message = `Critical Error: ${err.message}`;
} else {
assert(typeof err === 'string');
this.message = `Critical Error: ${err}`;
}

if (Error.captureStackTrace)
Error.captureStackTrace(this, CriticalError);
}
}

/*
* Expose
*/

exports.CriticalError = CriticalError;
3 changes: 3 additions & 0 deletions lib/hsd.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ hsd.define('Rules', './covenants/rules');
hsd.define('dns', './dns/server');
hsd.define('resource', './dns/resource');

// Errors
hsd.define('errors', './errors');

// HD
hsd.define('hd', './hd');
hsd.define('HDPrivateKey', './hd/private');
Expand Down
12 changes: 12 additions & 0 deletions lib/node/fullnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,17 @@ class FullNode extends Node {
init() {
// Bind to errors
this.chain.on('error', err => this.error(err));
this.chain.on('abort', async (msg) => {
this.logger.error(`Critical error, shutting down: ${msg}`);
try {
this.emit('abort', msg);
await this.close();
} catch (e) {
this.logger.error(`Error occurred during shutdown: ${e.message}`);
process.exit(-2);
}
});

this.mempool.on('error', err => this.error(err));
this.pool.on('error', err => this.error(err));
this.miner.on('error', err => this.error(err));
Expand Down Expand Up @@ -327,6 +338,7 @@ class FullNode extends Node {
await this.handleClose();

this.logger.info('Node is closed.');
this.emit('closed');
}

/**
Expand Down
14 changes: 14 additions & 0 deletions lib/node/spvnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,17 @@ class SPVNode extends Node {
init() {
// Bind to errors
this.chain.on('error', err => this.error(err));
this.chain.on('abort', async (msg) => {
this.logger.error(`Critical error, shutting down: ${msg}`);
try {
this.emit('abort', msg);
await this.close();
} catch (e) {
this.logger.error(`Error occurred during shutdown: ${e.message}`);
process.exit(-2);
}
});

this.pool.on('error', err => this.error(err));

if (this.http)
Expand Down Expand Up @@ -214,6 +225,9 @@ class SPVNode extends Node {
await this.pool.close();
await this.chain.close();
await this.handleClose();

this.logger.info('Node is closed.');
this.emit('closed');
}

/**
Expand Down
3 changes: 2 additions & 1 deletion test/node-critical-error-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ describe('Node Critical Error', function() {
// at async Parser.<anonymous> (hsd/lib/net/peer.js:185:9)
await node.chain.add(block);
} catch (e) {
assert.strictEqual(e.message, 'Disk full!');
assert.strictEqual(e.message, 'Critical Error: Disk full!');
assert.strictEqual(e.type, 'CriticalError');
break;
}
}
Expand Down

0 comments on commit 9f5fedf

Please sign in to comment.