successful tx broadcast.

This commit is contained in:
Christopher Jeffrey 2014-09-25 13:12:28 -07:00
parent 547bd02ba3
commit b05ee032c5
3 changed files with 156 additions and 33 deletions

View File

@ -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);

View File

@ -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
*/

View File

@ -271,6 +271,7 @@ struct async_broadcast_tx_data {
std::string tx_hex;
std::string tx_hash;
bool override_fees;
bool own_only;
Persistent<Function> 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<Object> js_tx = Local<Object>::Cast(args[0]);
Local<Function> callback = Local<Function>::Cast(args[2]);
Local<Function> callback = Local<Function>::Cast(args[3]);
String::Utf8Value tx_hex_(js_tx->Get(NanNew<String>("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<Function>::New(callback);
@ -994,16 +993,22 @@ static void
async_broadcast_tx(uv_work_t *req) {
async_broadcast_tx_data* data = static_cast<async_broadcast_tx_data*>(req->data);
const std::vector<unsigned char> tx_hex(data->tx_hex.begin(), data->tx_hex.end());
CDataStream ssData(tx_hex, SER_NETWORK, PROTOCOL_VERSION);
// const std::vector<unsigned char> 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;