diff --git a/integration/livenet.js b/integration/livenet.js index 245b19d5..8ebc0881 100644 --- a/integration/livenet.js +++ b/integration/livenet.js @@ -167,7 +167,6 @@ describe('Basic Functionality', function() { var expected = tx.toBuffer().toString('hex'); txBuffer.toString('hex').should.equal(expected); }); - }); it('get outputs by address', function() { diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 82a035c8..2dd696ae 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -1037,6 +1037,66 @@ NAN_METHOD(GetInfo) { NanReturnValue(obj); } +/** + * Send Transaction + * bitcoindjs.sendTransaction() + * Will add a transaction to the mempool and broadcast to connected peers. + * @param {string} - The serialized hex string of the transaction. + * @param {boolean} - Skip absurdly high fee checks + */ +NAN_METHOD(SendTransaction) { + Isolate* isolate = Isolate::GetCurrent(); + HandleScope scope(isolate); + + LOCK(cs_main); + + // Decode the transaction + v8::String::Utf8Value param1(args[0]->ToString()); + std::string *input = new std::string(*param1); + CTransaction tx; + if (!DecodeHexTx(tx, *input)) { + return NanThrowError("TX decode failed"); + } + uint256 hashTx = tx.GetHash(); + + // Skip absurdly high fee check + bool allowAbsurdFees = false; + if (args.Length() > 1) { + allowAbsurdFees = args[1]->BooleanValue(); + } + + CCoinsViewCache &view = *pcoinsTip; + const CCoins* existingCoins = view.AccessCoins(hashTx); + bool fHaveMempool = mempool.exists(hashTx); + bool fHaveChain = existingCoins && existingCoins->nHeight < 1000000000; + if (!fHaveMempool && !fHaveChain) { + CValidationState state; + bool fMissingInputs; + char *errorMessage; + + // Attempt to add the transaction to the mempool + if (!AcceptToMemoryPool(mempool, state, tx, false, &fMissingInputs, !allowAbsurdFees)) { + if (state.IsInvalid()) { + sprintf(errorMessage, "%i: %s", state.GetRejectCode(), state.GetRejectReason().c_str()); + return NanThrowError(errorMessage); + } else { + if (fMissingInputs) { + return NanThrowError("Missing inputs"); + } + sprintf(errorMessage, "%s", state.GetRejectReason()); + return NanThrowError(errorMessage); + } + } + } else if (fHaveChain) { + return NanThrowError("transaction already in block chain"); + } + + // Relay the transaction connect peers + RelayTransaction(tx); + + return NanReturnValue(NanNew(hashTx.GetHex())); +} + /** * GetMempoolOutputs * bitcoindjs.getMempoolOutputs() @@ -1174,7 +1234,7 @@ init(Handle target) { NODE_SET_METHOD(target, "getMempoolOutputs", GetMempoolOutputs); NODE_SET_METHOD(target, "addMempoolUncheckedTransaction", AddMempoolUncheckedTransaction); NODE_SET_METHOD(target, "verifyScript", VerifyScript); - + NODE_SET_METHOD(target, "sendTransaction", SendTransaction); } NODE_MODULE(bitcoindjs, init) diff --git a/src/bitcoindjs.h b/src/bitcoindjs.h index 40d1a803..050d6830 100644 --- a/src/bitcoindjs.h +++ b/src/bitcoindjs.h @@ -12,6 +12,7 @@ #include "scheduler.h" #include "core_io.h" #include "script/bitcoinconsensus.h" +#include "consensus/validation.h" NAN_METHOD(StartBitcoind); NAN_METHOD(OnBlocksReady); @@ -26,3 +27,5 @@ NAN_METHOD(GetChainWork); NAN_METHOD(GetMempoolOutputs); NAN_METHOD(AddMempoolUncheckedTransaction); NAN_METHOD(VerifyScript); +NAN_METHOD(SendTransaction); +