diff --git a/lib/bitcoind.js b/lib/bitcoind.js index ebe70254..60493f05 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -310,30 +310,6 @@ Bitcoin.prototype.start = function(options, callback) { this._emitted = {}; - // this.on('newListener', function(name) { - // if (name === 'version' || name === 'peer') { - // self._pollPeers(); - // return; - // } - // if (name === 'addr') { - // self._pollAddresses(); - // return; - // } - // if (name === 'block') { - // self._pollBlocks(); - // return; - // } - // if (name === 'tx') { - // self._pollBlocks(); - // self._pollMempool(); - // return; - // } - // if (name === 'mptx') { - // self._pollMempool(); - // return; - // } - // }); - if (this.log_pipe !== -1) { this.log('log pipe opened: %d', this.log_pipe); this._pipe = new net.Socket(this.log_pipe); @@ -347,149 +323,6 @@ Bitcoin.prototype.start = function(options, callback) { } }; -Bitcoin.prototype._pollBlocks = function() { - var self = this; - if (this._pollingBlocks) return; - this._pollingBlocks = true; - (function next() { - return bitcoindjs.pollBlocks(function(err, blocks) { - if (err) { - if (self.debug) { - console.log('poll error:'); - console.log(err.message); - } - return setTimeout(next, self.pollInterval); - } - return utils.forEach(blocks, function(block, nextBlock) { - block = bitcoin.block(block); - - // XXX Bad workaround - if (self._emitted[block.hash]) { - if (Object.keys(self._emitted[block.hash]).length > 10000) { - self._emitted = {}; - } - return setImmediate(function() { - return nextBlock(); - }); - } - self._emitted[block.hash] = true; - - self.emit('block', block); - - if (!self._pollingTxs) { - return setImmediate(function() { - return nextBlock(); - }); - } - - return utils.forEach(block.tx, function(tx, nextTx) { - tx = bitcoin.tx(tx); - self.emit('tx', tx); - return setImmediate(function() { - return nextTx(); - }); - }, function() { - return setImmediate(function() { - return nextBlock(); - }); - }); - }, function() { - if (self.debug) { - console.log('emission finished'); - } - return setTimeout(next, self.pollInterval); - }); - }); - })(); -}; - -Bitcoin.prototype._pollMempool = function() { - var self = this; - if (this._pollingTxs) return; - this._pollingTxs = true; - (function next() { - return bitcoindjs.pollMempool(function(err, txs) { - if (err) return setTimeout(next, self.pollInterval); - return utils.forEach(txs, function(tx, nextTx) { - tx = bitcoin.tx(tx); - - // XXX Bad workaround - if (self._emitted[tx.txid]) { - if (Object.keys(self._emitted[block.hash]).length > 10000) { - self._emitted = {}; - } - return setImmediate(function() { - return nextTx(); - }); - } - self._emitted[tx.txid] = true; - - self.emit('mptx', tx); - self.emit('tx', tx); - - return setImmediate(function() { - return nextTx(); - }); - }, function() { - return setTimeout(next, self.pollInterval); - }); - }); - })(); -}; - -// XXX Not perfect - will not catch all version packets. -Bitcoin.prototype._pollPeers = function() { - var self = this; - if (this._pollingPeers) return; - this._pollingPeers = true; - var lastPeers = bitcoindjs.getPeerInfo(); - (function next() { - var peers = bitcoindjs.getPeerInfo(); - peers = peers.filter(function(peer, i) { - return !lastPeers[i] || peer.addr !== lastPeers[i].addr; - }); - peers.forEach(function(peer) { - self.emit('peer', peer); - self.emit('version', { - version: peer.version, - services: peer.services, - time: peer.conntime, - nonce: null, - useragent: peer.subver, - startheight: peer.startingheight, - relay: null // peer.fRelayTxes - }); - }); - lastPeers = peers; - return setTimeout(next, self.pollInterval); - })(); -}; - -Bitcoin.prototype._pollAddresses = function() { - var self = this; - if (this._pollingAddresses) return; - this._pollingAddresses = true; - var lastAddrs = bitcoindjs.getAddresses(); - (function next() { - var addrs = bitcoindjs.getAddresses(); - addrs = addrs.filter(function(addr, i) { - return !lastAddrs[i] || addr.time !== lastAddrs[i].time; - }); - addrs.forEach(function(addr) { - self.emit('addr', { - services: addr.services, - time: addr.time, - last: addr.last, - ip: addr.ip, - port: addr.port, - address: addr.address - }); - }); - lastAddrs = addrs; - return setTimeout(next, self.pollInterval); - })(); -}; - Bitcoin.prototype.getBlock = function(blockHash, callback) { return bitcoindjs.getBlock(blockHash, function(err, block) { if (err) return callback(err); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 258127ac..7ee4e174 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -160,8 +160,6 @@ NAN_METHOD(IsStopped); NAN_METHOD(StopBitcoind); NAN_METHOD(GetBlock); NAN_METHOD(GetTx); -NAN_METHOD(PollBlocks); -NAN_METHOD(PollMempool); NAN_METHOD(BroadcastTx); NAN_METHOD(VerifyBlock); NAN_METHOD(VerifyTransaction); @@ -231,18 +229,6 @@ async_get_tx(uv_work_t *req); static void async_get_tx_after(uv_work_t *req); -static void -async_poll_blocks(uv_work_t *req); - -static void -async_poll_blocks_after(uv_work_t *req); - -static void -async_poll_mempool(uv_work_t *req); - -static void -async_poll_mempool_after(uv_work_t *req); - static void async_broadcast_tx(uv_work_t *req); @@ -300,7 +286,6 @@ init(Handle); */ static volatile bool shutdown_complete = false; -static int block_poll_top_height = -1; static char *g_data_dir = NULL; static bool g_rpc = false; static bool g_testnet = false; @@ -360,39 +345,6 @@ struct async_tx_data { Persistent callback; }; -/** - * poll_blocks_list - * A singly linked list containing any polled CBlocks and CBlockIndexes. - * Contained by async_poll_blocks_data struct. - */ - -typedef struct _poll_blocks_list { - CBlock cblock; - CBlockIndex *cblock_index; - struct _poll_blocks_list *next; -} poll_blocks_list; - -/** - * async_poll_blocks_data - */ - -struct async_poll_blocks_data { - std::string err_msg; - poll_blocks_list *head; - Persistent result_array; - Persistent callback; -}; - -/** - * async_poll_mempool_data - */ - -struct async_poll_mempool_data { - std::string err_msg; - Persistent result_array; - Persistent callback; -}; - /** * async_broadcast_tx_data */ @@ -1010,245 +962,6 @@ async_get_tx_after(uv_work_t *req) { delete req; } -/** - * PollBlocks() - * bitcoind.pollBlocks(callback) - * Poll for new blocks on the chain. This is necessary since we have no way of - * hooking in to AcceptBlock(). Instead, we constant check for new blocks using - * a SetTimeout() within node.js. - * Creating a linked list of all blocks within the work function is necessary - * due to doing v8 things within the libuv thread pool will cause a segfault. - * Since this reads full blocks, obviously it will poll for transactions which - * have already been included in blocks as well. - */ - -NAN_METHOD(PollBlocks) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.pollBlocks(callback)"); - } - - Local callback = Local::Cast(args[0]); - - async_poll_blocks_data *data = new async_poll_blocks_data(); - data->err_msg = std::string(""); - data->callback = Persistent::New(callback); - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_poll_blocks, - (uv_after_work_cb)async_poll_blocks_after); - - assert(status == 0); - - NanReturnValue(Undefined()); -} - -static void -async_poll_blocks(uv_work_t *req) { - async_poll_blocks_data* data = static_cast(req->data); - - int poll_saved_height = block_poll_top_height; - - // Poll, wait until we actually have a blockchain download. - // Once we've noticed the height changed, assume we gained a few blocks. - while (chainActive.Tip()) { - int cur_height = chainActive.Height(); - if (cur_height != block_poll_top_height) { - block_poll_top_height = cur_height; - break; - } - // Try again in 100ms - useconds_t usec = 100 * 1000; - usleep(usec); - } - - // NOTE: Since we can't do v8 stuff on the uv thread pool, we need to create - // a linked list for all the blocks and free them up later. - poll_blocks_list *head = NULL; - poll_blocks_list *cur = NULL; - - for (int i = poll_saved_height; i < block_poll_top_height; i++) { - if (i == -1) continue; - CBlockIndex *cblock_index = chainActive[i]; - if (cblock_index != NULL) { - CBlock cblock; - if (ReadBlockFromDisk(cblock, cblock_index)) { - poll_blocks_list *next = new poll_blocks_list(); - next->next = NULL; - if (cur == NULL) { - head = next; - cur = next; - } else { - cur->next = next; - cur = next; - } - cur->cblock = cblock; - cur->cblock_index = cblock_index; - } - } - } - - data->head = head; -} - -static void -async_poll_blocks_after(uv_work_t *req) { - NanScope(); - async_poll_blocks_data* data = static_cast(req->data); - - if (!data->err_msg.empty()) { - Local err = Exception::Error(String::New(data->err_msg.c_str())); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - data->callback->Call(Context::GetCurrent()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - const unsigned argc = 2; - Local blocks = NanNew(); - - poll_blocks_list *cur = static_cast(data->head); - poll_blocks_list *next; - int i = 0; - - while (cur != NULL) { - CBlock cblock = cur->cblock; - CBlockIndex *cblock_index = cur->cblock_index; - Local jsblock = NanNew(); - cblock_to_jsblock(cblock, cblock_index, jsblock); - blocks->Set(i, jsblock); - i++; - next = cur->next; - delete cur; - cur = next; - } - - Local argv[argc] = { - Local::New(Null()), - Local::New(blocks) - }; - TryCatch try_catch; - data->callback->Call(Context::GetCurrent()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - data->callback.Dispose(); - - delete data; - delete req; -} - -/** - * PollMempool() - * bitcoind.pollMempool(callback) - * This will poll for any transactions in the mempool. i.e. Transactions which - * have not been included in blocks yet. This is not technically necessary to - * be done asynchronously since there are no real blocking calls done here, but - * we will leave the async function here as a placeholder in case we're wrong. - */ - -NAN_METHOD(PollMempool) { - NanScope(); - - if (args.Length() < 1 || !args[0]->IsFunction()) { - return NanThrowError( - "Usage: bitcoindjs.pollMempool(callback)"); - } - - Local callback = Local::Cast(args[0]); - - async_poll_mempool_data *data = new async_poll_mempool_data(); - data->err_msg = std::string(""); - data->callback = Persistent::New(callback); - - uv_work_t *req = new uv_work_t(); - req->data = data; - - int status = uv_queue_work(uv_default_loop(), - req, async_poll_mempool, - (uv_after_work_cb)async_poll_mempool_after); - - assert(status == 0); - - NanReturnValue(Undefined()); -} - -static void -async_poll_mempool(uv_work_t *req) { - // XXX Potentially do everything async, but would it matter? Everything is in - // memory. There aren't really any harsh blocking calls. Leave this here as a - // placeholder. - useconds_t usec = 5 * 1000; - usleep(usec); -} - -static void -async_poll_mempool_after(uv_work_t *req) { - NanScope(); - async_poll_mempool_data* data = static_cast(req->data); - - if (!data->err_msg.empty()) { - Local err = Exception::Error(String::New(data->err_msg.c_str())); - const unsigned argc = 1; - Local argv[argc] = { err }; - TryCatch try_catch; - data->callback->Call(Context::GetCurrent()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } else { - int ti = 0; - Local txs = NanNew(); - - { - std::map::const_iterator it = mempool.mapTx.begin(); - for (; it != mempool.mapTx.end(); it++) { - const CTransaction& ctx = it->second.GetTx(); - Local jstx = NanNew(); - ctx_to_jstx(ctx, 0, jstx); - txs->Set(ti, jstx); - ti++; - } - } - - { - std::map::const_iterator it = mempool.mapNextTx.begin(); - for (; it != mempool.mapNextTx.end(); it++) { - const CTransaction ctx = *it->second.ptx; - Local jstx = NanNew(); - ctx_to_jstx(ctx, 0, jstx); - txs->Set(ti, jstx); - ti++; - } - } - - const unsigned argc = 2; - Local argv[argc] = { - Local::New(Null()), - Local::New(txs) - }; - TryCatch try_catch; - data->callback->Call(Context::GetCurrent()->Global(), argc, argv); - if (try_catch.HasCaught()) { - node::FatalException(try_catch); - } - } - - data->callback.Dispose(); - - delete data; - delete req; -} - /** * BroadcastTx() * bitcoind.broadcastTx(tx, override_fees, own_only, callback) @@ -3964,8 +3677,6 @@ init(Handle target) { NODE_SET_METHOD(target, "stopped", IsStopped); NODE_SET_METHOD(target, "getBlock", GetBlock); NODE_SET_METHOD(target, "getTx", GetTx); - NODE_SET_METHOD(target, "pollBlocks", PollBlocks); - NODE_SET_METHOD(target, "pollMempool", PollMempool); NODE_SET_METHOD(target, "broadcastTx", BroadcastTx); NODE_SET_METHOD(target, "verifyBlock", VerifyBlock); NODE_SET_METHOD(target, "verifyTransaction", VerifyTransaction);