diff --git a/integration/index.js b/integration/index.js index fd89630b..34a1435c 100644 --- a/integration/index.js +++ b/integration/index.js @@ -133,7 +133,57 @@ describe('Basic Functionality', function() { var work = bitcoind.getChainWork(hash); should.equal(work, undefined); }); + }); + + describe('mempool functionality', function() { + + var fromAddress = 'mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1'; + var utxo = { + address: fromAddress, + txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', + outputIndex: 0, + script: bitcore.Script.buildPublicKeyHashOut(fromAddress).toString(), + satoshis: 100000 + }; + var toAddress = 'mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc'; + var changeAddress = 'mgBCJAsvzgT2qNNeXsoECg2uPKrUsZ76up'; + var changeAddressP2SH = '2N7T3TAetJrSCruQ39aNrJvYLhG1LJosujf'; + var privateKey = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'; + var private1 = '6ce7e97e317d2af16c33db0b9270ec047a91bff3eff8558afb5014afb2bb5976'; + var private2 = 'c9b26b0f771a0d2dad88a44de90f05f416b3b385ff1d989343005546a0032890'; + var tx = new bitcore.Transaction(); + tx.from(utxo); + tx.to(toAddress, 50000); + tx.change(changeAddress); + tx.sign(privateKey); + + it('will add an unchecked transaction', function() { + var added = bitcoind.addMempoolUncheckedTransaction(tx.serialize()); + added.should.equal(true); + bitcoind.getTransaction(tx.hash, true, function(err, txBuffer) { + if(err) { + throw err; + } + var expected = tx.toBuffer().toString('hex'); + txBuffer.toString('hex').should.equal(expected); + }); + + }); + + it('get outputs by address', function() { + var outputs = bitcoind.getMempoolOutputs(changeAddress); + var expected = [ + { + script: 'OP_DUP OP_HASH160 073b7eae2823efa349e3b9155b8a735526463a0f OP_EQUALVERIFY OP_CHECKSIG', + satoshis: 40000, + txid: tx.hash, + outputIndex: 1 + } + ]; + outputs.should.deep.equal(expected); + }); }); }); + diff --git a/lib/bitcoind.js b/lib/bitcoind.js index 46218747..83591768 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -382,6 +382,14 @@ Bitcoin.prototype.getTransactionWithBlock = function(txid, blockhash, callback) }); }; +Bitcoin.prototype.getMempoolOutputs = function(address) { + return bitcoindjs.getMempoolOutputs(address); +}; + +Bitcoin.prototype.addMempoolUncheckedTransaction = function(txBuffer) { + return bitcoindjs.addMempoolUncheckedTransaction(txBuffer); +}; + Bitcoin.prototype.getInfo = function() { if (bitcoin.stopping) return []; return bitcoindjs.getInfo(); diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index fcff27a0..78ccd507 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -821,6 +821,7 @@ async_get_tx(uv_work_t *req) { { if (mempool.lookup(hash, ctx)) { + data->ctx = ctx; return; } } @@ -983,6 +984,103 @@ NAN_METHOD(GetInfo) { NanReturnValue(obj); } +/** + * GetMempoolOutputs + * bitcoindjs.getMempoolOutputs() + * Will return outputs by address from the mempool. + */ +NAN_METHOD(GetMempoolOutputs) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + + // Instatiate an empty array that we will fill later + // with matching outputs. + Local outputs = Array::New(isolate); + int arrayIndex = 0; + + // Decode the input address into the hash bytes + // that we can then match to the scriptPubKeys data + v8::String::Utf8Value param1(args[0]->ToString()); + std::string *input = new std::string(*param1); + const char* psz = input->c_str(); + std::vector vAddress; + DecodeBase58(psz, vAddress); + vector hashBytes(vAddress.begin()+1, vAddress.begin()+21); + + // Iterate through the entire mempool + std::map mapTx = mempool.mapTx; + + for(std::map::iterator it = mapTx.begin(); it != mapTx.end(); it++) { + + uint256 txid = it->first; + CTxMemPoolEntry entry = it->second; + const CTransaction tx = entry.GetTx(); + + int outputIndex = 0; + + // Iterate through each output + BOOST_FOREACH(const CTxOut& txout, tx.vout) { + + CScript script = txout.scriptPubKey; + + txnouttype type; + std::vector > hashResults; + + if (Solver(script, type, hashResults)) { + + // See if the script is any of the standard address types + if (type == TX_PUBKEYHASH || type == TX_SCRIPTHASH) { + + vector scripthashBytes = hashResults.front(); + + // Compare the hash bytes with the input hash bytes + if(equal(hashBytes.begin(), hashBytes.end(), scripthashBytes.begin())) { + + Local output = NanNew(); + + output->Set(NanNew("script"), NanNew(script.ToString())); + + uint64_t satoshis = txout.nValue; + output->Set(NanNew("satoshis"), NanNew(satoshis)); // can't go above 2 ^ 53 -1 + output->Set(NanNew("txid"), NanNew(txid.GetHex())); + + output->Set(NanNew("outputIndex"), NanNew(outputIndex)); + + // We have a match and push the results to the array + // that is returned as the result + outputs->Set(arrayIndex, output); + arrayIndex++; + + } + } + } + + outputIndex++; + } + } + + NanReturnValue(outputs); + +} + +/** + * AddMempoolUncheckedTransaction + */ +NAN_METHOD(AddMempoolUncheckedTransaction) { + NanScope(); + + v8::String::Utf8Value param1(args[0]->ToString()); + std::string *input = new std::string(*param1); + + CTransaction tx; + if (!DecodeHexTx(tx, *input)) { + return NanThrowError("could not decode tx"); + } + bool added = mempool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(tx, 0, 0, 0.0, 1)); + NanReturnValue(NanNew(added)); + +} + /** * Helpers */ @@ -1020,7 +1118,8 @@ init(Handle target) { NODE_SET_METHOD(target, "getInfo", GetInfo); NODE_SET_METHOD(target, "isSpent", IsSpent); NODE_SET_METHOD(target, "getChainWork", GetChainWork); - + NODE_SET_METHOD(target, "getMempoolOutputs", GetMempoolOutputs); + NODE_SET_METHOD(target, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction); } NODE_MODULE(bitcoindjs, init) diff --git a/src/bitcoindjs.h b/src/bitcoindjs.h index ea825a87..28c625e9 100644 --- a/src/bitcoindjs.h +++ b/src/bitcoindjs.h @@ -1,11 +1,3 @@ -/** - * bitcoind.js - * Copyright (c) 2015, BitPay (MIT License) - * - * bitcoindjs.h: - * A bitcoind node.js binding header file. - */ - #include "main.h" #include "addrman.h" #include "alert.h" @@ -18,6 +10,7 @@ #include #include "nan.h" #include "scheduler.h" +#include "core_io.h" NAN_METHOD(StartBitcoind); NAN_METHOD(OnBlocksReady); @@ -29,3 +22,5 @@ NAN_METHOD(GetTransaction); NAN_METHOD(GetInfo); NAN_METHOD(IsSpent); NAN_METHOD(GetChainWork); +NAN_METHOD(GetMempoolOutputs); +NAN_METHOD(AddMempoolUncheckedTransaction);