successful tx broadcast.
This commit is contained in:
parent
547bd02ba3
commit
b05ee032c5
|
@ -23,6 +23,13 @@ bitcoind.start(function(err) {
|
||||||
// print('Found tx:');
|
// print('Found tx:');
|
||||||
// print(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) {
|
bitcoind.on('mptx', function(mptx) {
|
||||||
print('Found mempool tx:');
|
print('Found mempool tx:');
|
||||||
print(mptx);
|
print(mptx);
|
||||||
|
|
149
lib/bitcoind.js
149
lib/bitcoind.js
|
@ -365,13 +365,19 @@ Transaction.prototype.toHex = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.toHex = function(tx) {
|
Transaction.toHex = function(tx) {
|
||||||
|
return new bn(Transaction.binary(tx)).toString('hex');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast TX
|
* 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) {
|
if (!callback) {
|
||||||
callback = options;
|
callback = options;
|
||||||
options = null;
|
options = null;
|
||||||
|
@ -382,26 +388,36 @@ Bitcoin._broadcastTx = function(tx, options, callback) {
|
||||||
}
|
}
|
||||||
|
|
||||||
options.overrideFees = options.overrideFees || false;
|
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) {
|
Transaction.binary = function(tx) {
|
||||||
var p = [];
|
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);
|
off += utils.varint(p, tx.vin.length, off);
|
||||||
|
|
||||||
for (var i = 0; i < tx.vin.length; i++) {
|
for (var i = 0; i < tx.vin.length; i++) {
|
||||||
var input = tx.vin[i];
|
var input = tx.vin[i];
|
||||||
|
|
||||||
off += utils.copy(utils.toArray(input.out.hash, 'hex'), p, off, true);
|
if (input.coinbase) {
|
||||||
off += utils.writeU32(p, input.out.index, off);
|
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);
|
// var s = script.encode(input.scriptSig.asm.split(' '));
|
||||||
off += utils.varint(p, s.length, off);
|
var s = script.encode(new bn(input.scriptSig.hex, 'hex').toArray());
|
||||||
off += utils.copy(s, p, off, true);
|
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);
|
off += utils.varint(p, tx.vout.length, off);
|
||||||
|
@ -409,17 +425,19 @@ Transaction.binary = function(tx) {
|
||||||
var output = tx.vout[i];
|
var output = tx.vout[i];
|
||||||
|
|
||||||
// Put LE value
|
// Put LE value
|
||||||
var value = output.value.toArray().slice().reverse();
|
var value = new bn(output.value).toArray().slice().reverse();
|
||||||
assert(value.length <= 8);
|
assert(value.length <= 8);
|
||||||
off += utils.copy(value, p, off, true);
|
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;
|
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.varint(p, s.length, off);
|
||||||
off += utils.copy(s, p, off, true);
|
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;
|
return p;
|
||||||
};
|
};
|
||||||
|
@ -427,9 +445,10 @@ Transaction.binary = function(tx) {
|
||||||
var script = {};
|
var script = {};
|
||||||
|
|
||||||
script.encode = function encode(s) {
|
script.encode = function encode(s) {
|
||||||
if (!s)
|
if (!s) {
|
||||||
return [];
|
return [];
|
||||||
var opcodes = constants.opcodes;
|
}
|
||||||
|
|
||||||
var res = [];
|
var res = [];
|
||||||
for (var i = 0; i < s.length; i++) {
|
for (var i = 0; i < s.length; i++) {
|
||||||
var instr = s[i];
|
var instr = s[i];
|
||||||
|
@ -443,25 +462,117 @@ script.encode = function encode(s) {
|
||||||
} else if (1 <= instr.length && instr.length <= 0x4b) {
|
} else if (1 <= instr.length && instr.length <= 0x4b) {
|
||||||
res = res.concat(instr.length, instr);
|
res = res.concat(instr.length, instr);
|
||||||
} else if (instr.length <= 0xff) {
|
} 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) {
|
} else if (instr.length <= 0xffff) {
|
||||||
res.push(opcodes.pushdata2);
|
// res.push(script.opcodes.pushdata2);
|
||||||
|
res.push(0x4d);
|
||||||
utils.writeU16(res, instr.length, res.length);
|
utils.writeU16(res, instr.length, res.length);
|
||||||
res = res.concat(instr);
|
res = res.concat(instr);
|
||||||
} else {
|
} else {
|
||||||
res.push(opcodes.pushdata4);
|
// res.push(script.opcodes.pushdata4);
|
||||||
|
res.push(0x4e);
|
||||||
utils.writeU32(res, instr.length, res.length);
|
utils.writeU32(res, instr.length, res.length);
|
||||||
res = res.concat(instr);
|
res = res.concat(instr);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.push(opcodes[instr] || instr);
|
// res.push(script.opcodes[instr] || instr);
|
||||||
|
res.push(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
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
|
* Utils
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -271,6 +271,7 @@ struct async_broadcast_tx_data {
|
||||||
std::string tx_hex;
|
std::string tx_hex;
|
||||||
std::string tx_hash;
|
std::string tx_hash;
|
||||||
bool override_fees;
|
bool override_fees;
|
||||||
|
bool own_only;
|
||||||
Persistent<Function> callback;
|
Persistent<Function> callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -947,34 +948,32 @@ async_poll_mempool_after(uv_work_t *req) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BroadcastTx(tx, override_fees, callback)
|
* BroadcastTx(tx, override_fees, own_only, callback)
|
||||||
* bitcoind.broadcastTx(tx, override_fees, callback)
|
* bitcoind.broadcastTx(tx, override_fees, own_only, callback)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
NAN_METHOD(BroadcastTx) {
|
NAN_METHOD(BroadcastTx) {
|
||||||
NanScope();
|
NanScope();
|
||||||
|
|
||||||
if (args.Length() < 3
|
if (args.Length() < 4
|
||||||
|| !args[0]->IsObject()
|
|| !args[0]->IsObject()
|
||||||
|| !args[1]->IsBoolean()
|
|| !args[1]->IsBoolean()
|
||||||
|| !args[2]->IsFunction()) {
|
|| !args[2]->IsBoolean()
|
||||||
|
|| !args[3]->IsFunction()) {
|
||||||
return NanThrowError(
|
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<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());
|
String::Utf8Value tx_hex_(js_tx->Get(NanNew<String>("hex"))->ToString());
|
||||||
std::string tx_hex = std::string(*tx_hex_);
|
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();
|
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->override_fees = args[1]->ToBoolean()->IsTrue();
|
||||||
|
data->own_only = args[2]->ToBoolean()->IsTrue();
|
||||||
data->err_msg = std::string("");
|
data->err_msg = std::string("");
|
||||||
data->callback = Persistent<Function>::New(callback);
|
data->callback = Persistent<Function>::New(callback);
|
||||||
|
|
||||||
|
@ -994,16 +993,22 @@ static void
|
||||||
async_broadcast_tx(uv_work_t *req) {
|
async_broadcast_tx(uv_work_t *req) {
|
||||||
async_broadcast_tx_data* data = static_cast<async_broadcast_tx_data*>(req->data);
|
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());
|
// 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(tx_hex, SER_NETWORK, PROTOCOL_VERSION);
|
||||||
|
CDataStream ssData(ParseHex(data->tx_hex), SER_NETWORK, PROTOCOL_VERSION);
|
||||||
CTransaction tx;
|
CTransaction tx;
|
||||||
|
|
||||||
bool fOverrideFees = false;
|
bool fOverrideFees = false;
|
||||||
|
bool fOwnOnly = false;
|
||||||
|
|
||||||
if (data->override_fees) {
|
if (data->override_fees) {
|
||||||
fOverrideFees = true;
|
fOverrideFees = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data->own_only) {
|
||||||
|
fOwnOnly = true;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ssData >> tx;
|
ssData >> tx;
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
|
@ -1016,7 +1021,7 @@ async_broadcast_tx(uv_work_t *req) {
|
||||||
bool fHave = false;
|
bool fHave = false;
|
||||||
CCoinsViewCache &view = *pcoinsTip;
|
CCoinsViewCache &view = *pcoinsTip;
|
||||||
CCoins existingCoins;
|
CCoins existingCoins;
|
||||||
{
|
if (ownOnly) {
|
||||||
fHave = view.GetCoins(hashTx, existingCoins);
|
fHave = view.GetCoins(hashTx, existingCoins);
|
||||||
if (!fHave) {
|
if (!fHave) {
|
||||||
CValidationState state;
|
CValidationState state;
|
||||||
|
|
Loading…
Reference in New Issue