From 0ff742c1b6001417b5926e512efe2d1b6370f2d5 Mon Sep 17 00:00:00 2001 From: Patrick Nagurny Date: Tue, 8 Sep 2015 14:04:14 -0400 Subject: [PATCH] add isMainChain method --- docs/services/bitcoind.md | 1 + integration/regtest-node.js | 11 +++++++++-- integration/regtest.js | 8 ++++++++ lib/services/bitcoind.js | 4 ++++ src/libbitcoind.cc | 31 +++++++++++++++++++++++++++++++ src/libbitcoind.h | 2 ++ test/services/bitcoind.unit.js | 1 + 7 files changed, 56 insertions(+), 2 deletions(-) diff --git a/docs/services/bitcoind.md b/docs/services/bitcoind.md index 39b469f0..8251aea8 100644 --- a/docs/services/bitcoind.md +++ b/docs/services/bitcoind.md @@ -8,6 +8,7 @@ The bitcoin service adds a native interface to Bitcoin Core for querying informa - `bitcoind.getBlock(blockHash|blockHeight, callback)` - Get any block asynchronously by block hash or height as a node buffer. - `bitcoind.isSpent(txid, outputIndex)` - Returns a boolean if a txid and outputIndex is already spent. - `bitcoind.getBlockIndex(blockHash)` - Will return the block chain work and previous hash. +- `bitcoind.isMainChain(blockHash)` - Returns true if block is on the main chain. Returns false if it is an orphan. - `bitcoind.estimateFee(blocks)` - Estimates the fees required to have a transaction included in the number of blocks specified as the first argument. - `bitcoind.sendTransaction(transaction, allowAbsurdFees)` - Will attempt to add a transaction to the mempool and broadcast to peers. - `bitcoind.getTransaction(txid, queryMempool, callback)` - Get any tx asynchronously by reading it from disk, with an argument to optionally not include the mempool. diff --git a/integration/regtest-node.js b/integration/regtest-node.js index bc4909bb..1ea90be1 100644 --- a/integration/regtest-node.js +++ b/integration/regtest-node.js @@ -131,6 +131,8 @@ describe('Node Functionality', function() { }); }); + var invalidatedBlockHash; + it('will handle a reorganization', function(done) { var count; @@ -151,12 +153,12 @@ describe('Node Functionality', function() { if (err) { return next(err); } - blockHash = response.result; + invalidatedBlockHash = response.result; next(); }); }, function(next) { - client.invalidateBlock(blockHash, next); + client.invalidateBlock(invalidatedBlockHash, next); }, function(next) { client.getBlockCount(function(err, response) { @@ -206,4 +208,9 @@ describe('Node Functionality', function() { }); }); + + it('isMainChain() will return false for stale/orphan block', function(done) { + bitcoind.isMainChain(invalidatedBlockHash).should.equal(false); + setImmediate(done); + }); }); diff --git a/integration/regtest.js b/integration/regtest.js index e7f48287..f1c68dc6 100644 --- a/integration/regtest.js +++ b/integration/regtest.js @@ -251,6 +251,14 @@ describe('Daemon Binding Functionality', function() { }); }); + describe('isMainChain', funciton() { + [1,2,3,4,5,6,7,8,9].forEach(function(i) { + it('block ' + i + ' is on the main chain', function() { + bitcoind.isMainChain(blockHashes[i]).should.equal(true); + }); + }); + }); + describe('send transaction functionality', function() { it('will not error and return the transaction hash', function() { diff --git a/lib/services/bitcoind.js b/lib/services/bitcoind.js index 9585f69d..5cd3319f 100644 --- a/lib/services/bitcoind.js +++ b/lib/services/bitcoind.js @@ -189,6 +189,10 @@ Bitcoin.prototype.getBlockIndex = function(blockHash) { return bindings.getBlockIndex(blockHash); }; +Bitcoin.prototype.isMainChain = function(blockHash) { + return bindings.isMainChain(blockHash); +}; + Bitcoin.prototype.estimateFee = function(blocks) { return bindings.estimateFee(blocks); }; diff --git a/src/libbitcoind.cc b/src/libbitcoind.cc index 9212206f..b3e0fd6d 100644 --- a/src/libbitcoind.cc +++ b/src/libbitcoind.cc @@ -1350,6 +1350,36 @@ NAN_METHOD(GetBlockIndex) { NanReturnValue(obj); }; + +/** + * IsMainChain() + * bitcoind.isMainChain() + * + * @param {string} - block hash + * @returns {boolean} - True if the block is in the main chain. False if it is an orphan. + */ +NAN_METHOD(IsMainChain) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + + CBlockIndex* blockIndex; + + String::Utf8Value hash_(args[0]->ToString()); + std::string hashStr = std::string(*hash_); + uint256 hash = uint256S(hashStr); + if (mapBlockIndex.count(hash) == 0) { + NanReturnValue(Undefined(isolate)); + } else { + blockIndex = mapBlockIndex[hash]; + } + + if (chainActive.Contains(blockIndex)) { + NanReturnValue(NanNew(true)); + } else { + NanReturnValue(NanNew(false)); + } +} + /** * GetInfo() * bitcoindjs.getInfo() @@ -1606,6 +1636,7 @@ init(Handle target) { NODE_SET_METHOD(target, "getInfo", GetInfo); NODE_SET_METHOD(target, "isSpent", IsSpent); NODE_SET_METHOD(target, "getBlockIndex", GetBlockIndex); + NODE_SET_METHOD(target, "isMainChain", IsMainChain); NODE_SET_METHOD(target, "getMempoolOutputs", GetMempoolOutputs); NODE_SET_METHOD(target, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction); NODE_SET_METHOD(target, "sendTransaction", SendTransaction); diff --git a/src/libbitcoind.h b/src/libbitcoind.h index e35e40b6..12bdc7b5 100644 --- a/src/libbitcoind.h +++ b/src/libbitcoind.h @@ -22,6 +22,8 @@ NAN_METHOD(OnBlocksReady); NAN_METHOD(OnTipUpdate); NAN_METHOD(StopBitcoind); NAN_METHOD(GetBlock); +NAN_METHOD(GetBlockIndex); +NAN_METHOD(IsMainChain); NAN_METHOD(GetTransaction); NAN_METHOD(GetInfo); NAN_METHOD(IsSpent); diff --git a/test/services/bitcoind.unit.js b/test/services/bitcoind.unit.js index 7d6d8fd4..0704c1ce 100644 --- a/test/services/bitcoind.unit.js +++ b/test/services/bitcoind.unit.js @@ -371,6 +371,7 @@ describe('Bitcoin Service', function() { ['getBlock', 2], ['isSpent', 2], ['getBlockIndex', 1], + ['isMainChain', 1], ['estimateFee', 1], ['sendTransaction', 2], ['getTransaction', 3],