Merge pull request #100 from braydonf/libbitcoind
Cleanup and Document Daemon
This commit is contained in:
commit
6764871a95
13
README.md
13
README.md
|
@ -362,10 +362,15 @@ Note that if you already have a bitcore-node database, and you want to query dat
|
|||
|
||||
- `daemon.start([options], [callback])` - Start the JavaScript Bitcoin node.
|
||||
- `daemon.getBlock(blockHash|blockHeight, callback)` - Get any block asynchronously by block hash or height as a node buffer.
|
||||
- `daemon.getTransaction(txid, blockhash, callback)` - Get any tx asynchronously by reading it from disk.
|
||||
- `daemon.log(message), daemon.info(message)` - Log to standard output.
|
||||
- `daemon.error(message)` - Log to stderr.
|
||||
- `daemon.close([callback])` - Stop the JavaScript bitcoin node safely, the callback will be called when bitcoind is closed. This will also be done automatically on `process.exit`. It also takes the bitcoind node off the libuv event loop. If the daemon object is the only thing on the event loop. Node will simply close.
|
||||
- `daemon.isSpent(txid, outputIndex)` - Returns a boolean if a txid and outputIndex is already spent.
|
||||
- `daemon.getBlockIndex(blockHash)` - Will return the block chain work and previous hash.
|
||||
- `daemon.estimateFee(blocks)` - Estimates the fees required to have a transaction included in the number of blocks specified as the first argument.
|
||||
- `daemon.sendTransaction(transaction, allowAbsurdFees)` - Will attempt to add a transaction to the mempool and broadcast to peers.
|
||||
- `daemon.getTransaction(txid, queryMempool, callback)` - Get any tx asynchronously by reading it from disk, with an argument to optionally not include the mempool.
|
||||
- `daemon.getTransactionWithBlockInfo(txid, queryMempool, callback)` - Similar to getTransaction but will also include the block timestamp and height.
|
||||
- `daemon.getMempoolOutputs(address)` - Will return an array of outputs that match an address from the mempool.
|
||||
- `daemon.getInfo()` - Basic information about the chain including total number of blocks.
|
||||
- `daemon.stop([callback])` - Stop the JavaScript bitcoin node safely, the callback will be called when bitcoind is closed. This will also be done automatically on `process.exit`. It also takes the bitcoind node off the libuv event loop. If the daemon object is the only thing on the event loop. Node will simply close.
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
@ -2,32 +2,27 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* bitcoind.js example
|
||||
*/
|
||||
var chainlib = require('chainlib');
|
||||
var log = chainlib.log;
|
||||
|
||||
process.title = 'bitcore-node';
|
||||
process.title = 'libbitcoind';
|
||||
|
||||
/**
|
||||
* daemon
|
||||
*/
|
||||
var daemon = require('../').daemon({
|
||||
datadir: process.env.BITCORENODE_DIR || '~/.bitcoin',
|
||||
network: 'testnet'
|
||||
network: process.env.BITCORENODE_NETWORK || 'testnet'
|
||||
});
|
||||
|
||||
daemon.on('ready', function() {
|
||||
console.log('ready');
|
||||
});
|
||||
|
||||
daemon.on('tx', function(txid) {
|
||||
console.log('txid', txid);
|
||||
log.info('ready');
|
||||
});
|
||||
|
||||
daemon.on('error', function(err) {
|
||||
daemon.log('error="%s"', err.message);
|
||||
log.info('error="%s"', err.message);
|
||||
});
|
||||
|
||||
daemon.on('open', function(status) {
|
||||
daemon.log('status="%s"', status);
|
||||
log.info('status="%s"', status);
|
||||
});
|
|
@ -5,8 +5,11 @@
|
|||
// functionality by including the wallet in the build.
|
||||
// To run the tests: $ mocha -R spec integration/regtest.js
|
||||
|
||||
var chainlib = require('chainlib');
|
||||
var log = chainlib.log;
|
||||
|
||||
if (process.env.BITCORENODE_ENV !== 'test') {
|
||||
console.log('Please set the environment variable BITCORENODE_ENV=test and make sure bindings are compiled for testing');
|
||||
log.info('Please set the environment variable BITCORENODE_ENV=test and make sure bindings are compiled for testing');
|
||||
process.exit();
|
||||
}
|
||||
|
||||
|
@ -63,14 +66,14 @@ describe('Daemon Binding Functionality', function() {
|
|||
});
|
||||
|
||||
bitcoind.on('error', function(err) {
|
||||
bitcoind.log('error="%s"', err.message);
|
||||
log.error('error="%s"', err.message);
|
||||
});
|
||||
|
||||
bitcoind.on('open', function(status) {
|
||||
bitcoind.log('status="%s"', status);
|
||||
log.info('status="%s"', status);
|
||||
});
|
||||
|
||||
console.log('Waiting for Bitcoin Core to initialize...');
|
||||
log.info('Waiting for Bitcoin Core to initialize...');
|
||||
|
||||
bitcoind.on('ready', function() {
|
||||
|
||||
|
@ -82,7 +85,7 @@ describe('Daemon Binding Functionality', function() {
|
|||
pass: 'local321'
|
||||
});
|
||||
|
||||
console.log('Generating 100 blocks...');
|
||||
log.info('Generating 100 blocks...');
|
||||
|
||||
// Generate enough blocks so that the initial coinbase transactions
|
||||
// can be spent.
|
||||
|
@ -98,7 +101,7 @@ describe('Daemon Binding Functionality', function() {
|
|||
// We'll construct a new transaction that will send funds
|
||||
// to a new address with pubkeyhashout for later testing.
|
||||
|
||||
console.log('Preparing unspent outputs...');
|
||||
log.info('Preparing unspent outputs...');
|
||||
|
||||
client.getBalance(function(err, response) {
|
||||
if (err) {
|
||||
|
@ -149,7 +152,7 @@ describe('Daemon Binding Functionality', function() {
|
|||
throw err;
|
||||
}
|
||||
|
||||
console.log('Testing setup complete!');
|
||||
log.info('Testing setup complete!');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
659
lib/daemon.js
659
lib/daemon.js
|
@ -1,15 +1,13 @@
|
|||
var net = require('net');
|
||||
'use strict';
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var bitcoind = require('bindings')('bitcoind.node');
|
||||
var chainlib = require('chainlib');
|
||||
var log = chainlib.log;
|
||||
var util = require('util');
|
||||
var fs = require('fs');
|
||||
var mkdirp = require('mkdirp');
|
||||
var tiny = require('tiny').json;
|
||||
var bitcore = require('bitcore');
|
||||
var $ = bitcore.util.preconditions;
|
||||
|
||||
var daemon = Daemon;
|
||||
|
||||
function Daemon(options) {
|
||||
var self = this;
|
||||
|
||||
|
@ -31,14 +29,6 @@ function Daemon(options) {
|
|||
|
||||
this.config = this.datadir + '/bitcoin.conf';
|
||||
|
||||
this.network = Daemon.livenet;
|
||||
|
||||
if (this.options.network === 'testnet') {
|
||||
this.network = Daemon.testnet;
|
||||
} else if(this.options.network === 'regtest') {
|
||||
this.network = Daemon.regtest;
|
||||
}
|
||||
|
||||
Object.keys(exports).forEach(function(key) {
|
||||
self[key] = exports[key];
|
||||
});
|
||||
|
@ -50,28 +40,7 @@ function Daemon(options) {
|
|||
});
|
||||
}
|
||||
|
||||
Daemon.prototype.__proto__ = EventEmitter.prototype;
|
||||
|
||||
Daemon.livenet = {
|
||||
name: 'livenet',
|
||||
peers: [
|
||||
// hardcoded peers
|
||||
]
|
||||
};
|
||||
|
||||
Daemon.testnet = {
|
||||
name: 'testnet',
|
||||
peers: [
|
||||
// hardcoded peers
|
||||
]
|
||||
};
|
||||
|
||||
Daemon.regtest = {
|
||||
name: 'regtest',
|
||||
peers: [
|
||||
// hardcoded peers
|
||||
]
|
||||
};
|
||||
util.inherits(Daemon, EventEmitter);
|
||||
|
||||
// Make sure signal handlers are not overwritten
|
||||
Daemon._signalQueue = [];
|
||||
|
@ -91,26 +60,13 @@ Daemon.instances = {};
|
|||
Daemon.prototype.instances = Daemon.instances;
|
||||
|
||||
Daemon.__defineGetter__('global', function() {
|
||||
if (daemon.stopping) return [];
|
||||
return Daemon.instances[Object.keys(Daemon.instances)[0]];
|
||||
});
|
||||
|
||||
Daemon.prototype.__defineGetter__('global', function() {
|
||||
if (daemon.stopping) return [];
|
||||
return Daemon.global;
|
||||
});
|
||||
|
||||
tiny.debug = function() {};
|
||||
tiny.prototype.debug = function() {};
|
||||
tiny.error = function() {};
|
||||
tiny.prototype.error = function() {};
|
||||
|
||||
Daemon.db = tiny({
|
||||
file: process.env.HOME + '/.bitcoind.db',
|
||||
saveIndex: false,
|
||||
initialCache: false
|
||||
});
|
||||
|
||||
Daemon.prototype.start = function(options, callback) {
|
||||
var self = this;
|
||||
|
||||
|
@ -124,7 +80,7 @@ Daemon.prototype.start = function(options, callback) {
|
|||
}
|
||||
|
||||
if (!callback) {
|
||||
callback = utils.NOOP;
|
||||
callback = function() {};
|
||||
}
|
||||
|
||||
if (this.instances[this.datadir]) {
|
||||
|
@ -249,11 +205,9 @@ Daemon.prototype.start = function(options, callback) {
|
|||
this._shutdown = setInterval(function() {
|
||||
if (!self._stoppingSaid && bitcoind.stopping()) {
|
||||
self._stoppingSaid = true;
|
||||
self.log('shutting down...');
|
||||
}
|
||||
|
||||
if (bitcoind.stopped()) {
|
||||
self.log('shut down.');
|
||||
|
||||
clearInterval(self._shutdown);
|
||||
delete self._shutdown;
|
||||
|
@ -265,34 +219,17 @@ Daemon.prototype.start = function(options, callback) {
|
|||
process.kill(process.pid, exitCaught.name);
|
||||
});
|
||||
return;
|
||||
}
|
||||
return self._exit(exitCaught);
|
||||
}
|
||||
|
||||
if (errorCaught !== none) {
|
||||
if (errorCaught && errorCaught.stack) {
|
||||
} else if (errorCaught && errorCaught.stack) {
|
||||
console.error(errorCaught.stack);
|
||||
}
|
||||
return self._exit(0);
|
||||
return self._exit(exitCaught);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
Daemon.prototype.getBlock = function(blockhash, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getBlock(blockhash, function(err, block) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, block);
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getBlockHeight = function(height, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getBlock(+height, function(err, block) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, daemon.block(block));
|
||||
});
|
||||
return bitcoind.getBlock(blockhash, callback);
|
||||
};
|
||||
|
||||
Daemon.prototype.isSpent = function(txid, outputIndex) {
|
||||
|
@ -315,53 +252,6 @@ Daemon.prototype.getTransaction = function(txid, queryMempool, callback) {
|
|||
return bitcoind.getTransaction(txid, queryMempool, callback);
|
||||
};
|
||||
|
||||
Daemon.prototype.getTransactionWithBlock = function(txid, blockhash, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
|
||||
var self = this;
|
||||
var slow = true;
|
||||
|
||||
if (typeof txid === 'object' && txid) {
|
||||
var options = txid;
|
||||
callback = blockhash;
|
||||
txid = options.txid || options.tx || options.txhash || options.id || options.hash;
|
||||
blockhash = options.blockhash || options.block;
|
||||
slow = options.slow !== false;
|
||||
}
|
||||
|
||||
if (typeof blockhash === 'function') {
|
||||
callback = blockhash;
|
||||
blockhash = '';
|
||||
}
|
||||
|
||||
if (typeof blockhash !== 'string') {
|
||||
if (blockhash) {
|
||||
blockhash = blockhash.hash
|
||||
|| blockhash.blockhash
|
||||
|| (blockhash.getHash && blockhash.getHash())
|
||||
|| '';
|
||||
} else {
|
||||
blockhash = '';
|
||||
}
|
||||
}
|
||||
|
||||
return bitcoind.getTransaction(txid, blockhash, function(err, tx) {
|
||||
if (err) return callback(err);
|
||||
|
||||
if (slow && !tx.blockhash) {
|
||||
return self.getBlockByTx(txid, function(err, block, tx_) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, tx, block);
|
||||
});
|
||||
}
|
||||
|
||||
return bitcoind.getBlock(tx.blockhash, function(err, block) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, daemon.tx(tx), daemon.block(block));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getTransactionWithBlockInfo = function(txid, queryMempool, callback) {
|
||||
return bitcoind.getTransactionWithBlockInfo(txid, queryMempool, callback);
|
||||
};
|
||||
|
@ -375,185 +265,17 @@ Daemon.prototype.addMempoolUncheckedTransaction = function(txBuffer) {
|
|||
};
|
||||
|
||||
Daemon.prototype.getInfo = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getInfo();
|
||||
};
|
||||
|
||||
Daemon.prototype.getPeerInfo = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getPeerInfo();
|
||||
};
|
||||
|
||||
Daemon.prototype.getAddresses = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getAddresses();
|
||||
};
|
||||
|
||||
Daemon.prototype.getProgress = function(callback) {
|
||||
return bitcoind.getProgress(callback);
|
||||
};
|
||||
|
||||
Daemon.prototype.setGenerate = function(options) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.setGenerate(options || {});
|
||||
};
|
||||
|
||||
Daemon.prototype.getGenerate = function(options) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getGenerate(options || {});
|
||||
};
|
||||
|
||||
Daemon.prototype.getMiningInfo = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getMiningInfo();
|
||||
};
|
||||
|
||||
Daemon.prototype.getAddrTransactions = function(address, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return daemon.db.get('addr-tx/' + address, function(err, records) {
|
||||
var options = {
|
||||
address: address,
|
||||
blockheight: (records || []).reduce(function(out, record) {
|
||||
return record.blockheight > out
|
||||
? record.blockheight
|
||||
: out;
|
||||
}, -1),
|
||||
blocktime: (records || []).reduce(function(out, record) {
|
||||
return record.blocktime > out
|
||||
? record.blocktime
|
||||
: out;
|
||||
}, -1)
|
||||
};
|
||||
return bitcoind.getAddrTransactions(options, function(err, addr) {
|
||||
if (err) return callback(err);
|
||||
addr = daemon.addr(addr);
|
||||
if (addr.tx[0] && !addr.tx[0].vout[0]) {
|
||||
return daemon.db.set('addr-tx/' + address, [{
|
||||
txid: null,
|
||||
blockhash: null,
|
||||
blockheight: null,
|
||||
blocktime: null
|
||||
}], function() {
|
||||
return callback(null, daemon.addr({
|
||||
address: addr.address,
|
||||
tx: []
|
||||
}));
|
||||
});
|
||||
}
|
||||
var set = [];
|
||||
if (records && records.length) {
|
||||
set = records;
|
||||
}
|
||||
addr.tx.forEach(function(tx) {
|
||||
set.push({
|
||||
txid: tx.txid,
|
||||
blockhash: tx.blockhash,
|
||||
blockheight: tx.blockheight,
|
||||
blocktime: tx.blocktime
|
||||
});
|
||||
});
|
||||
return daemon.db.set('addr-tx/' + address, set, function() {
|
||||
return callback(null, addr);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getBestBlock = function(callback) {
|
||||
if (daemon.stopping) return [];
|
||||
var hash = bitcoind.getBestBlock();
|
||||
return bitcoind.getBlock(hash, callback);
|
||||
};
|
||||
|
||||
Daemon.prototype.getChainHeight = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getChainHeight();
|
||||
};
|
||||
|
||||
Daemon.prototype.__defineGetter__('chainHeight', function() {
|
||||
if (daemon.stopping) return [];
|
||||
return this.getChainHeight();
|
||||
});
|
||||
|
||||
Daemon.prototype.getBlockByTxid =
|
||||
Daemon.prototype.getBlockByTx = function(txid, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return daemon.db.get('block-tx/' + txid, function(err, block) {
|
||||
if (block) {
|
||||
return self.getBlock(block.hash, function(err, block) {
|
||||
if (err) return callback(err);
|
||||
var tx_ = block.tx.filter(function(tx) {
|
||||
return tx.txid === txid;
|
||||
})[0];
|
||||
return callback(null, block, tx_);
|
||||
});
|
||||
}
|
||||
return bitcoind.getBlockByTx(txid, function(err, block, tx_) {
|
||||
if (err) return callback(err);
|
||||
daemon.db.set('block-tx/' + txid, { hash: block.hash }, utils.NOOP);
|
||||
return callback(null, daemon.block(block), daemon.tx(tx_));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getBlocksByDate =
|
||||
Daemon.prototype.getBlocksByTime = function(options, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getBlocksByTime(options, function(err, blocks) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, blocks.map(function(block) {
|
||||
return daemon.block(block);
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getFromTx = function(txid, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getFromTx(txid, function(err, txs) {
|
||||
if (err) return callback(err);
|
||||
return callback(null, txs.map(function(tx) {
|
||||
return daemon.tx(tx)
|
||||
}));
|
||||
});
|
||||
};
|
||||
|
||||
Daemon.prototype.getLastFileIndex = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return bitcoind.getLastFileIndex();
|
||||
};
|
||||
|
||||
Daemon.prototype.log =
|
||||
Daemon.prototype.info = function() {
|
||||
if (daemon.stopping) return [];
|
||||
if (this.options.silent) return;
|
||||
if (typeof arguments[0] !== 'string') {
|
||||
var out = util.inspect(arguments[0], null, 20, true);
|
||||
return process.stdout.write('bitcoind.js: ' + out + '\n');
|
||||
}
|
||||
var out = util.format.apply(util, arguments);
|
||||
return process.stdout.write('bitcoind.js: ' + out + '\n');
|
||||
};
|
||||
|
||||
Daemon.prototype.error = function() {
|
||||
if (daemon.stopping) return [];
|
||||
if (this.options.silent) return;
|
||||
if (typeof arguments[0] !== 'string') {
|
||||
var out = util.inspect(arguments[0], null, 20, true);
|
||||
return process.stderr.write('bitcoind.js: ' + out + '\n');
|
||||
}
|
||||
var out = util.format.apply(util, arguments);
|
||||
return process.stderr.write('bitcoind.js: ' + out + '\n');
|
||||
};
|
||||
|
||||
Daemon.prototype.stop =
|
||||
Daemon.prototype.close = function(callback) {
|
||||
if (daemon.stopping) return [];
|
||||
Daemon.prototype.stop = function(callback) {
|
||||
if (Daemon.stopping) return [];
|
||||
var self = this;
|
||||
return bitcoind.stop(function(err, status) {
|
||||
if (err) {
|
||||
self.error(err.message);
|
||||
} else {
|
||||
self.log(status);
|
||||
log.info(status);
|
||||
}
|
||||
if (!callback) return;
|
||||
return callback(err, status);
|
||||
|
@ -576,359 +298,4 @@ Daemon.__defineGetter__('stopped', function() {
|
|||
return bitcoind.stopped();
|
||||
});
|
||||
|
||||
/**
|
||||
* Block
|
||||
*/
|
||||
|
||||
function Block(data) {
|
||||
if (!(this instanceof Block)) {
|
||||
return new Block(data);
|
||||
}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
return Block.fromHex(data);
|
||||
}
|
||||
|
||||
if (data instanceof Block) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (daemon.stopping) return [];
|
||||
|
||||
var self = this;
|
||||
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (!self[key]) {
|
||||
self[key] = data[key];
|
||||
}
|
||||
});
|
||||
|
||||
this.tx = this.tx.map(function(tx) {
|
||||
return daemon.tx(tx);
|
||||
});
|
||||
|
||||
if (!this.hex) {
|
||||
this.hex = this.toHex();
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Block.prototype, '_blockFlag', {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: {}
|
||||
});
|
||||
|
||||
Block.isBlock = function(block) {
|
||||
if (daemon.stopping) return [];
|
||||
return block._blockFlag === Block.prototype._blockFlag;
|
||||
};
|
||||
|
||||
Block.fromHex = function(hex) {
|
||||
if (daemon.stopping) return [];
|
||||
return daemon.block(bitcoind.blockFromHex(hex));
|
||||
};
|
||||
|
||||
Block.prototype.getHash = function(enc) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getBlockHex(this);
|
||||
if (!this.hash || this.hash !== data.hash) {
|
||||
this.hash = data.hash;
|
||||
}
|
||||
if (enc === 'hex') return data.hash;
|
||||
var buf = new Buffer(data.hash, 'hex');
|
||||
var out = enc ? buf.toString(enc) : buf;
|
||||
return out;
|
||||
};
|
||||
|
||||
Block.prototype.verify = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return this.verified = this.verified || bitcoind.verifyBlock(this);
|
||||
};
|
||||
|
||||
Block.prototype.toHex = function() {
|
||||
if (daemon.stopping) return [];
|
||||
var hex = Block.toHex(this);
|
||||
if (!this.hex || this.hex !== hex) {
|
||||
this.hex = hex;
|
||||
}
|
||||
return hex;
|
||||
};
|
||||
|
||||
Block.toHex = function(block) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getBlockHex(block);
|
||||
return data.hex;
|
||||
};
|
||||
|
||||
Block.prototype.toBinary = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return Block.toBinary(this);
|
||||
};
|
||||
|
||||
Block.toBinary = function(block) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getBlockHex(block);
|
||||
return new Buffer(data.hex, 'hex');
|
||||
};
|
||||
|
||||
/**
|
||||
* Transaction
|
||||
*/
|
||||
|
||||
function Transaction(data) {
|
||||
if (!(this instanceof Transaction)) {
|
||||
return new Transaction(data);
|
||||
}
|
||||
|
||||
if (typeof data === 'string') {
|
||||
return Transaction.fromHex(data);
|
||||
}
|
||||
|
||||
if (data instanceof Transaction) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (daemon.stopping) return [];
|
||||
|
||||
var self = this;
|
||||
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (!self[key]) {
|
||||
self[key] = data[key];
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.hex) {
|
||||
this.hex = this.toHex();
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Transaction.prototype, '_txFlag', {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: {}
|
||||
});
|
||||
|
||||
Transaction.isTransaction =
|
||||
Transaction.isTx = function(tx) {
|
||||
if (daemon.stopping) return [];
|
||||
return tx._txFlag === Transaction.prototype._txFlag;
|
||||
};
|
||||
|
||||
Transaction.fromHex = function(hex) {
|
||||
if (daemon.stopping) return [];
|
||||
return daemon.tx(bitcoind.txFromHex(hex));
|
||||
};
|
||||
|
||||
Transaction.prototype.verify = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return this.verified = this.verified || bitcoind.verifyTransaction(this);
|
||||
};
|
||||
|
||||
Transaction.prototype.sign =
|
||||
Transaction.prototype.fill = function(options) {
|
||||
if (daemon.stopping) return [];
|
||||
return Transaction.fill(this, options);
|
||||
};
|
||||
|
||||
Transaction.sign =
|
||||
Transaction.fill = function(tx, options) {
|
||||
if (daemon.stopping) return [];
|
||||
var isTx = daemon.tx.isTx(tx)
|
||||
, newTx;
|
||||
|
||||
if (!isTx) {
|
||||
tx = daemon.tx(tx);
|
||||
}
|
||||
|
||||
try {
|
||||
newTx = bitcoind.fillTransaction(tx, options || {});
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Object.keys(newTx).forEach(function(key) {
|
||||
tx[key] = newTx[key];
|
||||
});
|
||||
|
||||
return tx;
|
||||
};
|
||||
|
||||
Transaction.prototype.getHash = function(enc) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getTxHex(this);
|
||||
if (!this.txid || this.txid !== data.hash) {
|
||||
this.txid = data.hash;
|
||||
}
|
||||
if (enc === 'hex') return data.hash;
|
||||
var buf = new Buffer(data.hash, 'hex');
|
||||
var out = enc ? buf.toString(enc) : buf;
|
||||
return out;
|
||||
};
|
||||
|
||||
Transaction.prototype.isCoinbase = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return this.vin.length === 1 && this.vin[0].coinbase;
|
||||
};
|
||||
|
||||
Transaction.prototype.toHex = function() {
|
||||
if (daemon.stopping) return [];
|
||||
var hex = Transaction.toHex(this);
|
||||
if (!this.hex || hex !== this.hex) {
|
||||
this.hex = hex;
|
||||
}
|
||||
return hex;
|
||||
};
|
||||
|
||||
Transaction.toHex = function(tx) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getTxHex(tx);
|
||||
return data.hex;
|
||||
};
|
||||
|
||||
Transaction.prototype.toBinary = function() {
|
||||
if (daemon.stopping) return [];
|
||||
return Transaction.toBinary(this);
|
||||
};
|
||||
|
||||
Transaction.toBinary = function(tx) {
|
||||
if (daemon.stopping) return [];
|
||||
var data = bitcoind.getTxHex(tx);
|
||||
return new Buffer(data.hex, 'hex');
|
||||
};
|
||||
|
||||
Transaction.broadcast = function(tx, options, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
if (typeof tx === 'string') {
|
||||
tx = { hex: tx };
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
if (!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var fee = options.overrideFees = options.overrideFees || false;
|
||||
var own = options.ownOnly = options.ownOnly || false;
|
||||
|
||||
if (!callback) {
|
||||
callback = utils.NOOP;
|
||||
}
|
||||
|
||||
if (!daemon.isTx(tx)) {
|
||||
tx = daemon.tx(tx);
|
||||
}
|
||||
|
||||
return bitcoind.broadcastTx(tx, fee, own, function(err, hash, tx) {
|
||||
if (err) {
|
||||
if (callback === utils.NOOP) {
|
||||
daemon.global.emit('error', err);
|
||||
}
|
||||
return callback(err);
|
||||
}
|
||||
tx = daemon.tx(tx);
|
||||
daemon.global.emit('broadcast', tx);
|
||||
return callback(null, hash, tx);
|
||||
});
|
||||
};
|
||||
|
||||
Transaction.prototype.broadcast = function(options, callback) {
|
||||
if (daemon.stopping) return [];
|
||||
if (!callback) {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
return Transaction.broadcast(this, options, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Addresses
|
||||
*/
|
||||
|
||||
function Addresses(data) {
|
||||
if (!(this instanceof Addresses)) {
|
||||
return new Addresses(data);
|
||||
}
|
||||
|
||||
if (data instanceof Addresses) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (daemon.stopping) return [];
|
||||
|
||||
var self = this;
|
||||
|
||||
Object.keys(data).forEach(function(key) {
|
||||
if (!self[key]) {
|
||||
self[key] = data[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(Transaction.prototype, '_addrFlag', {
|
||||
__proto__: null,
|
||||
configurable: false,
|
||||
enumerable: false,
|
||||
writable: false,
|
||||
value: {}
|
||||
});
|
||||
|
||||
Addresses.isAddresses =
|
||||
Addresses.isAddr = function(addr) {
|
||||
if (daemon.stopping) return [];
|
||||
return addr._txFlag === Addresses.prototype._addrFlag;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utils
|
||||
*/
|
||||
|
||||
var utils = {};
|
||||
|
||||
utils.forEach = function(obj, iter, done) {
|
||||
if (daemon.stopping) return [];
|
||||
var pending = obj.length;
|
||||
if (!pending) return done();
|
||||
var next = function() {
|
||||
if (!--pending) done();
|
||||
};
|
||||
obj.forEach(function(item) {
|
||||
iter(item, next);
|
||||
});
|
||||
};
|
||||
|
||||
utils.NOOP = function() {};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = exports = daemon;
|
||||
|
||||
exports.Daemon = daemon;
|
||||
exports.daemon = daemon;
|
||||
exports.bitcoind = daemon;
|
||||
|
||||
exports.native = bitcoind;
|
||||
exports.bitcoind = bitcoind;
|
||||
|
||||
exports.Block = Block;
|
||||
exports.block = Block;
|
||||
|
||||
exports.Transaction = Transaction;
|
||||
exports.transaction = Transaction;
|
||||
exports.tx = Transaction;
|
||||
|
||||
exports.Addresses = Addresses;
|
||||
exports.addresses = Addresses;
|
||||
exports.addr = Addresses;
|
||||
|
||||
exports.utils = utils;
|
||||
module.exports = Daemon;
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
"install": "./bin/build-bindings",
|
||||
"start": "node example",
|
||||
"test": "NODE_ENV=test mocha --recursive",
|
||||
"coverage": "istanbul cover _mocha -- --recursive"
|
||||
"coverage": "istanbul cover _mocha -- --recursive",
|
||||
"libbitcoind": "node bin/start-libbitcoind.js"
|
||||
},
|
||||
"tags": [
|
||||
"bitcoin",
|
||||
|
@ -44,8 +45,7 @@
|
|||
"errno": "^0.1.2",
|
||||
"memdown": "^1.0.0",
|
||||
"mkdirp": "0.5.0",
|
||||
"nan": "1.3.0",
|
||||
"tiny": "0.0.10"
|
||||
"nan": "1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"benchmark": "1.0.0",
|
||||
|
|
Loading…
Reference in New Issue