From b05ee032c5eeff86ccb18557380b1175b9b0c006 Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Thu, 25 Sep 2014 13:12:28 -0700 Subject: [PATCH] successful tx broadcast. --- example/index.js | 7 +++ lib/bitcoind.js | 149 ++++++++++++++++++++++++++++++++++++++++------ src/bitcoindjs.cc | 33 +++++----- 3 files changed, 156 insertions(+), 33 deletions(-) diff --git a/example/index.js b/example/index.js index 131acd15..051aea8b 100755 --- a/example/index.js +++ b/example/index.js @@ -23,6 +23,13 @@ bitcoind.start(function(err) { // print('Found tx:'); // print(tx); // }); + bitcoind.once('tx', function(tx) { + console.log('Broadcasting tx...'); + bitcoind._broadcastTx(tx, function(err, hash) { + if (err) throw err; + console.log('tx hash: %s', hash); + }); + }); bitcoind.on('mptx', function(mptx) { print('Found mempool tx:'); print(mptx); diff --git a/lib/bitcoind.js b/lib/bitcoind.js index f565e22c..f07cf001 100644 --- a/lib/bitcoind.js +++ b/lib/bitcoind.js @@ -365,13 +365,19 @@ Transaction.prototype.toHex = function() { }; Transaction.toHex = function(tx) { + return new bn(Transaction.binary(tx)).toString('hex'); }; /** * Broadcast TX */ -Bitcoin._broadcastTx = function(tx, options, callback) { +Bitcoin._broadcastTx = +Bitcoin.prototype._broadcastTx = function(tx, options, callback) { + if (typeof tx === 'string') { + tx = { hex: tx }; + } + if (!callback) { callback = options; options = null; @@ -382,26 +388,36 @@ Bitcoin._broadcastTx = function(tx, options, callback) { } options.overrideFees = options.overrideFees || false; + options.ownOnly = options.ownOnly || false; - return bitcoindjs.broadcastTx(tx, options.overrideFees, callback); + return bitcoindjs.broadcastTx(tx, + options.overrideFees, + options.ownOnly, + callback); }; Transaction.binary = function(tx) { var p = []; - var off = utils.writeU32(p, tx.nVersion, 0); + var off = utils.writeU32(p, tx.nVersion || tx.version, 0); off += utils.varint(p, tx.vin.length, off); for (var i = 0; i < tx.vin.length; i++) { var input = tx.vin[i]; - off += utils.copy(utils.toArray(input.out.hash, 'hex'), p, off, true); - off += utils.writeU32(p, input.out.index, off); + if (input.coinbase) { + off += utils.copy(new bn(input.coinbase, 'hex').toArray(), p, off, true); + off += utils.writeU32(p, input.sequence, off); + } else { + off += utils.copy(new bn(input.txid, 'hex').toArray(), p, off, true); + off += utils.writeU32(p, input.vout, off); - var s = script.encode(input.script); - off += utils.varint(p, s.length, off); - off += utils.copy(s, p, off, true); + // var s = script.encode(input.scriptSig.asm.split(' ')); + var s = script.encode(new bn(input.scriptSig.hex, 'hex').toArray()); + off += utils.varint(p, s.length, off); + off += utils.copy(s, p, off, true); - off += utils.writeU32(p, input.seq, off); + off += utils.writeU32(p, input.sequence, off); + } } off += utils.varint(p, tx.vout.length, off); @@ -409,17 +425,19 @@ Transaction.binary = function(tx) { var output = tx.vout[i]; // Put LE value - var value = output.value.toArray().slice().reverse(); + var value = new bn(output.value).toArray().slice().reverse(); assert(value.length <= 8); off += utils.copy(value, p, off, true); - for (var j = value.length; j < 8; j++, off++) + for (var j = value.length; j < 8; j++, off++) { p[off] = 0; + } - var s = script.encode(output.script); + //var s = script.encode(output.scriptPubKey.asm.split(' ')); + var s = script.encode(new bn(output.scriptPubKey.hex, 'hex').toArray()); off += utils.varint(p, s.length, off); off += utils.copy(s, p, off, true); } - off += utils.writeU32(p, tx.nLockTime, off); + off += utils.writeU32(p, tx.nLockTime || tx.locktime, off); return p; }; @@ -427,9 +445,10 @@ Transaction.binary = function(tx) { var script = {}; script.encode = function encode(s) { - if (!s) + if (!s) { return []; - var opcodes = constants.opcodes; + } + var res = []; for (var i = 0; i < s.length; i++) { var instr = s[i]; @@ -443,25 +462,117 @@ script.encode = function encode(s) { } else if (1 <= instr.length && instr.length <= 0x4b) { res = res.concat(instr.length, instr); } else if (instr.length <= 0xff) { - res = res.concat(opcodes.pushdata1, instr.length, instr); + // res = res.concat(script.opcodes.pushdata1, instr.length, instr); + res = res.concat(0x4c, instr.length, instr); } else if (instr.length <= 0xffff) { - res.push(opcodes.pushdata2); + // res.push(script.opcodes.pushdata2); + res.push(0x4d); utils.writeU16(res, instr.length, res.length); res = res.concat(instr); } else { - res.push(opcodes.pushdata4); + // res.push(script.opcodes.pushdata4); + res.push(0x4e); utils.writeU32(res, instr.length, res.length); res = res.concat(instr); } continue; } - res.push(opcodes[instr] || instr); + // res.push(script.opcodes[instr] || instr); + res.push(instr); } return res; }; +script.opcodes = { + 0: 0, + pushdata1: 0x4c, + pushdata2: 0x4d, + pushdata4: 0x4e, + negate1: 0x4f, + + nop: 0x61, + if_: 0x63, + notif: 0x64, + else_: 0x67, + endif: 0x68, + verify: 0x69, + ret: 0x6a, + + toaltstack: 0x6b, + fromaltstack: 0x6c, + ifdup: 0x73, + depth: 0x74, + drop: 0x75, + dup: 0x76, + nip: 0x77, + over: 0x78, + pick: 0x79, + roll: 0x7a, + rot: 0x7b, + swap: 0x7c, + tuck: 0x7d, + drop2: 0x6d, + dup2: 0x6e, + dup3: 0x6f, + over2: 0x70, + rot2: 0x71, + swap2: 0x72, + + cat: 0x74, + substr: 0x7f, + left: 0x80, + right: 0x81, + size: 0x82, + + invert: 0x83, + and: 0x84, + or: 0x85, + xor: 0x86, + eq: 0x87, + eqverify: 0x88, + + add1: 0x8b, + sub1: 0x8c, + mul2: 0x8d, + div2: 0x8e, + negate: 0x8f, + abs: 0x90, + not: 0x91, + noteq0: 0x92, + add: 0x93, + sub: 0x94, + mul: 0x95, + div: 0x96, + mod: 0x97, + lshift: 0x98, + rshift: 0x99, + booland: 0x9a, + boolor: 0x9b, + numeq: 0x9c, + numeqverify: 0x9d, + numneq: 0x9e, + lt: 0x9f, + gt: 0xa0, + lte: 0xa1, + gte: 0xa2, + min: 0xa3, + max: 0xa4, + within: 0xa5, + + ripemd160: 0xa6, + sha1: 0xa7, + sha256: 0xa8, + hash160: 0xa9, + hash256: 0xaa, + codesep: 0xab, + checksig: 0xac, + checksigverify: 0xad, + checkmultisig: 0xae, + checkmultisigverify: 0xaf +}; + /** * Utils */ diff --git a/src/bitcoindjs.cc b/src/bitcoindjs.cc index 09bc5664..83127f3a 100644 --- a/src/bitcoindjs.cc +++ b/src/bitcoindjs.cc @@ -271,6 +271,7 @@ struct async_broadcast_tx_data { std::string tx_hex; std::string tx_hash; bool override_fees; + bool own_only; Persistent callback; }; @@ -947,34 +948,32 @@ async_poll_mempool_after(uv_work_t *req) { } /** - * BroadcastTx(tx, override_fees, callback) - * bitcoind.broadcastTx(tx, override_fees, callback) + * BroadcastTx(tx, override_fees, own_only, callback) + * bitcoind.broadcastTx(tx, override_fees, own_only, callback) */ NAN_METHOD(BroadcastTx) { NanScope(); - if (args.Length() < 3 + if (args.Length() < 4 || !args[0]->IsObject() || !args[1]->IsBoolean() - || !args[2]->IsFunction()) { + || !args[2]->IsBoolean() + || !args[3]->IsFunction()) { return NanThrowError( - "Usage: bitcoindjs.broadcastTx(tx, override_fees, callback)"); + "Usage: bitcoindjs.broadcastTx(tx, override_fees, own_only, callback)"); } Local js_tx = Local::Cast(args[0]); - Local callback = Local::Cast(args[2]); + Local callback = Local::Cast(args[3]); String::Utf8Value tx_hex_(js_tx->Get(NanNew("hex"))->ToString()); std::string tx_hex = std::string(*tx_hex_); - if (tx_hex[1] != 'x') { - tx_hex = "0x" + tx_hex; - } - std::string strHex(tx_hex); async_broadcast_tx_data *data = new async_broadcast_tx_data(); - data->tx_hex = strHex; + data->tx_hex = tx_hex; data->override_fees = args[1]->ToBoolean()->IsTrue(); + data->own_only = args[2]->ToBoolean()->IsTrue(); data->err_msg = std::string(""); data->callback = Persistent::New(callback); @@ -994,16 +993,22 @@ static void async_broadcast_tx(uv_work_t *req) { async_broadcast_tx_data* data = static_cast(req->data); - const std::vector tx_hex(data->tx_hex.begin(), data->tx_hex.end()); - CDataStream ssData(tx_hex, SER_NETWORK, PROTOCOL_VERSION); + // const std::vector tx_hex(data->tx_hex.begin(), data->tx_hex.end()); + // CDataStream ssData(tx_hex, SER_NETWORK, PROTOCOL_VERSION); + CDataStream ssData(ParseHex(data->tx_hex), SER_NETWORK, PROTOCOL_VERSION); CTransaction tx; bool fOverrideFees = false; + bool fOwnOnly = false; if (data->override_fees) { fOverrideFees = true; } + if (data->own_only) { + fOwnOnly = true; + } + try { ssData >> tx; } catch (std::exception &e) { @@ -1016,7 +1021,7 @@ async_broadcast_tx(uv_work_t *req) { bool fHave = false; CCoinsViewCache &view = *pcoinsTip; CCoins existingCoins; - { + if (ownOnly) { fHave = view.GetCoins(hashTx, existingCoins); if (!fHave) { CValidationState state;