ran js-beautify on all bitcore source
js-beautify -s 2 -r *.js ...did not run on bundles, only on source.
This commit is contained in:
parent
bba0945581
commit
ca67786a77
47
bitcore.js
47
bitcore.js
|
@ -7,19 +7,27 @@ Instead, we can set the 'get' property of each class to only require them when
|
||||||
they are accessed, saving memory if they are not used in a given project.
|
they are accessed, saving memory if they are not used in a given project.
|
||||||
*/
|
*/
|
||||||
var requireWhenAccessed = function(name, file) {
|
var requireWhenAccessed = function(name, file) {
|
||||||
Object.defineProperty(module.exports, name, {get: function() {return require(file)}});
|
Object.defineProperty(module.exports, name, {
|
||||||
|
get: function() {
|
||||||
|
return require(file)
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
requireWhenAccessed('Bignum', 'bignum');
|
requireWhenAccessed('Bignum', 'bignum');
|
||||||
Object.defineProperty(module.exports, 'bignum', {get: function() {
|
Object.defineProperty(module.exports, 'bignum', {
|
||||||
console.log('bignum (with a lower-case "b") is deprecated. Use bitcore.Bignum (capital "B") instead.');
|
get: function() {
|
||||||
return require('bignum');
|
console.log('bignum (with a lower-case "b") is deprecated. Use bitcore.Bignum (capital "B") instead.');
|
||||||
}});
|
return require('bignum');
|
||||||
|
}
|
||||||
|
});
|
||||||
requireWhenAccessed('Base58', './lib/Base58');
|
requireWhenAccessed('Base58', './lib/Base58');
|
||||||
Object.defineProperty(module.exports, 'base58', {get: function() {
|
Object.defineProperty(module.exports, 'base58', {
|
||||||
console.log('base58 (with a lower-case "b") is deprecated. Use bitcore.Base58 (capital "B") instead.');
|
get: function() {
|
||||||
return require('./lib/Base58');
|
console.log('base58 (with a lower-case "b") is deprecated. Use bitcore.Base58 (capital "B") instead.');
|
||||||
}});
|
return require('./lib/Base58');
|
||||||
|
}
|
||||||
|
});
|
||||||
requireWhenAccessed('bufferput', 'bufferput');
|
requireWhenAccessed('bufferput', 'bufferput');
|
||||||
requireWhenAccessed('buffertools', 'buffertools');
|
requireWhenAccessed('buffertools', 'buffertools');
|
||||||
requireWhenAccessed('Buffers.monkey', './patches/Buffers.monkey');
|
requireWhenAccessed('Buffers.monkey', './patches/Buffers.monkey');
|
||||||
|
@ -38,10 +46,12 @@ requireWhenAccessed('VersionedData', './util/VersionedData');
|
||||||
requireWhenAccessed('BinaryParser', './util/BinaryParser');
|
requireWhenAccessed('BinaryParser', './util/BinaryParser');
|
||||||
requireWhenAccessed('Address', './lib/Address');
|
requireWhenAccessed('Address', './lib/Address');
|
||||||
requireWhenAccessed('HierarchicalKey', './lib/HierarchicalKey');
|
requireWhenAccessed('HierarchicalKey', './lib/HierarchicalKey');
|
||||||
Object.defineProperty(module.exports, 'BIP32', {get: function() {
|
Object.defineProperty(module.exports, 'BIP32', {
|
||||||
console.log('BIP32 is deprecated. Use bitcore.HierarchicalKey instead.');
|
get: function() {
|
||||||
return require('./lib/HierarchicalKey');
|
console.log('BIP32 is deprecated. Use bitcore.HierarchicalKey instead.');
|
||||||
}});
|
return require('./lib/HierarchicalKey');
|
||||||
|
}
|
||||||
|
});
|
||||||
requireWhenAccessed('BIP39', './lib/BIP39');
|
requireWhenAccessed('BIP39', './lib/BIP39');
|
||||||
requireWhenAccessed('BIP39WordlistEn', './lib/BIP39WordlistEn');
|
requireWhenAccessed('BIP39WordlistEn', './lib/BIP39WordlistEn');
|
||||||
requireWhenAccessed('Point', './lib/Point');
|
requireWhenAccessed('Point', './lib/Point');
|
||||||
|
@ -55,10 +65,12 @@ requireWhenAccessed('Block', './lib/Block');
|
||||||
requireWhenAccessed('ScriptInterpreter', './lib/ScriptInterpreter');
|
requireWhenAccessed('ScriptInterpreter', './lib/ScriptInterpreter');
|
||||||
requireWhenAccessed('Bloom', './lib/Bloom');
|
requireWhenAccessed('Bloom', './lib/Bloom');
|
||||||
requireWhenAccessed('Key', './lib/Key');
|
requireWhenAccessed('Key', './lib/Key');
|
||||||
Object.defineProperty(module.exports, 'KeyModule', {get: function() {
|
Object.defineProperty(module.exports, 'KeyModule', {
|
||||||
console.log('KeyModule is deprecated.');
|
get: function() {
|
||||||
return require('bindings')('KeyModule');
|
console.log('KeyModule is deprecated.');
|
||||||
}});
|
return require('bindings')('KeyModule');
|
||||||
|
}
|
||||||
|
});
|
||||||
requireWhenAccessed('SINKey', './lib/SINKey');
|
requireWhenAccessed('SINKey', './lib/SINKey');
|
||||||
requireWhenAccessed('SIN', './lib/SIN');
|
requireWhenAccessed('SIN', './lib/SIN');
|
||||||
requireWhenAccessed('PrivateKey', './lib/PrivateKey');
|
requireWhenAccessed('PrivateKey', './lib/PrivateKey');
|
||||||
|
@ -70,4 +82,3 @@ requireWhenAccessed('Message', './lib/Message');
|
||||||
requireWhenAccessed('Electrum', './lib/Electrum');
|
requireWhenAccessed('Electrum', './lib/Electrum');
|
||||||
requireWhenAccessed('Armory', './lib/Armory');
|
requireWhenAccessed('Armory', './lib/Armory');
|
||||||
module.exports.Buffer = Buffer;
|
module.exports.Buffer = Buffer;
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ var puts = function(error, stdout, stderr) {
|
||||||
//sys.puts(stderr);
|
//sys.puts(stderr);
|
||||||
};
|
};
|
||||||
|
|
||||||
var pack = function (params) {
|
var pack = function(params) {
|
||||||
var file = require.resolve('soop');
|
var file = require.resolve('soop');
|
||||||
var dir = file.substr(0, file.length - String('soop.js').length);
|
var dir = file.substr(0, file.length - String('soop.js').length);
|
||||||
var preludePath = dir + 'example/custom_prelude.js';
|
var preludePath = dir + 'example/custom_prelude.js';
|
||||||
|
|
20
const.js
20
const.js
|
@ -1,18 +1,20 @@
|
||||||
|
|
||||||
MSG = {
|
MSG = {
|
||||||
TX: 1,
|
TX: 1,
|
||||||
BLOCK: 2,
|
BLOCK: 2,
|
||||||
FILTERED_BLOCK: 3,
|
FILTERED_BLOCK: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
MSG.to_str = function(t) {
|
MSG.to_str = function(t) {
|
||||||
switch(t) {
|
switch (t) {
|
||||||
case MSG.TX: return 'transaction';
|
case MSG.TX:
|
||||||
case MSG.BLOCK: return 'block';
|
return 'transaction';
|
||||||
case MSG.FILTERED_BLOCK: return 'filtered block';
|
case MSG.BLOCK:
|
||||||
default: return 'unknown';
|
return 'block';
|
||||||
|
case MSG.FILTERED_BLOCK:
|
||||||
|
return 'filtered block';
|
||||||
|
default:
|
||||||
|
return 'unknown';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.MSG = MSG;
|
exports.MSG = MSG;
|
||||||
|
|
||||||
|
|
|
@ -63,4 +63,3 @@ for (var i = 0; i < 5; i++) {
|
||||||
console.log(Address.fromPubKey(b.pubkey).as('base58'));
|
console.log(Address.fromPubKey(b.pubkey).as('base58'));
|
||||||
b = b.next();
|
b = b.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var Peer = require('../lib/Peer');
|
var Peer = require('../lib/Peer');
|
||||||
var Connection = require('../lib/Connection');
|
var Connection = require('../lib/Connection');
|
||||||
var dns = require('dns');
|
var dns = require('dns');
|
||||||
|
|
||||||
// get a peer from dns seed
|
// get a peer from dns seed
|
||||||
dns.resolve('dnsseed.bluematt.me', function(err, seeds) {
|
dns.resolve('dnsseed.bluematt.me', function(err, seeds) {
|
||||||
|
@ -9,12 +9,15 @@ dns.resolve('dnsseed.bluematt.me', function(err, seeds) {
|
||||||
|
|
||||||
//Custom peer:
|
//Custom peer:
|
||||||
//var peer = new Peer('180.153.139.246', '8888');
|
//var peer = new Peer('180.153.139.246', '8888');
|
||||||
|
|
||||||
// create a connection without an existing socket
|
// create a connection without an existing socket
|
||||||
// but specify a socks5 proxy to create a socket
|
// but specify a socks5 proxy to create a socket
|
||||||
// that's bound to that proxy in it's place
|
// that's bound to that proxy in it's place
|
||||||
var connection = new Connection(null, peer, {
|
var connection = new Connection(null, peer, {
|
||||||
proxy: { host: '127.0.0.1', port: 9050 }
|
proxy: {
|
||||||
|
host: '127.0.0.1',
|
||||||
|
port: 9050
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
connection.open();
|
connection.open();
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
|
|
||||||
var run = function() {
|
var run = function() {
|
||||||
bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
bitcore = typeof(bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
||||||
var networks = require('../networks');
|
var networks = require('../networks');
|
||||||
var WalletKey = bitcore.WalletKey;
|
var WalletKey = bitcore.WalletKey;
|
||||||
var Builder = bitcore.TransactionBuilder;
|
var Builder = bitcore.TransactionBuilder;
|
||||||
var opts = {network: networks.testnet};
|
var opts = {
|
||||||
|
network: networks.testnet
|
||||||
|
};
|
||||||
|
|
||||||
console.log('## Network: ' + opts.network.name);
|
console.log('## Network: ' + opts.network.name);
|
||||||
|
|
||||||
|
@ -13,8 +14,7 @@ var run = function() {
|
||||||
input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V";
|
input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V";
|
||||||
|
|
||||||
// Complete with the corresponding UTXO you want to use
|
// Complete with the corresponding UTXO you want to use
|
||||||
var utxos = [
|
var utxos = [{
|
||||||
{
|
|
||||||
address: input.addr,
|
address: input.addr,
|
||||||
txid: "39c71ebda371f75f4b854a720eaf9898b237facf3c2b101b58cd4383a44a6adc",
|
txid: "39c71ebda371f75f4b854a720eaf9898b237facf3c2b101b58cd4383a44a6adc",
|
||||||
vout: 1,
|
vout: 1,
|
||||||
|
@ -22,10 +22,9 @@ var run = function() {
|
||||||
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
||||||
amount: 0.4296,
|
amount: 0.4296,
|
||||||
confirmations: 2
|
confirmations: 2
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
|
|
||||||
var privs = [
|
var privs = [
|
||||||
"cP6JBHuQf7yqeqtdKRd22ibF3VehDv7G6BdzxSNABgrv3jFJUGoN",
|
"cP6JBHuQf7yqeqtdKRd22ibF3VehDv7G6BdzxSNABgrv3jFJUGoN",
|
||||||
"cQfRwF7XLSM5xGUpF8PZvob2MZyULvZPA2j5cat2RKDJrja7FtCZ",
|
"cQfRwF7XLSM5xGUpF8PZvob2MZyULvZPA2j5cat2RKDJrja7FtCZ",
|
||||||
"cUkYub4jtFVYymHh38yMMW36nJB4pXG5Pzd5QjResq79kAndkJcg",
|
"cUkYub4jtFVYymHh38yMMW36nJB4pXG5Pzd5QjResq79kAndkJcg",
|
||||||
|
@ -36,18 +35,24 @@ var run = function() {
|
||||||
var pubkeys = []
|
var pubkeys = []
|
||||||
privs.forEach(function(p) {
|
privs.forEach(function(p) {
|
||||||
var wk = new WalletKey(opts);
|
var wk = new WalletKey(opts);
|
||||||
wk.fromObj({priv: p});
|
wk.fromObj({
|
||||||
|
priv: p
|
||||||
|
});
|
||||||
pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public));
|
pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
var outs = [{nreq:3, pubkeys:pubkeys, amount:0.05}];
|
var outs = [{
|
||||||
|
nreq: 3,
|
||||||
|
pubkeys: pubkeys,
|
||||||
|
amount: 0.05
|
||||||
|
}];
|
||||||
var tx = new Builder(opts)
|
var tx = new Builder(opts)
|
||||||
.setUnspent(utxos)
|
.setUnspent(utxos)
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign([input.priv])
|
.sign([input.priv])
|
||||||
.build();
|
.build();
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('1) SEND TO MULSISIG TX: ', txHex);
|
console.log('1) SEND TO MULSISIG TX: ', txHex);
|
||||||
console.log('[this example originally generated TXID: e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5 on testnet]\n\n\thttp://test.bitcore.io/tx/e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5\n\n');
|
console.log('[this example originally generated TXID: e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5 on testnet]\n\n\thttp://test.bitcore.io/tx/e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5\n\n');
|
||||||
|
|
||||||
|
@ -59,31 +64,32 @@ var run = function() {
|
||||||
*
|
*
|
||||||
* REDDEEM TX
|
* REDDEEM TX
|
||||||
*/
|
*/
|
||||||
var utxos2 = [
|
var utxos2 = [{
|
||||||
{
|
|
||||||
address: input.addr,
|
address: input.addr,
|
||||||
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
||||||
vout: 0,
|
vout: 0,
|
||||||
ts: 1396288753,
|
ts: 1396288753,
|
||||||
scriptPubKey: scriptPubKey,
|
scriptPubKey: scriptPubKey,
|
||||||
amount: 0.05,
|
amount: 0.05,
|
||||||
confirmations: 2
|
confirmations: 2
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
|
|
||||||
outs = [{address:input.addr, amount:0.04}];
|
outs = [{
|
||||||
|
address: input.addr,
|
||||||
|
amount: 0.04
|
||||||
|
}];
|
||||||
var b = new Builder(opts)
|
var b = new Builder(opts)
|
||||||
.setUnspent(utxos2)
|
.setUnspent(utxos2)
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign(privs);
|
.sign(privs);
|
||||||
|
|
||||||
|
|
||||||
tx= b.build();
|
tx = b.build();
|
||||||
|
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('2) REDEEM SCRIPT: ', txHex);
|
console.log('2) REDEEM SCRIPT: ', txHex);
|
||||||
console.log('=> Is signed status:', b.isFullySigned(), tx.countInputMissingSignatures(0) );
|
console.log('=> Is signed status:', b.isFullySigned(), tx.countInputMissingSignatures(0));
|
||||||
|
|
||||||
console.log('[this example originally generated TXID: 1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83 on testnet]\n\n\thttp://test.bitcore.io/tx/1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83');
|
console.log('[this example originally generated TXID: 1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83 on testnet]\n\n\thttp://test.bitcore.io/tx/1eb388977b2de99562eb0fbcc661a100eaffed99c53bfcfebe5a087002039b83');
|
||||||
|
|
||||||
|
@ -100,4 +106,3 @@ if (typeof module !== 'undefined') {
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var run = function() {
|
var run = function() {
|
||||||
bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
bitcore = typeof(bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
||||||
|
|
||||||
var priv = 'cTgGUrcro89yUtKeG6gHBAS14r3qp25KwTTxG9d4kEzcFxecuZDm';
|
var priv = 'cTgGUrcro89yUtKeG6gHBAS14r3qp25KwTTxG9d4kEzcFxecuZDm';
|
||||||
var amt = '0.005';
|
var amt = '0.005';
|
||||||
var toAddress = 'myuAQcCc1REUgXGsCTiYhZvPPc3XxZ36G1';
|
var toAddress = 'myuAQcCc1REUgXGsCTiYhZvPPc3XxZ36G1';
|
||||||
var changeAddressString = 'moDz3jEo9q7CxjBDjmb13sL4SKkgo2AACE';
|
var changeAddressString = 'moDz3jEo9q7CxjBDjmb13sL4SKkgo2AACE';
|
||||||
|
|
||||||
|
@ -19,13 +16,20 @@ var run = function() {
|
||||||
confirmations: 2
|
confirmations: 2
|
||||||
}];
|
}];
|
||||||
|
|
||||||
console.log('TX Data: BTC:' + amt + ' => '+ toAddress + ', change To:' + changeAddressString ) ;
|
console.log('TX Data: BTC:' + amt + ' => ' + toAddress + ', change To:' + changeAddressString);
|
||||||
console.log('Unspends Outputs:', utxos);
|
console.log('Unspends Outputs:', utxos);
|
||||||
|
|
||||||
|
|
||||||
var outs = [{address:toAddress, amount:amt}];
|
var outs = [{
|
||||||
|
address: toAddress,
|
||||||
|
amount: amt
|
||||||
|
}];
|
||||||
var keys = [priv];
|
var keys = [priv];
|
||||||
var opts = {remainderOut: {address: changeAddressString}};
|
var opts = {
|
||||||
|
remainderOut: {
|
||||||
|
address: changeAddressString
|
||||||
|
}
|
||||||
|
};
|
||||||
var Builder = bitcore.TransactionBuilder;
|
var Builder = bitcore.TransactionBuilder;
|
||||||
|
|
||||||
var tx = new Builder(opts)
|
var tx = new Builder(opts)
|
||||||
|
@ -34,25 +38,25 @@ var run = function() {
|
||||||
.sign(keys)
|
.sign(keys)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
/* create and signing can be done in multiple steps using:
|
/* create and signing can be done in multiple steps using:
|
||||||
*
|
*
|
||||||
* var builder = new bitcore.TransactionBuilder(opts)
|
* var builder = new bitcore.TransactionBuilder(opts)
|
||||||
* .setUnspent(utxos)
|
* .setUnspent(utxos)
|
||||||
* .setOutputs(outs);
|
* .setOutputs(outs);
|
||||||
*
|
*
|
||||||
* builder.sign(key1);
|
* builder.sign(key1);
|
||||||
* builder.sign(key2);
|
* builder.sign(key2);
|
||||||
* ...
|
* ...
|
||||||
* if (builder.isFullySigned()){
|
* if (builder.isFullySigned()){
|
||||||
* var tx = builder.build();
|
* var tx = builder.build();
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* The selected Unspent Outputs for the transaction can be retrieved with:
|
* The selected Unspent Outputs for the transaction can be retrieved with:
|
||||||
*
|
*
|
||||||
* var selectedUnspent = build.getSelectedUnspent();
|
* var selectedUnspent = build.getSelectedUnspent();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('TX HEX IS: ', txHex);
|
console.log('TX HEX IS: ', txHex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,4 +71,3 @@ if (typeof module !== 'undefined') {
|
||||||
}
|
}
|
||||||
|
|
||||||
////
|
////
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
var run = function() {
|
var run = function() {
|
||||||
bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
bitcore = typeof(bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
||||||
var networks = require('../networks');
|
var networks = require('../networks');
|
||||||
var WalletKey = bitcore.WalletKey;
|
var WalletKey = bitcore.WalletKey;
|
||||||
var Script = bitcore.Script;
|
var Script = bitcore.Script;
|
||||||
var Builder = bitcore.TransactionBuilder;
|
var Builder = bitcore.TransactionBuilder;
|
||||||
var opts = {network: networks.testnet};
|
var opts = {
|
||||||
|
network: networks.testnet
|
||||||
|
};
|
||||||
|
|
||||||
console.log('## Network: ' + opts.network.name);
|
console.log('## Network: ' + opts.network.name);
|
||||||
|
|
||||||
|
@ -13,19 +15,17 @@ var run = function() {
|
||||||
input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V";
|
input.priv = "cS62Ej4SobZnpFQYN1PEEBr2KWf5sgRYYnELtumcG6WVCfxno39V";
|
||||||
|
|
||||||
// Complete with the corresponding UTXO you want to use
|
// Complete with the corresponding UTXO you want to use
|
||||||
var utxos = [
|
var utxos = [{
|
||||||
{
|
|
||||||
address: "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp",
|
address: "n2hoFVbPrYQf7RJwiRy1tkbuPPqyhAEfbp",
|
||||||
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
txid: "e4bc22d8c519d3cf848d710619f8480be56176a4a6548dfbe865ab3886b578b5",
|
||||||
vout: 1,
|
vout: 1,
|
||||||
ts: 1396290442,
|
ts: 1396290442,
|
||||||
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
scriptPubKey: "76a914e867aad8bd361f57c50adc37a0c018692b5b0c9a88ac",
|
||||||
amount: 0.3795,
|
amount: 0.3795,
|
||||||
confirmations: 7
|
confirmations: 7
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
|
|
||||||
var privs = [
|
var privs = [
|
||||||
"cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA",
|
"cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA",
|
||||||
"cVf32m9MR4vxcPwKNJuPepUe8XrHD2z63eCk76d6njRGyCkXpkSM",
|
"cVf32m9MR4vxcPwKNJuPepUe8XrHD2z63eCk76d6njRGyCkXpkSM",
|
||||||
"cQ2sVRFX4jQYMLhWyzz6jTQ2xju51P36968ecXnPhRLKLH677eKR",
|
"cQ2sVRFX4jQYMLhWyzz6jTQ2xju51P36968ecXnPhRLKLH677eKR",
|
||||||
|
@ -36,29 +36,37 @@ var run = function() {
|
||||||
var pubkeys = []
|
var pubkeys = []
|
||||||
privs.forEach(function(p) {
|
privs.forEach(function(p) {
|
||||||
var wk = new WalletKey(opts);
|
var wk = new WalletKey(opts);
|
||||||
wk.fromObj({priv: p});
|
wk.fromObj({
|
||||||
|
priv: p
|
||||||
|
});
|
||||||
pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public));
|
pubkeys.push(bitcore.buffertools.toHex(wk.privKey.public));
|
||||||
});
|
});
|
||||||
|
|
||||||
// multisig p2sh
|
// multisig p2sh
|
||||||
var opts = {nreq:3, pubkeys:pubkeys};
|
var opts = {
|
||||||
|
nreq: 3,
|
||||||
|
pubkeys: pubkeys
|
||||||
|
};
|
||||||
|
|
||||||
// p2scriphash p2sh
|
// p2scriphash p2sh
|
||||||
//var opts = [{address: an_address}];
|
//var opts = [{address: an_address}];
|
||||||
|
|
||||||
var info = Builder.infoForP2sh(opts, 'testnet');
|
var info = Builder.infoForP2sh(opts, 'testnet');
|
||||||
var p2shScript = info.scriptBufHex;
|
var p2shScript = info.scriptBufHex;
|
||||||
var p2shAddress = info.address;
|
var p2shAddress = info.address;
|
||||||
|
|
||||||
|
|
||||||
var outs = [{address:p2shAddress, amount:0.05}];
|
var outs = [{
|
||||||
|
address: p2shAddress,
|
||||||
|
amount: 0.05
|
||||||
|
}];
|
||||||
var tx = new Builder(opts)
|
var tx = new Builder(opts)
|
||||||
.setUnspent(utxos)
|
.setUnspent(utxos)
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign([input.priv])
|
.sign([input.priv])
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
|
|
||||||
|
|
||||||
console.log('## p2sh address: ' + p2shAddress); //TODO
|
console.log('## p2sh address: ' + p2shAddress); //TODO
|
||||||
|
@ -72,8 +80,7 @@ var run = function() {
|
||||||
*
|
*
|
||||||
* REDDEEM TX
|
* REDDEEM TX
|
||||||
*/
|
*/
|
||||||
var utxos2 = [
|
var utxos2 = [{
|
||||||
{
|
|
||||||
address: p2shAddress,
|
address: p2shAddress,
|
||||||
txid: "c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7",
|
txid: "c2e50d1c8c581d8c4408378b751633f7eb86687fc5f0502be7b467173f275ae7",
|
||||||
vout: 0,
|
vout: 0,
|
||||||
|
@ -81,13 +88,15 @@ var run = function() {
|
||||||
scriptPubKey: scriptPubKey,
|
scriptPubKey: scriptPubKey,
|
||||||
amount: 0.05,
|
amount: 0.05,
|
||||||
confirmations: 1
|
confirmations: 1
|
||||||
}
|
}];
|
||||||
];
|
|
||||||
|
|
||||||
outs = [{address:input.addr, amount:0.04}];
|
outs = [{
|
||||||
|
address: input.addr,
|
||||||
|
amount: 0.04
|
||||||
|
}];
|
||||||
|
|
||||||
var hashMap = {};
|
var hashMap = {};
|
||||||
hashMap[p2shAddress]=p2shScript;
|
hashMap[p2shAddress] = p2shScript;
|
||||||
|
|
||||||
var b = new Builder(opts)
|
var b = new Builder(opts)
|
||||||
.setUnspent(utxos2)
|
.setUnspent(utxos2)
|
||||||
|
@ -95,21 +104,21 @@ var run = function() {
|
||||||
.setOutputs(outs)
|
.setOutputs(outs)
|
||||||
.sign(privs);
|
.sign(privs);
|
||||||
|
|
||||||
tx= b.build();
|
tx = b.build();
|
||||||
|
|
||||||
|
|
||||||
console.log('Builder:');
|
console.log('Builder:');
|
||||||
console.log('\tSignatures:' + tx.countInputMissingSignatures(0) );
|
console.log('\tSignatures:' + tx.countInputMissingSignatures(0));
|
||||||
console.log('\t#isFullySigned:' + b.isFullySigned() );
|
console.log('\t#isFullySigned:' + b.isFullySigned());
|
||||||
|
|
||||||
console.log('TX:');
|
console.log('TX:');
|
||||||
console.log('\t #isComplete:' + tx.isComplete() );
|
console.log('\t #isComplete:' + tx.isComplete());
|
||||||
|
|
||||||
var txHex = tx.serialize().toString('hex');
|
var txHex = tx.serialize().toString('hex');
|
||||||
console.log('2) REDEEM SCRIPT: ', txHex);
|
console.log('2) REDEEM SCRIPT: ', txHex);
|
||||||
console.log('[this example originally generated TXID: 8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7 on testnet]\n\n\thttp://test.bitcore.io/tx/8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7\n\n');
|
console.log('[this example originally generated TXID: 8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7 on testnet]\n\n\thttp://test.bitcore.io/tx/8284aa3b6f9c71c35ecb1d61d05ae78c8ca1f36940eaa615b50584dfc3d95cb7\n\n');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// To send TX with RPC:
|
// To send TX with RPC:
|
||||||
var RpcClient = bitcore.RpcClient;
|
var RpcClient = bitcore.RpcClient;
|
||||||
var config = {
|
var config = {
|
||||||
|
|
|
@ -8,21 +8,23 @@ var run = function() {
|
||||||
var networks = require('../networks');
|
var networks = require('../networks');
|
||||||
var WalletKey = bitcore.WalletKey;
|
var WalletKey = bitcore.WalletKey;
|
||||||
|
|
||||||
var opts = {network: networks.testnet};
|
var opts = {
|
||||||
|
network: networks.testnet
|
||||||
|
};
|
||||||
|
|
||||||
function print(wk) {
|
function print(wk) {
|
||||||
|
|
||||||
console.log('\n## Network: ' + wk.network.name);
|
console.log('\n## Network: ' + wk.network.name);
|
||||||
console.log ('\t * Hex Representation');
|
console.log('\t * Hex Representation');
|
||||||
console.log ('\tPrivate: ' + bitcore.buffertools.toHex(wk.privKey.private));
|
console.log('\tPrivate: ' + bitcore.buffertools.toHex(wk.privKey.private));
|
||||||
console.log ('\tPublic : ' + bitcore.buffertools.toHex(wk.privKey.public));
|
console.log('\tPublic : ' + bitcore.buffertools.toHex(wk.privKey.public));
|
||||||
console.log ('\tPublic Compressed : ' + (wk.privKey.compressed?'Yes':'No'));
|
console.log('\tPublic Compressed : ' + (wk.privKey.compressed ? 'Yes' : 'No'));
|
||||||
|
|
||||||
var wkObj = wk.storeObj();
|
var wkObj = wk.storeObj();
|
||||||
console.log ('\n\t * WalletKey Store Object');
|
console.log('\n\t * WalletKey Store Object');
|
||||||
console.log ('\tPrivate: ' + wkObj.priv);
|
console.log('\tPrivate: ' + wkObj.priv);
|
||||||
console.log ('\tPublic : ' + wkObj.pub);
|
console.log('\tPublic : ' + wkObj.pub);
|
||||||
console.log ('\tAddr : ' + wkObj.addr);
|
console.log('\tAddr : ' + wkObj.addr);
|
||||||
};
|
};
|
||||||
|
|
||||||
//Generate a new one (compressed public key, compressed WIF flag)
|
//Generate a new one (compressed public key, compressed WIF flag)
|
||||||
|
@ -32,7 +34,9 @@ var run = function() {
|
||||||
|
|
||||||
//Generate from private Key WIF. Compressed status taken from WIF.
|
//Generate from private Key WIF. Compressed status taken from WIF.
|
||||||
var wk2 = new WalletKey(opts);
|
var wk2 = new WalletKey(opts);
|
||||||
wk2.fromObj({priv:'cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA'});
|
wk2.fromObj({
|
||||||
|
priv: 'cMpKwGr5oxEacN95WFKNEq6tTcvi11regFwS3muHvGYVxMPJX8JA'
|
||||||
|
});
|
||||||
print(wk2);
|
print(wk2);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,9 @@ var run = function() {
|
||||||
var buffertools = bitcore.buffertools;
|
var buffertools = bitcore.buffertools;
|
||||||
var Address = bitcore.Address;
|
var Address = bitcore.Address;
|
||||||
var util = bitcore.util;
|
var util = bitcore.util;
|
||||||
var opts = {network: networks.testnet};
|
var opts = {
|
||||||
|
network: networks.testnet
|
||||||
|
};
|
||||||
|
|
||||||
var p = console.log;
|
var p = console.log;
|
||||||
|
|
||||||
|
@ -22,38 +24,38 @@ var run = function() {
|
||||||
p('\tHex : ' + buffertools.toHex(s.buffer));
|
p('\tHex : ' + buffertools.toHex(s.buffer));
|
||||||
p('\tHuman : ' + s.toHumanReadable());
|
p('\tHuman : ' + s.toHumanReadable());
|
||||||
p('\tKey -------------------------------');
|
p('\tKey -------------------------------');
|
||||||
console.log ('\tPrivate: ' + wkObj.priv);
|
console.log('\tPrivate: ' + wkObj.priv);
|
||||||
console.log ('\tPublic : ' + wkObj.pub);
|
console.log('\tPublic : ' + wkObj.pub);
|
||||||
console.log ('\tAddr : ' + wkObj.addr);
|
console.log('\tAddr : ' + wkObj.addr);
|
||||||
|
|
||||||
s = Script.createPubKeyHashOut(wk.privKey.public);
|
s = Script.createPubKeyHashOut(wk.privKey.public);
|
||||||
p('\nScript PubKeyHash:');
|
p('\nScript PubKeyHash:');
|
||||||
p('\tHex : ' + buffertools.toHex(s.buffer));
|
p('\tHex : ' + buffertools.toHex(s.buffer));
|
||||||
p('\tHuman : ' + s.toHumanReadable());
|
p('\tHuman : ' + s.toHumanReadable());
|
||||||
p('\tKey -------------------------------');
|
p('\tKey -------------------------------');
|
||||||
console.log ('\tPrivate: ' + wkObj.priv);
|
console.log('\tPrivate: ' + wkObj.priv);
|
||||||
console.log ('\tPublic : ' + wkObj.pub);
|
console.log('\tPublic : ' + wkObj.pub);
|
||||||
console.log ('\tAddr : ' + wkObj.addr);
|
console.log('\tAddr : ' + wkObj.addr);
|
||||||
|
|
||||||
var wks=[];
|
var wks = [];
|
||||||
var pubs = [];
|
var pubs = [];
|
||||||
for (var i =0; i<5; i++) {
|
for (var i = 0; i < 5; i++) {
|
||||||
wks[i] = new WalletKey(opts);
|
wks[i] = new WalletKey(opts);
|
||||||
wks[i].generate();
|
wks[i].generate();
|
||||||
pubs.push(wks[i].privKey.public);
|
pubs.push(wks[i].privKey.public);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = Script.createMultisig(3,pubs);
|
s = Script.createMultisig(3, pubs);
|
||||||
p('\nScript MultiSig (3 out of 5 required signatures):');
|
p('\nScript MultiSig (3 out of 5 required signatures):');
|
||||||
p('\tHex : ' + buffertools.toHex(s.buffer));
|
p('\tHex : ' + buffertools.toHex(s.buffer));
|
||||||
p('\tHuman : ' + s.toHumanReadable());
|
p('\tHuman : ' + s.toHumanReadable());
|
||||||
|
|
||||||
for (i =0; i<5; i++) {
|
for (i = 0; i < 5; i++) {
|
||||||
wkObj = wks[i].storeObj();
|
wkObj = wks[i].storeObj();
|
||||||
p('\tKey ['+i+'] -------------------------------');
|
p('\tKey [' + i + '] -------------------------------');
|
||||||
console.log ('\tPrivate: ' + wkObj.priv);
|
console.log('\tPrivate: ' + wkObj.priv);
|
||||||
console.log ('\tPublic : ' + wkObj.pub);
|
console.log('\tPublic : ' + wkObj.pub);
|
||||||
console.log ('\tAddr : ' + wkObj.addr);
|
console.log('\tAddr : ' + wkObj.addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash = util.sha256ripe160(s.buffer);
|
var hash = util.sha256ripe160(s.buffer);
|
||||||
|
@ -62,10 +64,10 @@ var run = function() {
|
||||||
p('\nScript P2SH:');
|
p('\nScript P2SH:');
|
||||||
p('\tHex : ' + buffertools.toHex(s.buffer));
|
p('\tHex : ' + buffertools.toHex(s.buffer));
|
||||||
p('\tHuman : ' + s.toHumanReadable());
|
p('\tHuman : ' + s.toHumanReadable());
|
||||||
p('\tScript Hash: ' + buffertools.toHex(hash));
|
p('\tScript Hash: ' + buffertools.toHex(hash));
|
||||||
var a = new Address(networks.livenet.P2SHVersion,hash);
|
var a = new Address(networks.livenet.P2SHVersion, hash);
|
||||||
p('\tp2sh Addr: ' + a.toString());
|
p('\tp2sh Addr: ' + a.toString());
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.run = run;
|
module.exports.run = run;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
var run = function() {
|
var run = function() {
|
||||||
bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
bitcore = typeof(bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
||||||
|
|
||||||
console.log('ECIES: Elliptic Curve Integrated Encryption Scheme');
|
console.log('ECIES: Elliptic Curve Integrated Encryption Scheme');
|
||||||
console.log('A way of encrypting with a public key and decrypting with a private key.');
|
console.log('A way of encrypting with a public key and decrypting with a private key.');
|
||||||
|
|
||||||
var key = bitcore.Key.generateSync();
|
var key = bitcore.Key.generateSync();
|
||||||
console.log('Private key: ' + key.private.toString('hex'));
|
console.log('Private key: ' + key.private.toString('hex'));
|
||||||
console.log('Public key: ' + key.public.toString('hex'));
|
console.log('Public key: ' + key.public.toString('hex'));
|
||||||
|
|
||||||
var message = new Buffer('This is a message to be encrypted');
|
var message = new Buffer('This is a message to be encrypted');
|
||||||
console.log('Message: "' + message.toString() + '"');
|
console.log('Message: "' + message.toString() + '"');
|
||||||
|
|
||||||
var encrypted = bitcore.ECIES.encrypt(key.public, message);
|
var encrypted = bitcore.ECIES.encrypt(key.public, message);
|
||||||
console.log('Encrypted (with public key): ' + encrypted.toString('hex'));
|
console.log('Encrypted (with public key): ' + encrypted.toString('hex'));
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
var run = function() {
|
var run = function() {
|
||||||
bitcore = typeof (bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
bitcore = typeof(bitcore) === 'undefined' ? require('../bitcore') : bitcore;
|
||||||
var HierarchicalKey = bitcore.HierarchicalKey;
|
var HierarchicalKey = bitcore.HierarchicalKey;
|
||||||
var Address = bitcore.Address;
|
var Address = bitcore.Address;
|
||||||
var networks = bitcore.networks;
|
var networks = bitcore.networks;
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
var PeerManager = require('../lib/PeerManager');
|
var PeerManager = require('../lib/PeerManager');
|
||||||
var peerman = new PeerManager();
|
var peerman = new PeerManager();
|
||||||
|
|
||||||
peerman.discover({ limit: 12 }).start();
|
peerman.discover({
|
||||||
|
limit: 12
|
||||||
|
}).start();
|
||||||
|
|
|
@ -81,7 +81,7 @@ var run = function() {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var txid = tx.getHash().toString('hex');
|
var txid = tx.getHash().toString('hex');
|
||||||
console.log('Created transaction with txid '+txid);
|
console.log('Created transaction with txid ' + txid);
|
||||||
var raw_tx = tx.serialize().toString('hex');
|
var raw_tx = tx.serialize().toString('hex');
|
||||||
console.log('Transaction raw hex dump:');
|
console.log('Transaction raw hex dump:');
|
||||||
console.log('-------------------------------------');
|
console.log('-------------------------------------');
|
||||||
|
|
|
@ -18,16 +18,17 @@ var socket = peer.createConnection();
|
||||||
|
|
||||||
var con = new Connection(socket, peer);
|
var con = new Connection(socket, peer);
|
||||||
|
|
||||||
con.on('error', function (msg) {
|
con.on('error', function(msg) {
|
||||||
var peer = msg.peer, err = msg.err;
|
var peer = msg.peer,
|
||||||
|
err = msg.err;
|
||||||
console.error('Error connecting to peer', peer.host + ':' + peer.port, '(' + err.message + ')');
|
console.error('Error connecting to peer', peer.host + ':' + peer.port, '(' + err.message + ')');
|
||||||
});
|
});
|
||||||
|
|
||||||
con.on('disconnect', function (msg) {
|
con.on('disconnect', function(msg) {
|
||||||
console.log('disconnect: ', msg);
|
console.log('disconnect: ', msg);
|
||||||
});
|
});
|
||||||
|
|
||||||
con.on('connect', function (msg) {
|
con.on('connect', function(msg) {
|
||||||
console.log('Connected to %s', msg.peer.host + ':' + msg.peer.port);
|
console.log('Connected to %s', msg.peer.host + ':' + msg.peer.port);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -36,37 +37,36 @@ con.on('connect', function (msg) {
|
||||||
// Make a log function available to all listeners
|
// Make a log function available to all listeners
|
||||||
// The log function is just like console.log except it prefixes
|
// The log function is just like console.log except it prefixes
|
||||||
// messages with [host:port]
|
// messages with [host:port]
|
||||||
function listen (event_name, fn) {
|
function listen(event_name, fn) {
|
||||||
con.on(event_name, function (event) {
|
con.on(event_name, function(event) {
|
||||||
fn(event, function () {
|
fn(event, function() {
|
||||||
var args = Array.prototype.slice.call(arguments);
|
var args = Array.prototype.slice.call(arguments);
|
||||||
var str = args.shift();
|
var str = args.shift();
|
||||||
str = '[%s:%s] ' + str;
|
str = '[%s:%s] ' + str;
|
||||||
args = [ str, event.peer.host, event.peer.port ].concat(args);
|
args = [str, event.peer.host, event.peer.port].concat(args);
|
||||||
console.log.apply(console, args);
|
console.log.apply(console, args);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
listen('getaddr', function (event, log) {
|
listen('getaddr', function(event, log) {
|
||||||
log('Received message getaddr');
|
log('Received message getaddr');
|
||||||
log(event);
|
log(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
listen('verack', function (event, log) {
|
listen('verack', function(event, log) {
|
||||||
log('Received message verack');
|
log('Received message verack');
|
||||||
});
|
});
|
||||||
|
|
||||||
listen('version', function (event, log) {
|
listen('version', function(event, log) {
|
||||||
log('Received message version (%s)', event.message.version);
|
log('Received message version (%s)', event.message.version);
|
||||||
});
|
});
|
||||||
|
|
||||||
listen('addr', function (event, log) {
|
listen('addr', function(event, log) {
|
||||||
log('Received message addr (%s addresses)', event.message.addrs.length);
|
log('Received message addr (%s addresses)', event.message.addrs.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
listen('inv', function (event, log) {
|
listen('inv', function(event, log) {
|
||||||
log('Received message inv (%s invs)', event.message.count);
|
log('Received message inv (%s invs)', event.message.count);
|
||||||
console.log(event.message.invs);
|
console.log(event.message.invs);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,15 +10,15 @@ var run = function() {
|
||||||
// config your regular expression
|
// config your regular expression
|
||||||
var re = /[0-9]{6}$/; // ends in 6 digits
|
var re = /[0-9]{6}$/; // ends in 6 digits
|
||||||
|
|
||||||
var a,k,m;
|
var a, k, m;
|
||||||
while (true) {
|
while (true) {
|
||||||
k = Key.generateSync();
|
k = Key.generateSync();
|
||||||
a = Address.fromKey(k);
|
a = Address.fromKey(k);
|
||||||
m = a.toString().match(re);
|
m = a.toString().match(re);
|
||||||
if (m) break;
|
if (m) break;
|
||||||
}
|
}
|
||||||
console.log('Address: '+a.toString());
|
console.log('Address: ' + a.toString());
|
||||||
console.log('Private Key: '+k.private.toString('hex'));
|
console.log('Private Key: ' + k.private.toString('hex'));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -85,7 +85,7 @@ Address.fromScript = function(script, network) {
|
||||||
network = 'livenet';
|
network = 'livenet';
|
||||||
|
|
||||||
if (typeof script === 'string') {
|
if (typeof script === 'string') {
|
||||||
script = new Script(new Buffer(script,'hex'));
|
script = new Script(new Buffer(script, 'hex'));
|
||||||
}
|
}
|
||||||
|
|
||||||
var version = networks[network].P2SHVersion;
|
var version = networks[network].P2SHVersion;
|
||||||
|
@ -99,16 +99,17 @@ Address.fromScript = function(script, network) {
|
||||||
Address.fromScriptPubKey = function(scriptPubKey, network) {
|
Address.fromScriptPubKey = function(scriptPubKey, network) {
|
||||||
|
|
||||||
if (typeof scriptPubKey === 'string') {
|
if (typeof scriptPubKey === 'string') {
|
||||||
scriptPubKey = new Script(new Buffer(scriptPubKey,'hex'));
|
scriptPubKey = new Script(new Buffer(scriptPubKey, 'hex'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!network)
|
if (!network)
|
||||||
network = 'livenet';
|
network = 'livenet';
|
||||||
|
|
||||||
var ret=[], version;
|
var ret = [],
|
||||||
|
version;
|
||||||
var payload = scriptPubKey.capture();
|
var payload = scriptPubKey.capture();
|
||||||
|
|
||||||
if (payload) {
|
if (payload) {
|
||||||
var txType = scriptPubKey.classify();
|
var txType = scriptPubKey.classify();
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case Script.TX_PUBKEY:
|
case Script.TX_PUBKEY:
|
||||||
|
@ -120,15 +121,15 @@ Address.fromScriptPubKey = function(scriptPubKey, network) {
|
||||||
break;
|
break;
|
||||||
case Script.TX_MULTISIG:
|
case Script.TX_MULTISIG:
|
||||||
version = networks[network].addressVersion;
|
version = networks[network].addressVersion;
|
||||||
for(var i in payload)
|
for (var i in payload)
|
||||||
payload[i] = coinUtil.sha256ripe160(payload[i]);
|
payload[i] = coinUtil.sha256ripe160(payload[i]);
|
||||||
break;
|
break;
|
||||||
case Script.TX_SCRIPTHASH:
|
case Script.TX_SCRIPTHASH:
|
||||||
version = networks[network].P2SHVersion;
|
version = networks[network].P2SHVersion;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for(var i in payload)
|
for (var i in payload)
|
||||||
ret.push(new Address(version,payload[i]));
|
ret.push(new Address(version, payload[i]));
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
@ -137,7 +138,7 @@ Address.fromScriptPubKey = function(scriptPubKey, network) {
|
||||||
Address.prototype.validate = function() {
|
Address.prototype.validate = function() {
|
||||||
this.doAsBinary(function() {
|
this.doAsBinary(function() {
|
||||||
Address.super(this, 'validate', arguments);
|
Address.super(this, 'validate', arguments);
|
||||||
if(this.data.length !== 21) throw new Error('invalid data length');
|
if (this.data.length !== 21) throw new Error('invalid data length');
|
||||||
});
|
});
|
||||||
if (typeof this.network() === 'undefined') throw new Error('invalid network');
|
if (typeof this.network() === 'undefined') throw new Error('invalid network');
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,12 +9,12 @@ var Point = require('./Point'),
|
||||||
*
|
*
|
||||||
* @example examples/Armory.js
|
* @example examples/Armory.js
|
||||||
*/
|
*/
|
||||||
function Armory (chaincode, pubkey) {
|
function Armory(chaincode, pubkey) {
|
||||||
this.chaincode = new Buffer(chaincode, 'hex');
|
this.chaincode = new Buffer(chaincode, 'hex');
|
||||||
this.pubkey = new Buffer(pubkey, 'hex');
|
this.pubkey = new Buffer(pubkey, 'hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
Armory.prototype.generatePubKey = function () {
|
Armory.prototype.generatePubKey = function() {
|
||||||
var pubKey = this.pubkey;
|
var pubKey = this.pubkey;
|
||||||
var chainCode = this.chaincode;
|
var chainCode = this.chaincode;
|
||||||
var chainXor = twoSha256(pubKey);
|
var chainXor = twoSha256(pubKey);
|
||||||
|
@ -30,7 +30,7 @@ Armory.prototype.generatePubKey = function () {
|
||||||
return new_pubkey;
|
return new_pubkey;
|
||||||
};
|
};
|
||||||
|
|
||||||
Armory.prototype.next = function () {
|
Armory.prototype.next = function() {
|
||||||
var next_pubkey = this.generatePubKey();
|
var next_pubkey = this.generatePubKey();
|
||||||
return new Armory(this.chaincode, next_pubkey);
|
return new Armory(this.chaincode, next_pubkey);
|
||||||
};
|
};
|
||||||
|
@ -44,13 +44,13 @@ Armory.prototype.next = function () {
|
||||||
*
|
*
|
||||||
* https://github.com/etotheipi/BitcoinArmory/issues/204#issuecomment-42217801
|
* https://github.com/etotheipi/BitcoinArmory/issues/204#issuecomment-42217801
|
||||||
*/
|
*/
|
||||||
Armory.fromMasterPublicKey = function (mpk) {
|
Armory.fromMasterPublicKey = function(mpk) {
|
||||||
var pubkey = mpk.substr(0, 130);
|
var pubkey = mpk.substr(0, 130);
|
||||||
var chaincode = mpk.substr(130, mpk.length);
|
var chaincode = mpk.substr(130, mpk.length);
|
||||||
return new Armory(chaincode, pubkey);
|
return new Armory(chaincode, pubkey);
|
||||||
};
|
};
|
||||||
|
|
||||||
function decode (str) {
|
function decode(str) {
|
||||||
var from = '0123456789abcdef';
|
var from = '0123456789abcdef';
|
||||||
var to = 'asdfghjkwertuion';
|
var to = 'asdfghjkwertuion';
|
||||||
var res = '';
|
var res = '';
|
||||||
|
@ -59,20 +59,20 @@ function decode (str) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
Armory.decodeSeed = function (seed) {
|
Armory.decodeSeed = function(seed) {
|
||||||
var keys = seed.trim().split('\n');
|
var keys = seed.trim().split('\n');
|
||||||
var lines = [];
|
var lines = [];
|
||||||
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
var k = keys[i].replace(' ','');
|
var k = keys[i].replace(' ', '');
|
||||||
var raw = new Buffer(decode(k), 'hex');
|
var raw = new Buffer(decode(k), 'hex');
|
||||||
var data = raw.slice(0, 16);
|
var data = raw.slice(0, 16);
|
||||||
lines.push(data);
|
lines.push(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
var privKey = Buffer.concat([ lines[0], lines[1] ]);
|
var privKey = Buffer.concat([lines[0], lines[1]]);
|
||||||
var chainCode = (lines.length==4) ?
|
var chainCode = (lines.length == 4) ?
|
||||||
Buffer.concat([ lines[2], lines[3] ]) : Armory.deriveChaincode(privKey);
|
Buffer.concat([lines[2], lines[3]]) : Armory.deriveChaincode(privKey);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
privKey: privKey,
|
privKey: privKey,
|
||||||
|
@ -81,7 +81,7 @@ Armory.decodeSeed = function (seed) {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Derive chain code from root key
|
// Derive chain code from root key
|
||||||
Armory.fromSeed = function (seed) {
|
Armory.fromSeed = function(seed) {
|
||||||
var res = Armory.decodeSeed(seed);
|
var res = Armory.decodeSeed(seed);
|
||||||
// generate first public key
|
// generate first public key
|
||||||
var key = new Key();
|
var key = new Key();
|
||||||
|
@ -92,7 +92,7 @@ Armory.fromSeed = function (seed) {
|
||||||
return new Armory(res.chainCode, key.public);
|
return new Armory(res.chainCode, key.public);
|
||||||
};
|
};
|
||||||
|
|
||||||
Armory.deriveChaincode = function (root) {
|
Armory.deriveChaincode = function(root) {
|
||||||
var msg = 'Derive Chaincode from Root Key';
|
var msg = 'Derive Chaincode from Root Key';
|
||||||
var hash = twoSha256(root);
|
var hash = twoSha256(root);
|
||||||
|
|
||||||
|
@ -107,8 +107,8 @@ Armory.deriveChaincode = function (root) {
|
||||||
ikey = new Buffer(ikey);
|
ikey = new Buffer(ikey);
|
||||||
|
|
||||||
var m = new Buffer(msg, 'utf8');
|
var m = new Buffer(msg, 'utf8');
|
||||||
var a = sha256(Buffer.concat([ ikey, m ]));
|
var a = sha256(Buffer.concat([ikey, m]));
|
||||||
var b = sha256(Buffer.concat([ okey, a ]));
|
var b = sha256(Buffer.concat([okey, a]));
|
||||||
return b;
|
return b;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
15
lib/BIP39.js
15
lib/BIP39.js
|
@ -3,10 +3,10 @@ var coinUtil = imports.coinUtil || require('../util');
|
||||||
var sjcl = imports.sjcl || require('./sjcl');
|
var sjcl = imports.sjcl || require('./sjcl');
|
||||||
var SecureRandom = require('./SecureRandom');
|
var SecureRandom = require('./SecureRandom');
|
||||||
|
|
||||||
var hmacSHA512 = function (key) {
|
var hmacSHA512 = function(key) {
|
||||||
var hasher = new sjcl.misc.hmac(key, sjcl.hash.sha512);
|
var hasher = new sjcl.misc.hmac(key, sjcl.hash.sha512);
|
||||||
this.encrypt = function () {
|
this.encrypt = function() {
|
||||||
return hasher.encrypt.apply(hasher, arguments);
|
return hasher.encrypt.apply(hasher, arguments);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,8 +15,7 @@ var pbkdf2Sync_sha512 = function(password, salt, iterations, keylen) {
|
||||||
return sjcl.codec.hex.fromBits(derivedKey)
|
return sjcl.codec.hex.fromBits(derivedKey)
|
||||||
};
|
};
|
||||||
|
|
||||||
var BIP39 = function() {
|
var BIP39 = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
BIP39.mnemonic = function(wordlist, bits) {
|
BIP39.mnemonic = function(wordlist, bits) {
|
||||||
if (!bits)
|
if (!bits)
|
||||||
|
@ -31,11 +30,11 @@ BIP39.entropy2mnemonic = function(wordlist, buf) {
|
||||||
var hash = coinUtil.sha256(buf);
|
var hash = coinUtil.sha256(buf);
|
||||||
var bin = "";
|
var bin = "";
|
||||||
var bits = buf.length * 8;
|
var bits = buf.length * 8;
|
||||||
for (var i = 0 ; i < buf.length ; i++) {
|
for (var i = 0; i < buf.length; i++) {
|
||||||
bin = bin + ("00000000" + buf[i].toString(2)).slice(-8);
|
bin = bin + ("00000000" + buf[i].toString(2)).slice(-8);
|
||||||
}
|
}
|
||||||
var hashbits = hash[0].toString(2);
|
var hashbits = hash[0].toString(2);
|
||||||
hashbits = ("00000000" + hashbits).slice(-8).slice(0, bits/32);
|
hashbits = ("00000000" + hashbits).slice(-8).slice(0, bits / 32);
|
||||||
bin = bin + hashbits;
|
bin = bin + hashbits;
|
||||||
if (bin.length % 11 != 0)
|
if (bin.length % 11 != 0)
|
||||||
throw new Error("internal error - entropy not an even multiple of 11 bits - " + bin.length);
|
throw new Error("internal error - entropy not an even multiple of 11 bits - " + bin.length);
|
||||||
|
@ -43,7 +42,7 @@ BIP39.entropy2mnemonic = function(wordlist, buf) {
|
||||||
for (var i = 0; i < bin.length / 11; i++) {
|
for (var i = 0; i < bin.length / 11; i++) {
|
||||||
if (mnemonic != "")
|
if (mnemonic != "")
|
||||||
mnemonic = mnemonic + " ";
|
mnemonic = mnemonic + " ";
|
||||||
var wi = parseInt(bin.slice(i*11, (i+1)*11), 2);
|
var wi = parseInt(bin.slice(i * 11, (i + 1) * 11), 2);
|
||||||
mnemonic = mnemonic + wordlist[wi];
|
mnemonic = mnemonic + wordlist[wi];
|
||||||
}
|
}
|
||||||
return mnemonic;
|
return mnemonic;
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -7,7 +7,7 @@ var ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
||||||
var ALPHABET_ZERO = ALPHABET[0];
|
var ALPHABET_ZERO = ALPHABET[0];
|
||||||
var ALPHABET_BUF = new Buffer(ALPHABET, 'ascii');
|
var ALPHABET_BUF = new Buffer(ALPHABET, 'ascii');
|
||||||
var ALPHABET_INV = {};
|
var ALPHABET_INV = {};
|
||||||
for(var i=0; i < ALPHABET.length; i++) {
|
for (var i = 0; i < ALPHABET.length; i++) {
|
||||||
ALPHABET_INV[ALPHABET[i]] = i;
|
ALPHABET_INV[ALPHABET[i]] = i;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,13 +18,13 @@ var base58 = {
|
||||||
var x = bignum.fromBuffer(buf);
|
var x = bignum.fromBuffer(buf);
|
||||||
var r;
|
var r;
|
||||||
|
|
||||||
if(buf.length < 512) {
|
if (buf.length < 512) {
|
||||||
str = globalBuffer;
|
str = globalBuffer;
|
||||||
} else {
|
} else {
|
||||||
str = new Buffer(buf.length << 1);
|
str = new Buffer(buf.length << 1);
|
||||||
}
|
}
|
||||||
var i = str.length - 1;
|
var i = str.length - 1;
|
||||||
while(x.gt(0)) {
|
while (x.gt(0)) {
|
||||||
r = x.mod(58);
|
r = x.mod(58);
|
||||||
x = x.div(58);
|
x = x.div(58);
|
||||||
str[i] = ALPHABET_BUF[r.toNumber()];
|
str[i] = ALPHABET_BUF[r.toNumber()];
|
||||||
|
@ -32,32 +32,33 @@ var base58 = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// deal with leading zeros
|
// deal with leading zeros
|
||||||
var j=0;
|
var j = 0;
|
||||||
while(buf[j] == 0) {
|
while (buf[j] == 0) {
|
||||||
str[i] = ALPHABET_BUF[0];
|
str[i] = ALPHABET_BUF[0];
|
||||||
j++; i--;
|
j++;
|
||||||
|
i--;
|
||||||
}
|
}
|
||||||
|
|
||||||
return str.slice(i+1,str.length).toString('ascii');
|
return str.slice(i + 1, str.length).toString('ascii');
|
||||||
},
|
},
|
||||||
|
|
||||||
decode: function(str) {
|
decode: function(str) {
|
||||||
if(str.length == 0) return zerobuf;
|
if (str.length == 0) return zerobuf;
|
||||||
var answer = bignum(0);
|
var answer = bignum(0);
|
||||||
for(var i=0; i<str.length; i++) {
|
for (var i = 0; i < str.length; i++) {
|
||||||
answer = answer.mul(58);
|
answer = answer.mul(58);
|
||||||
answer = answer.add(ALPHABET_INV[str[i]]);
|
answer = answer.add(ALPHABET_INV[str[i]]);
|
||||||
};
|
};
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while(i < str.length && str[i] == ALPHABET_ZERO) {
|
while (i < str.length && str[i] == ALPHABET_ZERO) {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if(i > 0) {
|
if (i > 0) {
|
||||||
var zb = new Buffer(i);
|
var zb = new Buffer(i);
|
||||||
zb.fill(0);
|
zb.fill(0);
|
||||||
if(i == str.length) return zb;
|
if (i == str.length) return zb;
|
||||||
answer = answer.toBuffer();
|
answer = answer.toBuffer();
|
||||||
return Buffer.concat([zb, answer], i+answer.length);
|
return Buffer.concat([zb, answer], i + answer.length);
|
||||||
} else {
|
} else {
|
||||||
return answer.toBuffer();
|
return answer.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
169
lib/Block.js
169
lib/Block.js
|
@ -1,24 +1,23 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
var util = imports.util || require('../util');
|
var util = imports.util || require('../util');
|
||||||
var Debug1 = imports.Debug1 || function() {};
|
var Debug1 = imports.Debug1 || function() {};
|
||||||
var Script = imports.Script || require('./Script');
|
var Script = imports.Script || require('./Script');
|
||||||
var Bignum = imports.Bignum || require('bignum');
|
var Bignum = imports.Bignum || require('bignum');
|
||||||
var Binary = imports.Binary || require('binary');
|
var Binary = imports.Binary || require('binary');
|
||||||
var Step = imports.Step || require('step');
|
var Step = imports.Step || require('step');
|
||||||
var buffertools = imports.buffertools || require('buffertools');
|
var buffertools = imports.buffertools || require('buffertools');
|
||||||
var Transaction = imports.Transaction || require('./Transaction');
|
var Transaction = imports.Transaction || require('./Transaction');
|
||||||
var TransactionIn = Transaction.In;
|
var TransactionIn = Transaction.In;
|
||||||
var TransactionOut = Transaction.Out;
|
var TransactionOut = Transaction.Out;
|
||||||
var COINBASE_OP = Transaction.COINBASE_OP;
|
var COINBASE_OP = Transaction.COINBASE_OP;
|
||||||
var VerificationError = imports.VerificationError || require('../util/error').VerificationError;
|
var VerificationError = imports.VerificationError || require('../util/error').VerificationError;
|
||||||
var BlockRules = {
|
var BlockRules = {
|
||||||
maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future
|
maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future
|
||||||
largestHash: Bignum(2).pow(256)
|
largestHash: Bignum(2).pow(256)
|
||||||
};
|
};
|
||||||
|
|
||||||
function Block(data)
|
function Block(data) {
|
||||||
{
|
|
||||||
if ("object" !== typeof data) {
|
if ("object" !== typeof data) {
|
||||||
data = {};
|
data = {};
|
||||||
}
|
}
|
||||||
|
@ -39,12 +38,18 @@ function Block(data)
|
||||||
Block.prototype.getHeader = function getHeader() {
|
Block.prototype.getHeader = function getHeader() {
|
||||||
var buf = new Buffer(80);
|
var buf = new Buffer(80);
|
||||||
var ofs = 0;
|
var ofs = 0;
|
||||||
buf.writeUInt32LE(this.version, ofs); ofs += 4;
|
buf.writeUInt32LE(this.version, ofs);
|
||||||
this.prev_hash.copy(buf, ofs); ofs += 32;
|
ofs += 4;
|
||||||
this.merkle_root.copy(buf, ofs); ofs += 32;
|
this.prev_hash.copy(buf, ofs);
|
||||||
buf.writeUInt32LE(this.timestamp, ofs); ofs += 4;
|
ofs += 32;
|
||||||
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
|
this.merkle_root.copy(buf, ofs);
|
||||||
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
|
ofs += 32;
|
||||||
|
buf.writeUInt32LE(this.timestamp, ofs);
|
||||||
|
ofs += 4;
|
||||||
|
buf.writeUInt32LE(this.bits, ofs);
|
||||||
|
ofs += 4;
|
||||||
|
buf.writeUInt32LE(this.nonce, ofs);
|
||||||
|
ofs += 4;
|
||||||
return buf;
|
return buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -102,12 +107,12 @@ Block.prototype.checkProofOfWork = function checkProofOfWork() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amount of work that went into this block.
|
* Returns the amount of work that went into this block.
|
||||||
*
|
*
|
||||||
* Work is defined as the average number of tries required to meet this
|
* Work is defined as the average number of tries required to meet this
|
||||||
* block's difficulty target. For example a target that is greater than 5%
|
* block's difficulty target. For example a target that is greater than 5%
|
||||||
* of all possible hashes would mean that 20 "work" is required to meet it.
|
* of all possible hashes would mean that 20 "work" is required to meet it.
|
||||||
*/
|
*/
|
||||||
Block.prototype.getWork = function getWork() {
|
Block.prototype.getWork = function getWork() {
|
||||||
var target = util.decodeDiffBits(this.bits, true);
|
var target = util.decodeDiffBits(this.bits, true);
|
||||||
return BlockRules.largestHash.div(target.add(1));
|
return BlockRules.largestHash.div(target.add(1));
|
||||||
|
@ -131,7 +136,7 @@ Block.prototype.checkTransactions = function checkTransactions(txs) {
|
||||||
}
|
}
|
||||||
for (var i = 1; i < txs.length; i++) {
|
for (var i = 1; i < txs.length; i++) {
|
||||||
if (txs[i].isCoinBase()) {
|
if (txs[i].isCoinBase()) {
|
||||||
throw new VerificationError('Tx index '+i+' must not be coinbase');
|
throw new VerificationError('Tx index ' + i + ' must not be coinbase');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,11 +144,11 @@ Block.prototype.checkTransactions = function checkTransactions(txs) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build merkle tree.
|
* Build merkle tree.
|
||||||
*
|
*
|
||||||
* Ported from Java. Original code: BitcoinJ by Mike Hearn
|
* Ported from Java. Original code: BitcoinJ by Mike Hearn
|
||||||
* Copyright (c) 2011 Google Inc.
|
* Copyright (c) 2011 Google Inc.
|
||||||
*/
|
*/
|
||||||
Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
||||||
// The merkle hash is based on a tree of hashes calculated from the transactions:
|
// The merkle hash is based on a tree of hashes calculated from the transactions:
|
||||||
//
|
//
|
||||||
|
@ -165,7 +170,7 @@ Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start by adding all the hashes of the transactions as leaves of the tree.
|
// Start by adding all the hashes of the transactions as leaves of the tree.
|
||||||
var tree = txs.map(function (tx) {
|
var tree = txs.map(function(tx) {
|
||||||
return tx instanceof Transaction ? tx.getHash() : tx;
|
return tx instanceof Transaction ? tx.getHash() : tx;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -177,7 +182,7 @@ Block.prototype.getMerkleTree = function getMerkleTree(txs) {
|
||||||
var i2 = Math.min(i + 1, size - 1);
|
var i2 = Math.min(i + 1, size - 1);
|
||||||
var a = tree[j + i];
|
var a = tree[j + i];
|
||||||
var b = tree[j + i2];
|
var b = tree[j + i2];
|
||||||
tree.push(util.twoSha256(Buffer.concat([a,b])));
|
tree.push(util.twoSha256(Buffer.concat([a, b])));
|
||||||
}
|
}
|
||||||
j += size;
|
j += size;
|
||||||
}
|
}
|
||||||
|
@ -229,24 +234,23 @@ Block.prototype.getBlockValue = function getBlockValue() {
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.toString = function toString() {
|
Block.prototype.toString = function toString() {
|
||||||
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
|
return "<Block " + util.formatHashAlt(this.hash) + " height=" + this.height + ">";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Block.prototype.createCoinbaseTx =
|
Block.prototype.createCoinbaseTx =
|
||||||
function createCoinbaseTx(beneficiary)
|
function createCoinbaseTx(beneficiary) {
|
||||||
{
|
var tx = new Transaction();
|
||||||
var tx = new Transaction();
|
tx.ins.push(new TransactionIn({
|
||||||
tx.ins.push(new TransactionIn({
|
s: util.EMPTY_BUFFER,
|
||||||
s: util.EMPTY_BUFFER,
|
q: 0xffffffff,
|
||||||
q: 0xffffffff,
|
o: COINBASE_OP
|
||||||
o: COINBASE_OP
|
}));
|
||||||
}));
|
tx.outs.push(new TransactionOut({
|
||||||
tx.outs.push(new TransactionOut({
|
v: util.bigIntToValue(this.getBlockValue()),
|
||||||
v: util.bigIntToValue(this.getBlockValue()),
|
s: Script.createPubKeyOut(beneficiary).getBuffer()
|
||||||
s: Script.createPubKeyOut(beneficiary).getBuffer()
|
}));
|
||||||
}));
|
return tx;
|
||||||
return tx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Block.prototype.solve = function solve(miner, callback) {
|
Block.prototype.solve = function solve(miner, callback) {
|
||||||
|
@ -256,45 +260,44 @@ Block.prototype.solve = function solve(miner, callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an object with the same field names as jgarzik's getblock patch.
|
* Returns an object with the same field names as jgarzik's getblock patch.
|
||||||
*/
|
*/
|
||||||
Block.prototype.getStandardizedObject =
|
Block.prototype.getStandardizedObject =
|
||||||
function getStandardizedObject(txs)
|
function getStandardizedObject(txs) {
|
||||||
{
|
var block = {
|
||||||
var block = {
|
hash: util.formatHashFull(this.getHash()),
|
||||||
hash: util.formatHashFull(this.getHash()),
|
version: this.version,
|
||||||
version: this.version,
|
prev_block: util.formatHashFull(this.prev_hash),
|
||||||
prev_block: util.formatHashFull(this.prev_hash),
|
mrkl_root: util.formatHashFull(this.merkle_root),
|
||||||
mrkl_root: util.formatHashFull(this.merkle_root),
|
time: this.timestamp,
|
||||||
time: this.timestamp,
|
bits: this.bits,
|
||||||
bits: this.bits,
|
nonce: this.nonce,
|
||||||
nonce: this.nonce,
|
height: this.height
|
||||||
height: this.height
|
};
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
if (txs) {
|
if (txs) {
|
||||||
var mrkl_tree = this.getMerkleTree(txs).map(function (buffer) {
|
var mrkl_tree = this.getMerkleTree(txs).map(function(buffer) {
|
||||||
return util.formatHashFull(buffer);
|
return util.formatHashFull(buffer);
|
||||||
});
|
});
|
||||||
block.mrkl_root = mrkl_tree[mrkl_tree.length - 1];
|
block.mrkl_root = mrkl_tree[mrkl_tree.length - 1];
|
||||||
|
|
||||||
block.n_tx = txs.length;
|
block.n_tx = txs.length;
|
||||||
var totalSize = 80; // Block header
|
var totalSize = 80; // Block header
|
||||||
totalSize += util.getVarIntSize(txs.length); // txn_count
|
totalSize += util.getVarIntSize(txs.length); // txn_count
|
||||||
txs = txs.map(function (tx) {
|
txs = txs.map(function(tx) {
|
||||||
tx = tx.getStandardizedObject();
|
tx = tx.getStandardizedObject();
|
||||||
totalSize += tx.size;
|
totalSize += tx.size;
|
||||||
return tx;
|
return tx;
|
||||||
});
|
});
|
||||||
block.size = totalSize;
|
block.size = totalSize;
|
||||||
block.tx = txs;
|
block.tx = txs;
|
||||||
|
|
||||||
block.mrkl_tree = mrkl_tree;
|
block.mrkl_tree = mrkl_tree;
|
||||||
} else {
|
} else {
|
||||||
block.size = this.size;
|
block.size = this.size;
|
||||||
}
|
}
|
||||||
return block;
|
return block;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = require('soop')(Block);
|
module.exports = require('soop')(Block);
|
||||||
|
|
25
lib/Bloom.js
25
lib/Bloom.js
|
@ -1,4 +1,4 @@
|
||||||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||||
var MAX_HASH_FUNCS = 50;
|
var MAX_HASH_FUNCS = 50;
|
||||||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
||||||
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
||||||
|
@ -47,13 +47,16 @@ Bloom.prototype.hash = function(hashNum, data) {
|
||||||
var k1 = 0;
|
var k1 = 0;
|
||||||
|
|
||||||
switch (data.length & 3) {
|
switch (data.length & 3) {
|
||||||
case 3: k1 ^= tail[2] << 16;
|
case 3:
|
||||||
case 2: k1 ^= tail[1] << 8;
|
k1 ^= tail[2] << 16;
|
||||||
case 1: k1 ^= tail[0];
|
case 2:
|
||||||
k1 *= c1;
|
k1 ^= tail[1] << 8;
|
||||||
k1 = ROTL32(k1, 15);
|
case 1:
|
||||||
k1 *= c2;
|
k1 ^= tail[0];
|
||||||
h1 ^= k1;
|
k1 *= c1;
|
||||||
|
k1 = ROTL32(k1, 15);
|
||||||
|
k1 *= c2;
|
||||||
|
h1 ^= k1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
|
@ -90,7 +93,7 @@ Bloom.prototype.sizeOk = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
function toInt(v) {
|
function toInt(v) {
|
||||||
return ~~v;
|
return~~ v;
|
||||||
}
|
}
|
||||||
|
|
||||||
function min(a, b) {
|
function min(a, b) {
|
||||||
|
@ -101,10 +104,10 @@ function min(a, b) {
|
||||||
|
|
||||||
Bloom.prototype.init = function(elements, FPRate) {
|
Bloom.prototype.init = function(elements, FPRate) {
|
||||||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
|
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
|
||||||
MAX_BLOOM_FILTER_SIZE * 8) / 8;
|
MAX_BLOOM_FILTER_SIZE * 8) / 8;
|
||||||
this.data[filterSize] = 0;
|
this.data[filterSize] = 0;
|
||||||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
|
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
|
||||||
MAX_HASH_FUNCS);
|
MAX_HASH_FUNCS);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
var log = imports.log || require('../util/log');
|
var log = imports.log || require('../util/log');
|
||||||
|
|
||||||
var MAX_RECEIVE_BUFFER = 10000000;
|
var MAX_RECEIVE_BUFFER = 10000000;
|
||||||
var PROTOCOL_VERSION = 70000;
|
var PROTOCOL_VERSION = 70000;
|
||||||
|
|
||||||
var Put = imports.Put || require('bufferput');
|
var Put = imports.Put || require('bufferput');
|
||||||
var Buffers = imports.Buffers || require('buffers');
|
var Buffers = imports.Buffers || require('buffers');
|
||||||
require('../patches/Buffers.monkey').patch(Buffers);
|
require('../patches/Buffers.monkey').patch(Buffers);
|
||||||
|
|
||||||
var bitcoreDefaults = imports.config || require('../config');
|
var bitcoreDefaults = imports.config || require('../config');
|
||||||
var networks = imports.networks || require('../networks');
|
var networks = imports.networks || require('../networks');
|
||||||
var Block = imports.Block || require('./Block');
|
var Block = imports.Block || require('./Block');
|
||||||
var Transaction = imports.Transaction || require('./Transaction');
|
var Transaction = imports.Transaction || require('./Transaction');
|
||||||
var util = imports.util || require('../util');
|
var util = imports.util || require('../util');
|
||||||
var Parser = imports.Parser || require('../util/BinaryParser');
|
var Parser = imports.Parser || require('../util/BinaryParser');
|
||||||
var buffertools = imports.buffertools || require('buffertools');
|
var buffertools = imports.buffertools || require('buffertools');
|
||||||
var doubleSha256 = imports.doubleSha256 || util.twoSha256;
|
var doubleSha256 = imports.doubleSha256 || util.twoSha256;
|
||||||
var SecureRandom = imports.SecureRandom || require('./SecureRandom');
|
var SecureRandom = imports.SecureRandom || require('./SecureRandom');
|
||||||
var nonce = SecureRandom.getPseudoRandomBuffer(8);
|
var nonce = SecureRandom.getPseudoRandomBuffer(8);
|
||||||
|
|
||||||
var BIP0031_VERSION = 60000;
|
var BIP0031_VERSION = 60000;
|
||||||
|
|
||||||
function Connection(socket, peer, opts) {
|
function Connection(socket, peer, opts) {
|
||||||
Connection.super(this, arguments);
|
Connection.super(this, arguments);
|
||||||
|
|
||||||
this.config = opts || bitcoreDefaults;
|
this.config = opts || bitcoreDefaults;
|
||||||
|
|
||||||
this.network = networks[this.config.network] || networks.livenet;
|
this.network = networks[this.config.network] || networks.livenet;
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
this.peer = peer;
|
this.peer = peer;
|
||||||
|
@ -70,22 +70,22 @@ Connection.prototype.open = function(callback) {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.setupHandlers = function () {
|
Connection.prototype.setupHandlers = function() {
|
||||||
this.socket.addListener('connect', this.handleConnect.bind(this));
|
this.socket.addListener('connect', this.handleConnect.bind(this));
|
||||||
this.socket.addListener('error', this.handleError.bind(this));
|
this.socket.addListener('error', this.handleError.bind(this));
|
||||||
this.socket.addListener('end', this.handleDisconnect.bind(this));
|
this.socket.addListener('end', this.handleDisconnect.bind(this));
|
||||||
this.socket.addListener('data', (function (data) {
|
this.socket.addListener('data', (function(data) {
|
||||||
var dumpLen = 35;
|
var dumpLen = 35;
|
||||||
log.debug('['+this.peer+'] '+
|
log.debug('[' + this.peer + '] ' +
|
||||||
'Recieved '+data.length+' bytes of data:');
|
'Recieved ' + data.length + ' bytes of data:');
|
||||||
log.debug('... '+ buffertools.toHex(data.slice(0, dumpLen > data.length ?
|
log.debug('... ' + buffertools.toHex(data.slice(0, dumpLen > data.length ?
|
||||||
data.length : dumpLen)) +
|
data.length : dumpLen)) +
|
||||||
(data.length > dumpLen ? '...' : ''));
|
(data.length > dumpLen ? '...' : ''));
|
||||||
}).bind(this));
|
}).bind(this));
|
||||||
this.socket.addListener('data', this.handleData.bind(this));
|
this.socket.addListener('data', this.handleData.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.handleConnect = function () {
|
Connection.prototype.handleConnect = function() {
|
||||||
if (!this.inbound) {
|
if (!this.inbound) {
|
||||||
this.sendVersion();
|
this.sendVersion();
|
||||||
}
|
}
|
||||||
|
@ -98,11 +98,11 @@ Connection.prototype.handleConnect = function () {
|
||||||
|
|
||||||
Connection.prototype.handleError = function(err) {
|
Connection.prototype.handleError = function(err) {
|
||||||
if (err.errno == 110 || err.errno == 'ETIMEDOUT') {
|
if (err.errno == 110 || err.errno == 'ETIMEDOUT') {
|
||||||
log.info('connection timed out for '+this.peer);
|
log.info('connection timed out for ' + this.peer);
|
||||||
} else if (err.errno == 111 || err.errno == 'ECONNREFUSED') {
|
} else if (err.errno == 111 || err.errno == 'ECONNREFUSED') {
|
||||||
log.info('connection refused for '+this.peer);
|
log.info('connection refused for ' + this.peer);
|
||||||
} else {
|
} else {
|
||||||
log.warn('connection with '+this.peer+' '+err.toString());
|
log.warn('connection with ' + this.peer + ' ' + err.toString());
|
||||||
}
|
}
|
||||||
this.emit('error', {
|
this.emit('error', {
|
||||||
conn: this,
|
conn: this,
|
||||||
|
@ -112,7 +112,7 @@ Connection.prototype.handleError = function(err) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.handleDisconnect = function () {
|
Connection.prototype.handleDisconnect = function() {
|
||||||
this.emit('disconnect', {
|
this.emit('disconnect', {
|
||||||
conn: this,
|
conn: this,
|
||||||
socket: this.socket,
|
socket: this.socket,
|
||||||
|
@ -128,48 +128,48 @@ Connection.prototype.handleMessage = function(message) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (message.command) {
|
switch (message.command) {
|
||||||
case 'version':
|
case 'version':
|
||||||
// Did we connect to ourself?
|
// Did we connect to ourself?
|
||||||
if (buffertools.compare(nonce, message.nonce) === 0) {
|
if (buffertools.compare(nonce, message.nonce) === 0) {
|
||||||
this.socket.end();
|
this.socket.end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.inbound) {
|
if (this.inbound) {
|
||||||
this.sendVersion();
|
this.sendVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.version >= 209) {
|
if (message.version >= 209) {
|
||||||
this.sendMessage('verack', new Buffer([]));
|
this.sendMessage('verack', new Buffer([]));
|
||||||
}
|
}
|
||||||
this.sendVer = Math.min(message.version, PROTOCOL_VERSION);
|
this.sendVer = Math.min(message.version, PROTOCOL_VERSION);
|
||||||
if (message.version < 209) {
|
if (message.version < 209) {
|
||||||
|
this.recvVer = Math.min(message.version, PROTOCOL_VERSION);
|
||||||
|
} else {
|
||||||
|
// We won't start expecting a checksum until after we've received
|
||||||
|
// the 'verack' message.
|
||||||
|
this.once('verack', (function() {
|
||||||
|
this.recvVer = message.version;
|
||||||
|
}).bind(this));
|
||||||
|
}
|
||||||
|
this.bestHeight = message.start_height;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'verack':
|
||||||
this.recvVer = Math.min(message.version, PROTOCOL_VERSION);
|
this.recvVer = Math.min(message.version, PROTOCOL_VERSION);
|
||||||
} else {
|
this.active = true;
|
||||||
// We won't start expecting a checksum until after we've received
|
break;
|
||||||
// the 'verack' message.
|
|
||||||
this.once('verack', (function () {
|
|
||||||
this.recvVer = message.version;
|
|
||||||
}).bind(this));
|
|
||||||
}
|
|
||||||
this.bestHeight = message.start_height;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'verack':
|
case 'ping':
|
||||||
this.recvVer = Math.min(message.version, PROTOCOL_VERSION);
|
if ('object' === typeof message.nonce) {
|
||||||
this.active = true;
|
this.sendPong(message.nonce);
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
case 'ping':
|
|
||||||
if ('object' === typeof message.nonce) {
|
|
||||||
this.sendPong(message.nonce);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.err('Error while handling "'+message.command+'" message from ' +
|
log.err('Error while handling "' + message.command + '" message from ' +
|
||||||
this.peer + ':\n' +
|
this.peer + ':\n' +
|
||||||
(e.stack ? e.stack : e.toString()));
|
(e.stack ? e.stack : e.toString()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.emit(message.command, {
|
this.emit(message.command, {
|
||||||
|
@ -180,17 +180,17 @@ Connection.prototype.handleMessage = function(message) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendPong = function (nonce) {
|
Connection.prototype.sendPong = function(nonce) {
|
||||||
this.sendMessage('pong', nonce);
|
this.sendMessage('pong', nonce);
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendVersion = function () {
|
Connection.prototype.sendVersion = function() {
|
||||||
var subversion = '/BitcoinX:0.1/';
|
var subversion = '/BitcoinX:0.1/';
|
||||||
|
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
put.word32le(PROTOCOL_VERSION); // version
|
put.word32le(PROTOCOL_VERSION); // version
|
||||||
put.word64le(1); // services
|
put.word64le(1); // services
|
||||||
put.word64le(Math.round(new Date().getTime()/1000)); // timestamp
|
put.word64le(Math.round(new Date().getTime() / 1000)); // timestamp
|
||||||
put.pad(26); // addr_me
|
put.pad(26); // addr_me
|
||||||
put.pad(26); // addr_you
|
put.pad(26); // addr_you
|
||||||
put.put(nonce);
|
put.put(nonce);
|
||||||
|
@ -201,7 +201,7 @@ Connection.prototype.sendVersion = function () {
|
||||||
this.sendMessage('version', put.buffer());
|
this.sendMessage('version', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) {
|
Connection.prototype.sendGetBlocks = function(starts, stop, wantHeaders) {
|
||||||
// Default value for stop is 0 to get as many blocks as possible (500)
|
// Default value for stop is 0 to get as many blocks as possible (500)
|
||||||
stop = stop || util.NULL_HASH;
|
stop = stop || util.NULL_HASH;
|
||||||
|
|
||||||
|
@ -236,7 +236,7 @@ Connection.prototype.sendGetHeaders = function(starts, stop) {
|
||||||
this.sendGetBlocks(starts, stop, true);
|
this.sendGetBlocks(starts, stop, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendGetData = function (invs) {
|
Connection.prototype.sendGetData = function(invs) {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
put.varint(invs.length);
|
put.varint(invs.length);
|
||||||
for (var i = 0; i < invs.length; i++) {
|
for (var i = 0; i < invs.length; i++) {
|
||||||
|
@ -246,16 +246,16 @@ Connection.prototype.sendGetData = function (invs) {
|
||||||
this.sendMessage('getdata', put.buffer());
|
this.sendMessage('getdata', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendGetAddr = function (invs) {
|
Connection.prototype.sendGetAddr = function(invs) {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
this.sendMessage('getaddr', put.buffer());
|
this.sendMessage('getaddr', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendInv = function(data) {
|
Connection.prototype.sendInv = function(data) {
|
||||||
if(!Array.isArray(data)) data = [data];
|
if (!Array.isArray(data)) data = [data];
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
put.varint(data.length);
|
put.varint(data.length);
|
||||||
data.forEach(function (value) {
|
data.forEach(function(value) {
|
||||||
if (value instanceof Block) {
|
if (value instanceof Block) {
|
||||||
// Block
|
// Block
|
||||||
put.word32le(2); // MSG_BLOCK
|
put.word32le(2); // MSG_BLOCK
|
||||||
|
@ -268,10 +268,10 @@ Connection.prototype.sendInv = function(data) {
|
||||||
this.sendMessage('inv', put.buffer());
|
this.sendMessage('inv', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendHeaders = function (headers) {
|
Connection.prototype.sendHeaders = function(headers) {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
put.varint(headers.length);
|
put.varint(headers.length);
|
||||||
headers.forEach(function (header) {
|
headers.forEach(function(header) {
|
||||||
put.put(header);
|
put.put(header);
|
||||||
|
|
||||||
// Indicate 0 transactions
|
// Indicate 0 transactions
|
||||||
|
@ -280,11 +280,11 @@ Connection.prototype.sendHeaders = function (headers) {
|
||||||
this.sendMessage('headers', put.buffer());
|
this.sendMessage('headers', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendTx = function (tx) {
|
Connection.prototype.sendTx = function(tx) {
|
||||||
this.sendMessage('tx', tx.serialize());
|
this.sendMessage('tx', tx.serialize());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendBlock = function (block, txs) {
|
Connection.prototype.sendBlock = function(block, txs) {
|
||||||
var put = new Put();
|
var put = new Put();
|
||||||
|
|
||||||
// Block header
|
// Block header
|
||||||
|
@ -292,14 +292,14 @@ Connection.prototype.sendBlock = function (block, txs) {
|
||||||
|
|
||||||
// List of transactions
|
// List of transactions
|
||||||
put.varint(txs.length);
|
put.varint(txs.length);
|
||||||
txs.forEach(function (tx) {
|
txs.forEach(function(tx) {
|
||||||
put.put(tx.serialize());
|
put.put(tx.serialize());
|
||||||
});
|
});
|
||||||
|
|
||||||
this.sendMessage('block', put.buffer());
|
this.sendMessage('block', put.buffer());
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.sendMessage = function (command, payload) {
|
Connection.prototype.sendMessage = function(command, payload) {
|
||||||
try {
|
try {
|
||||||
var magic = this.network.magic;
|
var magic = this.network.magic;
|
||||||
var commandBuf = new Buffer(command, 'ascii');
|
var commandBuf = new Buffer(command, 'ascii');
|
||||||
|
@ -312,35 +312,35 @@ Connection.prototype.sendMessage = function (command, payload) {
|
||||||
checksum = new Buffer([]);
|
checksum = new Buffer([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = new Put(); // -- HEADER --
|
var message = new Put(); // -- HEADER --
|
||||||
message.put(magic); // magic bytes
|
message.put(magic); // magic bytes
|
||||||
message.put(commandBuf); // command name
|
message.put(commandBuf); // command name
|
||||||
message.pad(12 - commandBuf.length); // zero-padded
|
message.pad(12 - commandBuf.length); // zero-padded
|
||||||
message.word32le(payload.length); // payload length
|
message.word32le(payload.length); // payload length
|
||||||
message.put(checksum); // checksum
|
message.put(checksum); // checksum
|
||||||
// -- BODY --
|
// -- BODY --
|
||||||
message.put(payload); // payload data
|
message.put(payload); // payload data
|
||||||
|
|
||||||
var buffer = message.buffer();
|
var buffer = message.buffer();
|
||||||
|
|
||||||
log.debug('['+this.peer+'] '+
|
log.debug('[' + this.peer + '] ' +
|
||||||
'Sending message '+command+' ('+payload.length+' bytes)');
|
'Sending message ' + command + ' (' + payload.length + ' bytes)');
|
||||||
|
|
||||||
this.socket.write(buffer);
|
this.socket.write(buffer);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// TODO: We should catch this error one level higher in order to better
|
// TODO: We should catch this error one level higher in order to better
|
||||||
// determine how to react to it. For now though, ignoring it will do.
|
// determine how to react to it. For now though, ignoring it will do.
|
||||||
log.err('Error while sending message to peer '+this.peer+': '+
|
log.err('Error while sending message to peer ' + this.peer + ': ' +
|
||||||
(err.stack ? err.stack : err.toString()));
|
(err.stack ? err.stack : err.toString()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.handleData = function (data) {
|
Connection.prototype.handleData = function(data) {
|
||||||
this.buffers.push(data);
|
this.buffers.push(data);
|
||||||
|
|
||||||
if (this.buffers.length > MAX_RECEIVE_BUFFER) {
|
if (this.buffers.length > MAX_RECEIVE_BUFFER) {
|
||||||
log.err('Peer '+this.peer+' exceeded maxreceivebuffer, disconnecting.'+
|
log.err('Peer ' + this.peer + ' exceeded maxreceivebuffer, disconnecting.' +
|
||||||
(err.stack ? err.stack : err.toString()));
|
(err.stack ? err.stack : err.toString()));
|
||||||
this.socket.destroy();
|
this.socket.destroy();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -348,22 +348,22 @@ Connection.prototype.handleData = function (data) {
|
||||||
this.processData();
|
this.processData();
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.processData = function () {
|
Connection.prototype.processData = function() {
|
||||||
// If there are less than 20 bytes there can't be a message yet.
|
// If there are less than 20 bytes there can't be a message yet.
|
||||||
if (this.buffers.length < 20) return;
|
if (this.buffers.length < 20) return;
|
||||||
|
|
||||||
var magic = this.network.magic;
|
var magic = this.network.magic;
|
||||||
var i = 0;
|
var i = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (this.buffers.get(i ) === magic[0] &&
|
if (this.buffers.get(i) === magic[0] &&
|
||||||
this.buffers.get(i+1) === magic[1] &&
|
this.buffers.get(i + 1) === magic[1] &&
|
||||||
this.buffers.get(i+2) === magic[2] &&
|
this.buffers.get(i + 2) === magic[2] &&
|
||||||
this.buffers.get(i+3) === magic[3]) {
|
this.buffers.get(i + 3) === magic[3]) {
|
||||||
if (i !== 0) {
|
if (i !== 0) {
|
||||||
log.debug('['+this.peer+'] '+
|
log.debug('[' + this.peer + '] ' +
|
||||||
'Received '+i+
|
'Received ' + i +
|
||||||
' bytes of inter-message garbage: ');
|
' bytes of inter-message garbage: ');
|
||||||
log.debug('... '+this.buffers.slice(0,i));
|
log.debug('... ' + this.buffers.slice(0, i));
|
||||||
|
|
||||||
this.buffers.skip(i);
|
this.buffers.skip(i);
|
||||||
}
|
}
|
||||||
|
@ -377,32 +377,33 @@ Connection.prototype.processData = function () {
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
var payloadLen = (this.buffers.get(16) ) +
|
var payloadLen = (this.buffers.get(16)) +
|
||||||
(this.buffers.get(17) << 8) +
|
(this.buffers.get(17) << 8) +
|
||||||
(this.buffers.get(18) << 16) +
|
(this.buffers.get(18) << 16) +
|
||||||
(this.buffers.get(19) << 24);
|
(this.buffers.get(19) << 24);
|
||||||
|
|
||||||
var startPos = (this.recvVer >= 209) ? 24 : 20;
|
var startPos = (this.recvVer >= 209) ? 24 : 20;
|
||||||
var endPos = startPos + payloadLen;
|
var endPos = startPos + payloadLen;
|
||||||
|
|
||||||
if (this.buffers.length < endPos) return;
|
if (this.buffers.length < endPos) return;
|
||||||
|
|
||||||
var command = this.buffers.slice(4, 16).toString('ascii').replace(/\0+$/,'');
|
var command = this.buffers.slice(4, 16).toString('ascii').replace(/\0+$/, '');
|
||||||
var payload = this.buffers.slice(startPos, endPos);
|
var payload = this.buffers.slice(startPos, endPos);
|
||||||
var checksum = (this.recvVer >= 209) ? this.buffers.slice(20, 24) : null;
|
var checksum = (this.recvVer >= 209) ? this.buffers.slice(20, 24) : null;
|
||||||
|
|
||||||
log.debug('['+this.peer+'] ' +
|
log.debug('[' + this.peer + '] ' +
|
||||||
'Received message ' + command +
|
'Received message ' + command +
|
||||||
' (' + payloadLen + ' bytes)');
|
' (' + payloadLen + ' bytes)');
|
||||||
|
|
||||||
if (checksum !== null) {
|
if (checksum !== null) {
|
||||||
var checksumConfirm = doubleSha256(payload).slice(0, 4);
|
var checksumConfirm = doubleSha256(payload).slice(0, 4);
|
||||||
if (buffertools.compare(checksumConfirm, checksum) !== 0) {
|
if (buffertools.compare(checksumConfirm, checksum) !== 0) {
|
||||||
log.err('['+this.peer+'] '+
|
log.err('[' + this.peer + '] ' +
|
||||||
'Checksum failed',
|
'Checksum failed', {
|
||||||
{ cmd: command,
|
cmd: command,
|
||||||
expected: checksumConfirm.toString('hex'),
|
expected: checksumConfirm.toString('hex'),
|
||||||
actual: checksum.toString('hex') });
|
actual: checksum.toString('hex')
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,9 +412,9 @@ Connection.prototype.processData = function () {
|
||||||
try {
|
try {
|
||||||
message = this.parseMessage(command, payload);
|
message = this.parseMessage(command, payload);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.err('Error while parsing message '+command+' from ' +
|
log.err('Error while parsing message ' + command + ' from ' +
|
||||||
this.peer + ':\n' +
|
this.peer + ':\n' +
|
||||||
(e.stack ? e.stack : e.toString()));
|
(e.stack ? e.stack : e.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
|
@ -424,7 +425,7 @@ Connection.prototype.processData = function () {
|
||||||
this.processData();
|
this.processData();
|
||||||
};
|
};
|
||||||
|
|
||||||
Connection.prototype.parseMessage = function (command, payload) {
|
Connection.prototype.parseMessage = function(command, payload) {
|
||||||
var parser = new Parser(payload);
|
var parser = new Parser(payload);
|
||||||
|
|
||||||
var data = {
|
var data = {
|
||||||
|
@ -434,129 +435,130 @@ Connection.prototype.parseMessage = function (command, payload) {
|
||||||
var i;
|
var i;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'version': // https://en.bitcoin.it/wiki/Protocol_specification#version
|
case 'version': // https://en.bitcoin.it/wiki/Protocol_specification#version
|
||||||
data.version = parser.word32le();
|
data.version = parser.word32le();
|
||||||
data.services = parser.word64le();
|
data.services = parser.word64le();
|
||||||
data.timestamp = parser.word64le();
|
data.timestamp = parser.word64le();
|
||||||
data.addr_me = parser.buffer(26);
|
data.addr_me = parser.buffer(26);
|
||||||
data.addr_you = parser.buffer(26);
|
data.addr_you = parser.buffer(26);
|
||||||
data.nonce = parser.buffer(8);
|
|
||||||
data.subversion = parser.varStr();
|
|
||||||
data.start_height = parser.word32le();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'inv':
|
|
||||||
case 'getdata':
|
|
||||||
data.count = parser.varInt();
|
|
||||||
|
|
||||||
data.invs = [];
|
|
||||||
for (i = 0; i < data.count; i++) {
|
|
||||||
data.invs.push({
|
|
||||||
type: parser.word32le(),
|
|
||||||
hash: parser.buffer(32)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'headers':
|
|
||||||
data.count = parser.varInt();
|
|
||||||
|
|
||||||
data.headers = [];
|
|
||||||
for (i = 0; i < data.count; i++) {
|
|
||||||
var header = new Block();
|
|
||||||
header.parse(parser);
|
|
||||||
data.headers.push(header);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'block':
|
|
||||||
var block = new Block();
|
|
||||||
block.parse(parser);
|
|
||||||
|
|
||||||
data.block = block;
|
|
||||||
data.version = block.version;
|
|
||||||
data.prev_hash = block.prev_hash;
|
|
||||||
data.merkle_root = block.merkle_root;
|
|
||||||
data.timestamp = block.timestamp;
|
|
||||||
data.bits = block.bits;
|
|
||||||
data.nonce = block.nonce;
|
|
||||||
|
|
||||||
data.txs = block.txs;
|
|
||||||
|
|
||||||
data.size = payload.length;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'tx':
|
|
||||||
var tx = new Transaction();
|
|
||||||
tx.parse(parser);
|
|
||||||
return {
|
|
||||||
command: command,
|
|
||||||
version: tx.version,
|
|
||||||
lock_time: tx.lock_time,
|
|
||||||
ins: tx.ins,
|
|
||||||
outs: tx.outs,
|
|
||||||
tx: tx,
|
|
||||||
};
|
|
||||||
|
|
||||||
case 'getblocks':
|
|
||||||
case 'getheaders':
|
|
||||||
// parse out the version
|
|
||||||
data.version = parser.word32le();
|
|
||||||
|
|
||||||
// TODO: Limit block locator size?
|
|
||||||
// reference implementation limits to 500 results
|
|
||||||
var startCount = parser.varInt();
|
|
||||||
|
|
||||||
data.starts = [];
|
|
||||||
for (i = 0; i < startCount; i++) {
|
|
||||||
data.starts.push(parser.buffer(32));
|
|
||||||
}
|
|
||||||
data.stop = parser.buffer(32);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'addr':
|
|
||||||
var addrCount = parser.varInt();
|
|
||||||
|
|
||||||
// Enforce a maximum number of addresses per message
|
|
||||||
if (addrCount > 1000) {
|
|
||||||
addrCount = 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.addrs = [];
|
|
||||||
for (i = 0; i < addrCount; i++) {
|
|
||||||
// TODO: Time actually depends on the version of the other peer (>=31402)
|
|
||||||
data.addrs.push({
|
|
||||||
time: parser.word32le(),
|
|
||||||
services: parser.word64le(),
|
|
||||||
ip: parser.buffer(16),
|
|
||||||
port: parser.word16be()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'alert':
|
|
||||||
data.payload = parser.varStr();
|
|
||||||
data.signature = parser.varStr();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'ping':
|
|
||||||
if (this.recvVer > BIP0031_VERSION) {
|
|
||||||
data.nonce = parser.buffer(8);
|
data.nonce = parser.buffer(8);
|
||||||
}
|
data.subversion = parser.varStr();
|
||||||
break;
|
data.start_height = parser.word32le();
|
||||||
|
break;
|
||||||
|
|
||||||
case 'getaddr':
|
case 'inv':
|
||||||
case 'verack':
|
case 'getdata':
|
||||||
case 'reject':
|
data.count = parser.varInt();
|
||||||
// Empty message, nothing to parse
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
data.invs = [];
|
||||||
log.err('Connection.parseMessage(): Command not implemented',
|
for (i = 0; i < data.count; i++) {
|
||||||
{cmd: command});
|
data.invs.push({
|
||||||
|
type: parser.word32le(),
|
||||||
|
hash: parser.buffer(32)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// This tells the calling function not to issue an event
|
case 'headers':
|
||||||
return null;
|
data.count = parser.varInt();
|
||||||
|
|
||||||
|
data.headers = [];
|
||||||
|
for (i = 0; i < data.count; i++) {
|
||||||
|
var header = new Block();
|
||||||
|
header.parse(parser);
|
||||||
|
data.headers.push(header);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'block':
|
||||||
|
var block = new Block();
|
||||||
|
block.parse(parser);
|
||||||
|
|
||||||
|
data.block = block;
|
||||||
|
data.version = block.version;
|
||||||
|
data.prev_hash = block.prev_hash;
|
||||||
|
data.merkle_root = block.merkle_root;
|
||||||
|
data.timestamp = block.timestamp;
|
||||||
|
data.bits = block.bits;
|
||||||
|
data.nonce = block.nonce;
|
||||||
|
|
||||||
|
data.txs = block.txs;
|
||||||
|
|
||||||
|
data.size = payload.length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'tx':
|
||||||
|
var tx = new Transaction();
|
||||||
|
tx.parse(parser);
|
||||||
|
return {
|
||||||
|
command: command,
|
||||||
|
version: tx.version,
|
||||||
|
lock_time: tx.lock_time,
|
||||||
|
ins: tx.ins,
|
||||||
|
outs: tx.outs,
|
||||||
|
tx: tx,
|
||||||
|
};
|
||||||
|
|
||||||
|
case 'getblocks':
|
||||||
|
case 'getheaders':
|
||||||
|
// parse out the version
|
||||||
|
data.version = parser.word32le();
|
||||||
|
|
||||||
|
// TODO: Limit block locator size?
|
||||||
|
// reference implementation limits to 500 results
|
||||||
|
var startCount = parser.varInt();
|
||||||
|
|
||||||
|
data.starts = [];
|
||||||
|
for (i = 0; i < startCount; i++) {
|
||||||
|
data.starts.push(parser.buffer(32));
|
||||||
|
}
|
||||||
|
data.stop = parser.buffer(32);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'addr':
|
||||||
|
var addrCount = parser.varInt();
|
||||||
|
|
||||||
|
// Enforce a maximum number of addresses per message
|
||||||
|
if (addrCount > 1000) {
|
||||||
|
addrCount = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.addrs = [];
|
||||||
|
for (i = 0; i < addrCount; i++) {
|
||||||
|
// TODO: Time actually depends on the version of the other peer (>=31402)
|
||||||
|
data.addrs.push({
|
||||||
|
time: parser.word32le(),
|
||||||
|
services: parser.word64le(),
|
||||||
|
ip: parser.buffer(16),
|
||||||
|
port: parser.word16be()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'alert':
|
||||||
|
data.payload = parser.varStr();
|
||||||
|
data.signature = parser.varStr();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ping':
|
||||||
|
if (this.recvVer > BIP0031_VERSION) {
|
||||||
|
data.nonce = parser.buffer(8);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getaddr':
|
||||||
|
case 'verack':
|
||||||
|
case 'reject':
|
||||||
|
// Empty message, nothing to parse
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.err('Connection.parseMessage(): Command not implemented', {
|
||||||
|
cmd: command
|
||||||
|
});
|
||||||
|
|
||||||
|
// This tells the calling function not to issue an event
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
|
15
lib/Curve.js
15
lib/Curve.js
|
@ -3,11 +3,12 @@ var imports = require('soop');
|
||||||
var bignum = imports.bignum || require('bignum');
|
var bignum = imports.bignum || require('bignum');
|
||||||
var Point = imports.Point || require('./Point');
|
var Point = imports.Point || require('./Point');
|
||||||
|
|
||||||
var n = bignum.fromBuffer(new Buffer("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 'hex'), {size: 32});
|
var n = bignum.fromBuffer(new Buffer("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 'hex'), {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
var Curve = function() {
|
var Curve = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
/* secp256k1 curve */
|
/* secp256k1 curve */
|
||||||
var G;
|
var G;
|
||||||
|
@ -16,8 +17,12 @@ Curve.getG = function() {
|
||||||
// when Point is not loaded yet
|
// when Point is not loaded yet
|
||||||
|
|
||||||
// use cached version if available
|
// use cached version if available
|
||||||
G = G || new Point(bignum.fromBuffer(new Buffer("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 'hex'), {size: 32}),
|
G = G || new Point(bignum.fromBuffer(new Buffer("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 'hex'), {
|
||||||
bignum.fromBuffer(new Buffer("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 'hex'), {size: 32}));
|
size: 32
|
||||||
|
}),
|
||||||
|
bignum.fromBuffer(new Buffer("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 'hex'), {
|
||||||
|
size: 32
|
||||||
|
}));
|
||||||
return G;
|
return G;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
|
exports.intFromCompact = function(c) {
|
||||||
exports.intFromCompact = function(c)
|
|
||||||
{
|
|
||||||
var bytes = ((c >>> 24) & 0xff) >>> 0;
|
var bytes = ((c >>> 24) & 0xff) >>> 0;
|
||||||
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
|
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,19 +12,23 @@ var Key = require('./Key'),
|
||||||
*
|
*
|
||||||
* @example examples/ElectrumMPK.js
|
* @example examples/ElectrumMPK.js
|
||||||
*/
|
*/
|
||||||
function Electrum (master_public_key) {
|
function Electrum(master_public_key) {
|
||||||
this.mpk = new Buffer(master_public_key, 'hex');
|
this.mpk = new Buffer(master_public_key, 'hex');
|
||||||
}
|
}
|
||||||
|
|
||||||
Electrum.prototype.getSequence = function (for_change, n) {
|
Electrum.prototype.getSequence = function(for_change, n) {
|
||||||
var mode = for_change ? 1 : 0;
|
var mode = for_change ? 1 : 0;
|
||||||
var buf = Buffer.concat([ new Buffer(n + ':' + mode + ':', 'utf8'), this.mpk ]);
|
var buf = Buffer.concat([new Buffer(n + ':' + mode + ':', 'utf8'), this.mpk]);
|
||||||
return bignum.fromBuffer(twoSha256(buf));
|
return bignum.fromBuffer(twoSha256(buf));
|
||||||
};
|
};
|
||||||
|
|
||||||
Electrum.prototype.generatePubKey = function (n, for_change) {
|
Electrum.prototype.generatePubKey = function(n, for_change) {
|
||||||
var x = bignum.fromBuffer(this.mpk.slice(0, 32), { size: 32 });
|
var x = bignum.fromBuffer(this.mpk.slice(0, 32), {
|
||||||
var y = bignum.fromBuffer(this.mpk.slice(32, 64), { size: 32 });
|
size: 32
|
||||||
|
});
|
||||||
|
var y = bignum.fromBuffer(this.mpk.slice(32, 64), {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var mpk_pt = new Point(x, y);
|
var mpk_pt = new Point(x, y);
|
||||||
|
|
||||||
var sequence = this.getSequence(for_change, n);
|
var sequence = this.getSequence(for_change, n);
|
||||||
|
@ -37,8 +41,12 @@ Electrum.prototype.generatePubKey = function (n, for_change) {
|
||||||
|
|
||||||
pt = Point.add(mpk_pt, sequence_pt);
|
pt = Point.add(mpk_pt, sequence_pt);
|
||||||
|
|
||||||
var xbuf = pt.x.toBuffer({ size: 32 });
|
var xbuf = pt.x.toBuffer({
|
||||||
var ybuf = pt.y.toBuffer({ size: 32 });
|
size: 32
|
||||||
|
});
|
||||||
|
var ybuf = pt.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var prefix = new Buffer([0x04]);
|
var prefix = new Buffer([0x04]);
|
||||||
|
|
||||||
var key = new Key();
|
var key = new Key();
|
||||||
|
@ -48,7 +56,7 @@ Electrum.prototype.generatePubKey = function (n, for_change) {
|
||||||
return key.public;
|
return key.public;
|
||||||
};
|
};
|
||||||
|
|
||||||
Electrum.prototype.generateChangePubKey = function (sequence) {
|
Electrum.prototype.generateChangePubKey = function(sequence) {
|
||||||
return this.generatePubKey(sequence, true);
|
return this.generatePubKey(sequence, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,7 @@ var HierarchicalKey = function(bytes) {
|
||||||
if (typeof bytes == 'undefined' || bytes == 'mainnet' || bytes == 'livenet') {
|
if (typeof bytes == 'undefined' || bytes == 'mainnet' || bytes == 'livenet') {
|
||||||
bytes = 'livenet';
|
bytes = 'livenet';
|
||||||
this.version = networks['livenet'].hkeyPrivateVersion;
|
this.version = networks['livenet'].hkeyPrivateVersion;
|
||||||
}
|
} else if (bytes == 'testnet') {
|
||||||
else if (bytes == 'testnet') {
|
|
||||||
this.version = networks['testnet'].hkeyPrivateVersion;
|
this.version = networks['testnet'].hkeyPrivateVersion;
|
||||||
}
|
}
|
||||||
if (bytes == 'livenet' || bytes == 'testnet') {
|
if (bytes == 'livenet' || bytes == 'testnet') {
|
||||||
|
@ -35,12 +34,12 @@ var HierarchicalKey = function(bytes) {
|
||||||
this.buildExtendedPrivateKey();
|
this.buildExtendedPrivateKey();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// decode base58
|
// decode base58
|
||||||
if (typeof bytes === 'string') {
|
if (typeof bytes === 'string') {
|
||||||
var decoded = base58.decode(bytes);
|
var decoded = base58.decode(bytes);
|
||||||
if (decoded.length != 82)
|
if (decoded.length != 82)
|
||||||
throw new Error('Not enough data, expected 82 and received '+decoded.length);
|
throw new Error('Not enough data, expected 82 and received ' + decoded.length);
|
||||||
var checksum = decoded.slice(78, 82);
|
var checksum = decoded.slice(78, 82);
|
||||||
bytes = decoded.slice(0, 78);
|
bytes = decoded.slice(0, 78);
|
||||||
|
|
||||||
|
@ -51,7 +50,7 @@ var HierarchicalKey = function(bytes) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes !== undefined && bytes !== null)
|
if (bytes !== undefined && bytes !== null)
|
||||||
this.initFromBytes(bytes);
|
this.initFromBytes(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,9 +60,9 @@ HierarchicalKey.seed = function(bytes, network) {
|
||||||
|
|
||||||
if (!Buffer.isBuffer(bytes))
|
if (!Buffer.isBuffer(bytes))
|
||||||
bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex
|
bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex
|
||||||
if (bytes.length < 128/8)
|
if (bytes.length < 128 / 8)
|
||||||
return false; //need more entropy
|
return false; //need more entropy
|
||||||
if (bytes.length > 512/8)
|
if (bytes.length > 512 / 8)
|
||||||
return false;
|
return false;
|
||||||
var hash = coinUtil.sha512hmac(bytes, new Buffer('Bitcoin seed'));
|
var hash = coinUtil.sha512hmac(bytes, new Buffer('Bitcoin seed'));
|
||||||
|
|
||||||
|
@ -87,23 +86,23 @@ HierarchicalKey.seed = function(bytes, network) {
|
||||||
|
|
||||||
HierarchicalKey.prototype.initFromBytes = function(bytes) {
|
HierarchicalKey.prototype.initFromBytes = function(bytes) {
|
||||||
// Both pub and private extended keys are 78 bytes
|
// Both pub and private extended keys are 78 bytes
|
||||||
if(bytes.length != 78) throw new Error('not enough data');
|
if (bytes.length != 78) throw new Error('not enough data');
|
||||||
|
|
||||||
this.version = u32(bytes.slice(0, 4));
|
this.version = u32(bytes.slice(0, 4));
|
||||||
this.depth = u8(bytes.slice(4, 5));
|
this.depth = u8(bytes.slice(4, 5));
|
||||||
this.parentFingerprint = bytes.slice(5, 9);
|
this.parentFingerprint = bytes.slice(5, 9);
|
||||||
this.childIndex = u32(bytes.slice(9, 13));
|
this.childIndex = u32(bytes.slice(9, 13));
|
||||||
this.chainCode = bytes.slice(13, 45);
|
this.chainCode = bytes.slice(13, 45);
|
||||||
|
|
||||||
var keyBytes = bytes.slice(45, 78);
|
var keyBytes = bytes.slice(45, 78);
|
||||||
|
|
||||||
var isPrivate =
|
var isPrivate =
|
||||||
(this.version == networks['livenet'].hkeyPrivateVersion ||
|
(this.version == networks['livenet'].hkeyPrivateVersion ||
|
||||||
this.version == networks['testnet'].hkeyPrivateVersion );
|
this.version == networks['testnet'].hkeyPrivateVersion);
|
||||||
|
|
||||||
var isPublic =
|
var isPublic =
|
||||||
(this.version == networks['livenet'].hkeyPublicVersion ||
|
(this.version == networks['livenet'].hkeyPublicVersion ||
|
||||||
this.version == networks['testnet'].hkeyPublicVersion );
|
this.version == networks['testnet'].hkeyPublicVersion);
|
||||||
|
|
||||||
if (isPrivate && keyBytes[0] == 0) {
|
if (isPrivate && keyBytes[0] == 0) {
|
||||||
this.eckey = new Key();
|
this.eckey = new Key();
|
||||||
|
@ -129,17 +128,17 @@ HierarchicalKey.prototype.buildExtendedPublicKey = function() {
|
||||||
this.extendedPublicKey = new Buffer([]);
|
this.extendedPublicKey = new Buffer([]);
|
||||||
|
|
||||||
var v = null;
|
var v = null;
|
||||||
switch(this.version) {
|
switch (this.version) {
|
||||||
case networks['livenet'].hkeyPublicVersion:
|
case networks['livenet'].hkeyPublicVersion:
|
||||||
case networks['livenet'].hkeyPrivateVersion:
|
case networks['livenet'].hkeyPrivateVersion:
|
||||||
v = networks['livenet'].hkeyPublicVersion;
|
v = networks['livenet'].hkeyPublicVersion;
|
||||||
break;
|
break;
|
||||||
case networks['testnet'].hkeyPublicVersion:
|
case networks['testnet'].hkeyPublicVersion:
|
||||||
case networks['testnet'].hkeyPrivateVersion:
|
case networks['testnet'].hkeyPrivateVersion:
|
||||||
v = networks['testnet'].hkeyPublicVersion;
|
v = networks['testnet'].hkeyPublicVersion;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error('Unknown version');
|
throw new Error('Unknown version');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
|
@ -220,12 +219,12 @@ HierarchicalKey.prototype.derive = function(path) {
|
||||||
for (var i in e) {
|
for (var i in e) {
|
||||||
var c = e[i];
|
var c = e[i];
|
||||||
|
|
||||||
if (i == 0 ) {
|
if (i == 0) {
|
||||||
if (c != 'm') throw new Error('invalid path');
|
if (c != 'm') throw new Error('invalid path');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var usePrivate = (c.length > 1) && (c[c.length-1] == '\'');
|
var usePrivate = (c.length > 1) && (c[c.length - 1] == '\'');
|
||||||
var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
|
var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff;
|
||||||
|
|
||||||
if (usePrivate)
|
if (usePrivate)
|
||||||
|
@ -241,15 +240,15 @@ HierarchicalKey.prototype.deriveChild = function(i) {
|
||||||
var ib = [];
|
var ib = [];
|
||||||
ib.push((i >> 24) & 0xff);
|
ib.push((i >> 24) & 0xff);
|
||||||
ib.push((i >> 16) & 0xff);
|
ib.push((i >> 16) & 0xff);
|
||||||
ib.push((i >> 8) & 0xff);
|
ib.push((i >> 8) & 0xff);
|
||||||
ib.push(i & 0xff);
|
ib.push(i & 0xff);
|
||||||
ib = new Buffer(ib);
|
ib = new Buffer(ib);
|
||||||
|
|
||||||
var usePrivate = (i & 0x80000000) != 0;
|
var usePrivate = (i & 0x80000000) != 0;
|
||||||
|
|
||||||
var isPrivate =
|
var isPrivate =
|
||||||
(this.version == networks['livenet'].hkeyPrivateVersion ||
|
(this.version == networks['livenet'].hkeyPrivateVersion ||
|
||||||
this.version == networks['testnet'].hkeyPrivateVersion );
|
this.version == networks['testnet'].hkeyPrivateVersion);
|
||||||
|
|
||||||
if (usePrivate && (!this.hasPrivateKey || !isPrivate))
|
if (usePrivate && (!this.hasPrivateKey || !isPrivate))
|
||||||
throw new Error('Cannot do private key derivation without private key');
|
throw new Error('Cannot do private key derivation without private key');
|
||||||
|
@ -265,18 +264,24 @@ HierarchicalKey.prototype.deriveChild = function(i) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash = coinUtil.sha512hmac(data, this.chainCode);
|
var hash = coinUtil.sha512hmac(data, this.chainCode);
|
||||||
var il = bignum.fromBuffer(hash.slice(0, 32), {size: 32});
|
var il = bignum.fromBuffer(hash.slice(0, 32), {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var ir = hash.slice(32, 64);
|
var ir = hash.slice(32, 64);
|
||||||
|
|
||||||
// ki = IL + kpar (mod n).
|
// ki = IL + kpar (mod n).
|
||||||
var priv = bignum.fromBuffer(this.eckey.private, {size: 32});
|
var priv = bignum.fromBuffer(this.eckey.private, {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var k = il.add(priv).mod(secp256k1_n);
|
var k = il.add(priv).mod(secp256k1_n);
|
||||||
|
|
||||||
ret = new HierarchicalKey(null);
|
ret = new HierarchicalKey(null);
|
||||||
ret.chainCode = ir;
|
ret.chainCode = ir;
|
||||||
|
|
||||||
ret.eckey = new Key();
|
ret.eckey = new Key();
|
||||||
ret.eckey.private = k.toBuffer({size: 32});
|
ret.eckey.private = k.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
ret.eckey.regenerateSync();
|
ret.eckey.regenerateSync();
|
||||||
ret.hasPrivateKey = true;
|
ret.hasPrivateKey = true;
|
||||||
|
|
||||||
|
@ -302,14 +307,14 @@ HierarchicalKey.prototype.deriveChild = function(i) {
|
||||||
ret.chainCode = new Buffer(ir);
|
ret.chainCode = new Buffer(ir);
|
||||||
|
|
||||||
var eckey = new Key();
|
var eckey = new Key();
|
||||||
eckey.public = newpub;
|
eckey.public = newpub;
|
||||||
eckey.compressed = true;
|
eckey.compressed = true;
|
||||||
ret.eckey = eckey;
|
ret.eckey = eckey;
|
||||||
ret.hasPrivateKey = false;
|
ret.hasPrivateKey = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.childIndex = i;
|
ret.childIndex = i;
|
||||||
ret.parentFingerprint = this.pubKeyHash.slice(0,4);
|
ret.parentFingerprint = this.pubKeyHash.slice(0, 4);
|
||||||
ret.version = this.version;
|
ret.version = this.version;
|
||||||
ret.depth = this.depth + 1;
|
ret.depth = this.depth + 1;
|
||||||
|
|
||||||
|
@ -334,9 +339,20 @@ function uint(f, size) {
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
function u8(f) {return uint(f,1);}
|
function u8(f) {
|
||||||
function u16(f) {return uint(f,2);}
|
return uint(f, 1);
|
||||||
function u32(f) {return uint(f,4);}
|
}
|
||||||
function u64(f) {return uint(f,8);}
|
|
||||||
|
function u16(f) {
|
||||||
|
return uint(f, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function u32(f) {
|
||||||
|
return uint(f, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
function u64(f) {
|
||||||
|
return uint(f, 8);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = require('soop')(HierarchicalKey);
|
module.exports = require('soop')(HierarchicalKey);
|
||||||
|
|
|
@ -3,8 +3,7 @@ var imports = require('soop').imports();
|
||||||
var coinUtil = imports.coinUtil || require('../util');
|
var coinUtil = imports.coinUtil || require('../util');
|
||||||
var Key = imports.Key || require('./Key');
|
var Key = imports.Key || require('./Key');
|
||||||
|
|
||||||
var Message = function() {
|
var Message = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
Message.sign = function(str, key) {
|
Message.sign = function(str, key) {
|
||||||
var hash = Message.magicHash(str);
|
var hash = Message.magicHash(str);
|
||||||
|
|
238
lib/Opcode.js
238
lib/Opcode.js
|
@ -1,156 +1,156 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
function Opcode(num) {
|
function Opcode(num) {
|
||||||
this.code = num;
|
this.code = num;
|
||||||
};
|
};
|
||||||
|
|
||||||
Opcode.prototype.toString = function () {
|
Opcode.prototype.toString = function() {
|
||||||
return Opcode.reverseMap[this.code];
|
return Opcode.reverseMap[this.code];
|
||||||
};
|
};
|
||||||
|
|
||||||
Opcode.map = {
|
Opcode.map = {
|
||||||
// push value
|
// push value
|
||||||
OP_FALSE : 0,
|
OP_FALSE: 0,
|
||||||
OP_0 : 0,
|
OP_0: 0,
|
||||||
OP_PUSHDATA1 : 76,
|
OP_PUSHDATA1: 76,
|
||||||
OP_PUSHDATA2 : 77,
|
OP_PUSHDATA2: 77,
|
||||||
OP_PUSHDATA4 : 78,
|
OP_PUSHDATA4: 78,
|
||||||
OP_1NEGATE : 79,
|
OP_1NEGATE: 79,
|
||||||
OP_RESERVED : 80,
|
OP_RESERVED: 80,
|
||||||
OP_TRUE : 81,
|
OP_TRUE: 81,
|
||||||
OP_1 : 81,
|
OP_1: 81,
|
||||||
OP_2 : 82,
|
OP_2: 82,
|
||||||
OP_3 : 83,
|
OP_3: 83,
|
||||||
OP_4 : 84,
|
OP_4: 84,
|
||||||
OP_5 : 85,
|
OP_5: 85,
|
||||||
OP_6 : 86,
|
OP_6: 86,
|
||||||
OP_7 : 87,
|
OP_7: 87,
|
||||||
OP_8 : 88,
|
OP_8: 88,
|
||||||
OP_9 : 89,
|
OP_9: 89,
|
||||||
OP_10 : 90,
|
OP_10: 90,
|
||||||
OP_11 : 91,
|
OP_11: 91,
|
||||||
OP_12 : 92,
|
OP_12: 92,
|
||||||
OP_13 : 93,
|
OP_13: 93,
|
||||||
OP_14 : 94,
|
OP_14: 94,
|
||||||
OP_15 : 95,
|
OP_15: 95,
|
||||||
OP_16 : 96,
|
OP_16: 96,
|
||||||
|
|
||||||
// control
|
// control
|
||||||
OP_NOP : 97,
|
OP_NOP: 97,
|
||||||
OP_VER : 98,
|
OP_VER: 98,
|
||||||
OP_IF : 99,
|
OP_IF: 99,
|
||||||
OP_NOTIF : 100,
|
OP_NOTIF: 100,
|
||||||
OP_VERIF : 101,
|
OP_VERIF: 101,
|
||||||
OP_VERNOTIF : 102,
|
OP_VERNOTIF: 102,
|
||||||
OP_ELSE : 103,
|
OP_ELSE: 103,
|
||||||
OP_ENDIF : 104,
|
OP_ENDIF: 104,
|
||||||
OP_VERIFY : 105,
|
OP_VERIFY: 105,
|
||||||
OP_RETURN : 106,
|
OP_RETURN: 106,
|
||||||
|
|
||||||
// stack ops
|
// stack ops
|
||||||
OP_TOALTSTACK : 107,
|
OP_TOALTSTACK: 107,
|
||||||
OP_FROMALTSTACK : 108,
|
OP_FROMALTSTACK: 108,
|
||||||
OP_2DROP : 109,
|
OP_2DROP: 109,
|
||||||
OP_2DUP : 110,
|
OP_2DUP: 110,
|
||||||
OP_3DUP : 111,
|
OP_3DUP: 111,
|
||||||
OP_2OVER : 112,
|
OP_2OVER: 112,
|
||||||
OP_2ROT : 113,
|
OP_2ROT: 113,
|
||||||
OP_2SWAP : 114,
|
OP_2SWAP: 114,
|
||||||
OP_IFDUP : 115,
|
OP_IFDUP: 115,
|
||||||
OP_DEPTH : 116,
|
OP_DEPTH: 116,
|
||||||
OP_DROP : 117,
|
OP_DROP: 117,
|
||||||
OP_DUP : 118,
|
OP_DUP: 118,
|
||||||
OP_NIP : 119,
|
OP_NIP: 119,
|
||||||
OP_OVER : 120,
|
OP_OVER: 120,
|
||||||
OP_PICK : 121,
|
OP_PICK: 121,
|
||||||
OP_ROLL : 122,
|
OP_ROLL: 122,
|
||||||
OP_ROT : 123,
|
OP_ROT: 123,
|
||||||
OP_SWAP : 124,
|
OP_SWAP: 124,
|
||||||
OP_TUCK : 125,
|
OP_TUCK: 125,
|
||||||
|
|
||||||
// splice ops
|
// splice ops
|
||||||
OP_CAT : 126,
|
OP_CAT: 126,
|
||||||
OP_SUBSTR : 127,
|
OP_SUBSTR: 127,
|
||||||
OP_LEFT : 128,
|
OP_LEFT: 128,
|
||||||
OP_RIGHT : 129,
|
OP_RIGHT: 129,
|
||||||
OP_SIZE : 130,
|
OP_SIZE: 130,
|
||||||
|
|
||||||
// bit logic
|
// bit logic
|
||||||
OP_INVERT : 131,
|
OP_INVERT: 131,
|
||||||
OP_AND : 132,
|
OP_AND: 132,
|
||||||
OP_OR : 133,
|
OP_OR: 133,
|
||||||
OP_XOR : 134,
|
OP_XOR: 134,
|
||||||
OP_EQUAL : 135,
|
OP_EQUAL: 135,
|
||||||
OP_EQUALVERIFY : 136,
|
OP_EQUALVERIFY: 136,
|
||||||
OP_RESERVED1 : 137,
|
OP_RESERVED1: 137,
|
||||||
OP_RESERVED2 : 138,
|
OP_RESERVED2: 138,
|
||||||
|
|
||||||
// numeric
|
// numeric
|
||||||
OP_1ADD : 139,
|
OP_1ADD: 139,
|
||||||
OP_1SUB : 140,
|
OP_1SUB: 140,
|
||||||
OP_2MUL : 141,
|
OP_2MUL: 141,
|
||||||
OP_2DIV : 142,
|
OP_2DIV: 142,
|
||||||
OP_NEGATE : 143,
|
OP_NEGATE: 143,
|
||||||
OP_ABS : 144,
|
OP_ABS: 144,
|
||||||
OP_NOT : 145,
|
OP_NOT: 145,
|
||||||
OP_0NOTEQUAL : 146,
|
OP_0NOTEQUAL: 146,
|
||||||
|
|
||||||
OP_ADD : 147,
|
OP_ADD: 147,
|
||||||
OP_SUB : 148,
|
OP_SUB: 148,
|
||||||
OP_MUL : 149,
|
OP_MUL: 149,
|
||||||
OP_DIV : 150,
|
OP_DIV: 150,
|
||||||
OP_MOD : 151,
|
OP_MOD: 151,
|
||||||
OP_LSHIFT : 152,
|
OP_LSHIFT: 152,
|
||||||
OP_RSHIFT : 153,
|
OP_RSHIFT: 153,
|
||||||
|
|
||||||
OP_BOOLAND : 154,
|
OP_BOOLAND: 154,
|
||||||
OP_BOOLOR : 155,
|
OP_BOOLOR: 155,
|
||||||
OP_NUMEQUAL : 156,
|
OP_NUMEQUAL: 156,
|
||||||
OP_NUMEQUALVERIFY : 157,
|
OP_NUMEQUALVERIFY: 157,
|
||||||
OP_NUMNOTEQUAL : 158,
|
OP_NUMNOTEQUAL: 158,
|
||||||
OP_LESSTHAN : 159,
|
OP_LESSTHAN: 159,
|
||||||
OP_GREATERTHAN : 160,
|
OP_GREATERTHAN: 160,
|
||||||
OP_LESSTHANOREQUAL : 161,
|
OP_LESSTHANOREQUAL: 161,
|
||||||
OP_GREATERTHANOREQUAL : 162,
|
OP_GREATERTHANOREQUAL: 162,
|
||||||
OP_MIN : 163,
|
OP_MIN: 163,
|
||||||
OP_MAX : 164,
|
OP_MAX: 164,
|
||||||
|
|
||||||
OP_WITHIN : 165,
|
OP_WITHIN: 165,
|
||||||
|
|
||||||
// crypto
|
// crypto
|
||||||
OP_RIPEMD160 : 166,
|
OP_RIPEMD160: 166,
|
||||||
OP_SHA1 : 167,
|
OP_SHA1: 167,
|
||||||
OP_SHA256 : 168,
|
OP_SHA256: 168,
|
||||||
OP_HASH160 : 169,
|
OP_HASH160: 169,
|
||||||
OP_HASH256 : 170,
|
OP_HASH256: 170,
|
||||||
OP_CODESEPARATOR : 171,
|
OP_CODESEPARATOR: 171,
|
||||||
OP_CHECKSIG : 172,
|
OP_CHECKSIG: 172,
|
||||||
OP_CHECKSIGVERIFY : 173,
|
OP_CHECKSIGVERIFY: 173,
|
||||||
OP_CHECKMULTISIG : 174,
|
OP_CHECKMULTISIG: 174,
|
||||||
OP_CHECKMULTISIGVERIFY : 175,
|
OP_CHECKMULTISIGVERIFY: 175,
|
||||||
|
|
||||||
// expansion
|
// expansion
|
||||||
OP_NOP1 : 176,
|
OP_NOP1: 176,
|
||||||
OP_NOP2 : 177,
|
OP_NOP2: 177,
|
||||||
OP_NOP3 : 178,
|
OP_NOP3: 178,
|
||||||
OP_NOP4 : 179,
|
OP_NOP4: 179,
|
||||||
OP_NOP5 : 180,
|
OP_NOP5: 180,
|
||||||
OP_NOP6 : 181,
|
OP_NOP6: 181,
|
||||||
OP_NOP7 : 182,
|
OP_NOP7: 182,
|
||||||
OP_NOP8 : 183,
|
OP_NOP8: 183,
|
||||||
OP_NOP9 : 184,
|
OP_NOP9: 184,
|
||||||
OP_NOP10 : 185,
|
OP_NOP10: 185,
|
||||||
|
|
||||||
// template matching params
|
// template matching params
|
||||||
OP_PUBKEYHASH : 253,
|
OP_PUBKEYHASH: 253,
|
||||||
OP_PUBKEY : 254,
|
OP_PUBKEY: 254,
|
||||||
OP_INVALIDOPCODE : 255
|
OP_INVALIDOPCODE: 255
|
||||||
};
|
};
|
||||||
|
|
||||||
Opcode.reverseMap = [];
|
Opcode.reverseMap = [];
|
||||||
|
|
||||||
for (var k in Opcode.map) {
|
for (var k in Opcode.map) {
|
||||||
if(Opcode.map.hasOwnProperty(k)) {
|
if (Opcode.map.hasOwnProperty(k)) {
|
||||||
Opcode.reverseMap[Opcode.map[k]] = k.substr(3);
|
Opcode.reverseMap[Opcode.map[k]] = k.substr(3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
lib/Peer.js
18
lib/Peer.js
|
@ -1,7 +1,7 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
var Net = imports.Net || require('net');
|
var Net = imports.Net || require('net');
|
||||||
var Binary = imports.Binary || require('binary');
|
var Binary = imports.Binary || require('binary');
|
||||||
var buffertools = imports.buffertools || require('buffertools');
|
var buffertools = imports.buffertools || require('buffertools');
|
||||||
|
|
||||||
function Peer(host, port, services) {
|
function Peer(host, port, services) {
|
||||||
|
@ -24,29 +24,29 @@ function Peer(host, port, services) {
|
||||||
this.port = +port || 8333;
|
this.port = +port || 8333;
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Could not instantiate peer, invalid parameter type: ' +
|
throw new Error('Could not instantiate peer, invalid parameter type: ' +
|
||||||
typeof host);
|
typeof host);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.services = (services) ? services : null;
|
this.services = (services) ? services : null;
|
||||||
this.lastSeen = 0;
|
this.lastSeen = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
|
Peer.IPV6_IPV4_PADDING = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255]);
|
||||||
|
|
||||||
Peer.prototype.createConnection = function () {
|
Peer.prototype.createConnection = function() {
|
||||||
this.connection = Net.createConnection(this.port, this.host);
|
this.connection = Net.createConnection(this.port, this.host);
|
||||||
return this.connection;
|
return this.connection;
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype.getHostAsBuffer = function () {
|
Peer.prototype.getHostAsBuffer = function() {
|
||||||
return new Buffer(this.host.split('.'));
|
return new Buffer(this.host.split('.'));
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype.toString = function () {
|
Peer.prototype.toString = function() {
|
||||||
return this.host + ":" + this.port;
|
return this.host + ":" + this.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
Peer.prototype.toBuffer = function () {
|
Peer.prototype.toBuffer = function() {
|
||||||
var put = Binary.put();
|
var put = Binary.put();
|
||||||
put.word32le(this.lastSeen);
|
put.word32le(this.lastSeen);
|
||||||
put.word64le(this.services);
|
put.word64le(this.services);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var log = imports.log || require('../util/log');
|
var log = imports.log || require('../util/log');
|
||||||
var bitcoreDefaults = imports.config || require('../config');
|
var bitcoreDefaults = imports.config || require('../config');
|
||||||
var Connection = imports.Connection || require ('./Connection');
|
var Connection = imports.Connection || require('./Connection');
|
||||||
var Peer = imports.Peer || require('./Peer');
|
var Peer = imports.Peer || require('./Peer');
|
||||||
|
|
||||||
GetAdjustedTime = imports.GetAdjustedTime || function () {
|
GetAdjustedTime = imports.GetAdjustedTime || function() {
|
||||||
// TODO: Implement actual adjustment
|
// TODO: Implement actual adjustment
|
||||||
return Math.floor(new Date().getTime() / 1000);
|
return Math.floor(new Date().getTime() / 1000);
|
||||||
};
|
};
|
||||||
|
@ -42,36 +42,37 @@ PeerManager.Connection = Connection;
|
||||||
|
|
||||||
PeerManager.prototype.start = function() {
|
PeerManager.prototype.start = function() {
|
||||||
this.active = true;
|
this.active = true;
|
||||||
if(!this.timer) {
|
if (!this.timer) {
|
||||||
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
|
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.stop = function() {
|
PeerManager.prototype.stop = function() {
|
||||||
this.active = false;
|
this.active = false;
|
||||||
if(this.timer) {
|
if (this.timer) {
|
||||||
clearInterval(this.timer);
|
clearInterval(this.timer);
|
||||||
this.timer = null;
|
this.timer = null;
|
||||||
}
|
}
|
||||||
for(var i=0; i<this.connections.length; i++) {
|
for (var i = 0; i < this.connections.length; i++) {
|
||||||
this.connections[i].socket.end();
|
this.connections[i].socket.end();
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.addPeer = function(peer, port) {
|
PeerManager.prototype.addPeer = function(peer, port) {
|
||||||
if(peer instanceof Peer) {
|
if (peer instanceof Peer) {
|
||||||
this.peers.push(peer);
|
this.peers.push(peer);
|
||||||
} else if ("string" == typeof peer) {
|
} else if ("string" == typeof peer) {
|
||||||
this.addPeer(new Peer(peer, port));
|
this.addPeer(new Peer(peer, port));
|
||||||
} else {
|
} else {
|
||||||
log.err('Node.addPeer(): Invalid value provided for peer',
|
log.err('Node.addPeer(): Invalid value provided for peer', {
|
||||||
{val: peer});
|
val: peer
|
||||||
|
});
|
||||||
throw 'Node.addPeer(): Invalid value provided for peer.';
|
throw 'Node.addPeer(): Invalid value provided for peer.';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.removePeer = function(peer) {
|
PeerManager.prototype.removePeer = function(peer) {
|
||||||
var index = this.peers.indexOf(peer);
|
var index = this.peers.indexOf(peer);
|
||||||
var exists = !!~index;
|
var exists = !!~index;
|
||||||
if (exists) this.peers.splice(index, 1);
|
if (exists) this.peers.splice(index, 1);
|
||||||
return exists;
|
return exists;
|
||||||
|
@ -79,7 +80,7 @@ PeerManager.prototype.removePeer = function(peer) {
|
||||||
|
|
||||||
PeerManager.prototype.checkStatus = function checkStatus() {
|
PeerManager.prototype.checkStatus = function checkStatus() {
|
||||||
// Make sure we are connected to all forcePeers
|
// Make sure we are connected to all forcePeers
|
||||||
if(this.peers.length) {
|
if (this.peers.length) {
|
||||||
var peerIndex = {};
|
var peerIndex = {};
|
||||||
this.peers.forEach(function(peer) {
|
this.peers.forEach(function(peer) {
|
||||||
peerIndex[peer.toString()] = peer;
|
peerIndex[peer.toString()] = peer;
|
||||||
|
@ -88,7 +89,7 @@ PeerManager.prototype.checkStatus = function checkStatus() {
|
||||||
// Ignore the ones we're already connected to
|
// Ignore the ones we're already connected to
|
||||||
this.connections.forEach(function(conn) {
|
this.connections.forEach(function(conn) {
|
||||||
var peerName = conn.peer.toString();
|
var peerName = conn.peer.toString();
|
||||||
if("undefined" !== peerIndex[peerName]) {
|
if ("undefined" !== peerIndex[peerName]) {
|
||||||
delete peerIndex[peerName];
|
delete peerIndex[peerName];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -111,7 +112,7 @@ PeerManager.prototype.connectTo = function(peer) {
|
||||||
try {
|
try {
|
||||||
return this.addConnection(peer.createConnection(), peer);
|
return this.addConnection(peer.createConnection(), peer);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.err('creating connection',e);
|
log.err('creating connection', e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -139,15 +140,15 @@ PeerManager.prototype.handleVersion = function(e) {
|
||||||
// TODO: Advertise our address (if listening)
|
// TODO: Advertise our address (if listening)
|
||||||
}
|
}
|
||||||
// Get recent addresses
|
// Get recent addresses
|
||||||
if(this.peerDiscovery &&
|
if (this.peerDiscovery &&
|
||||||
(e.message.version >= 31402 || this.peers.length < 1000)) {
|
(e.message.version >= 31402 || this.peers.length < 1000)) {
|
||||||
e.conn.sendGetAddr();
|
e.conn.sendGetAddr();
|
||||||
e.conn.getaddr = true;
|
e.conn.getaddr = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.handleReady = function (e) {
|
PeerManager.prototype.handleReady = function(e) {
|
||||||
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port);
|
log.info('connected to ' + e.conn.peer.host + ':' + e.conn.peer.port);
|
||||||
this.emit('connect', {
|
this.emit('connect', {
|
||||||
pm: this,
|
pm: this,
|
||||||
conn: e.conn,
|
conn: e.conn,
|
||||||
|
@ -155,17 +156,17 @@ PeerManager.prototype.handleReady = function (e) {
|
||||||
peer: e.peer
|
peer: e.peer
|
||||||
});
|
});
|
||||||
|
|
||||||
if(this.isConnected == false) {
|
if (this.isConnected == false) {
|
||||||
this.emit('netConnected', e);
|
this.emit('netConnected', e);
|
||||||
this.isConnected = true;
|
this.isConnected = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.handleAddr = function (e) {
|
PeerManager.prototype.handleAddr = function(e) {
|
||||||
if(!this.peerDiscovery) return;
|
if (!this.peerDiscovery) return;
|
||||||
|
|
||||||
var now = GetAdjustedTime();
|
var now = GetAdjustedTime();
|
||||||
e.message.addrs.forEach(function (addr) {
|
e.message.addrs.forEach(function(addr) {
|
||||||
try {
|
try {
|
||||||
// In case of an invalid time, assume "5 days ago"
|
// In case of an invalid time, assume "5 days ago"
|
||||||
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) {
|
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) {
|
||||||
|
@ -178,11 +179,11 @@ PeerManager.prototype.handleAddr = function (e) {
|
||||||
this.peers.push(peer);
|
this.peers.push(peer);
|
||||||
|
|
||||||
// TODO: Handle addr relay
|
// TODO: Handle addr relay
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
log.warn("Invalid addr received: "+e.message);
|
log.warn("Invalid addr received: " + e.message);
|
||||||
}
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
if (e.message.addrs.length < 1000 ) {
|
if (e.message.addrs.length < 1000) {
|
||||||
e.conn.getaddr = false;
|
e.conn.getaddr = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -192,14 +193,14 @@ PeerManager.prototype.handleGetAddr = function(e) {
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.handleError = function(e) {
|
PeerManager.prototype.handleError = function(e) {
|
||||||
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
|
log.err('unkown error with peer ' + e.peer + ' (disconnecting): ' + e.err);
|
||||||
this.handleDisconnect.apply(this, [].slice.call(arguments));
|
this.handleDisconnect.apply(this, [].slice.call(arguments));
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.handleDisconnect = function(e) {
|
PeerManager.prototype.handleDisconnect = function(e) {
|
||||||
log.info('disconnected from peer ' + e.peer);
|
log.info('disconnected from peer ' + e.peer);
|
||||||
var i = this.connections.indexOf(e.conn);
|
var i = this.connections.indexOf(e.conn);
|
||||||
if(i != -1) this.connections.splice(i, 1);
|
if (i != -1) this.connections.splice(i, 1);
|
||||||
|
|
||||||
this.removePeer(e.peer);
|
this.removePeer(e.peer);
|
||||||
if (this.pool.length) {
|
if (this.pool.length) {
|
||||||
|
@ -207,19 +208,19 @@ PeerManager.prototype.handleDisconnect = function(e) {
|
||||||
this.addPeer(this.pool.pop());
|
this.addPeer(this.pool.pop());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.connections.length) {
|
if (!this.connections.length) {
|
||||||
this.emit('netDisconnected');
|
this.emit('netDisconnected');
|
||||||
this.isConnected = false;
|
this.isConnected = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.getActiveConnection = function () {
|
PeerManager.prototype.getActiveConnection = function() {
|
||||||
var activeConnections = this.connections.filter(function (conn) {
|
var activeConnections = this.connections.filter(function(conn) {
|
||||||
return conn.active;
|
return conn.active;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (activeConnections.length) {
|
if (activeConnections.length) {
|
||||||
var randomIndex = Math.floor(Math.random()*activeConnections.length);
|
var randomIndex = Math.floor(Math.random() * activeConnections.length);
|
||||||
var candidate = activeConnections[randomIndex];
|
var candidate = activeConnections[randomIndex];
|
||||||
if (candidate.socket.writable) {
|
if (candidate.socket.writable) {
|
||||||
return candidate;
|
return candidate;
|
||||||
|
@ -237,16 +238,16 @@ PeerManager.prototype.getActiveConnection = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.getActiveConnections = function () {
|
PeerManager.prototype.getActiveConnections = function() {
|
||||||
return this.connections.slice(0);
|
return this.connections.slice(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
PeerManager.prototype.discover = function(options, callback) {
|
PeerManager.prototype.discover = function(options, callback) {
|
||||||
var self = this;
|
var self = this;
|
||||||
var async = imports.async || require('async');
|
var async = imports.async || require('async');
|
||||||
var dns = imports.dns || require('dns');
|
var dns = imports.dns || require('dns');
|
||||||
var networks = imports.networks || require('../networks');
|
var networks = imports.networks || require('../networks');
|
||||||
var seeds = networks[self.config.network].dnsSeeds;
|
var seeds = networks[self.config.network].dnsSeeds;
|
||||||
|
|
||||||
self.limit = options.limit || 12;
|
self.limit = options.limit || 12;
|
||||||
|
|
||||||
|
@ -264,16 +265,16 @@ PeerManager.prototype.discover = function(options, callback) {
|
||||||
return done(null, []);
|
return done(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('resolving dns seed '+ seed);
|
log.info('resolving dns seed ' + seed);
|
||||||
|
|
||||||
dns.resolve(seed, function(err, peers) {
|
dns.resolve(seed, function(err, peers) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log.err('failed to resolve dns seed '+ seed, err);
|
log.err('failed to resolve dns seed ' + seed, err);
|
||||||
self.seeds.failed.push(seed);
|
self.seeds.failed.push(seed);
|
||||||
return done(null, []);
|
return done(null, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('found '+ peers.length + ' peers from ' + seed);
|
log.info('found ' + peers.length + ' peers from ' + seed);
|
||||||
self.seeds.resolved.push(seed);
|
self.seeds.resolved.push(seed);
|
||||||
|
|
||||||
// transform that list into a list of Peer instances
|
// transform that list into a list of Peer instances
|
||||||
|
|
16
lib/Point.js
16
lib/Point.js
|
@ -28,15 +28,23 @@ Point.multiply = function(p1, x) {
|
||||||
//convert the public key of a Key into a Point
|
//convert the public key of a Key into a Point
|
||||||
Point.fromUncompressedPubKey = function(pubkey) {
|
Point.fromUncompressedPubKey = function(pubkey) {
|
||||||
var point = new Point();
|
var point = new Point();
|
||||||
point.x = bignum.fromBuffer(pubkey.slice(1, 33), {size: 32});
|
point.x = bignum.fromBuffer(pubkey.slice(1, 33), {
|
||||||
point.y = bignum.fromBuffer(pubkey.slice(33, 65), {size: 32});
|
size: 32
|
||||||
|
});
|
||||||
|
point.y = bignum.fromBuffer(pubkey.slice(33, 65), {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
return point;
|
return point;
|
||||||
};
|
};
|
||||||
|
|
||||||
//convert the Point into the Key containing a compressed public key
|
//convert the Point into the Key containing a compressed public key
|
||||||
Point.prototype.toUncompressedPubKey = function() {
|
Point.prototype.toUncompressedPubKey = function() {
|
||||||
var xbuf = this.x.toBuffer({size: 32});
|
var xbuf = this.x.toBuffer({
|
||||||
var ybuf = this.y.toBuffer({size: 32});
|
size: 32
|
||||||
|
});
|
||||||
|
var ybuf = this.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var prefix = new Buffer([0x04]);
|
var prefix = new Buffer([0x04]);
|
||||||
var pubkey = Buffer.concat([prefix, xbuf, ybuf]);
|
var pubkey = Buffer.concat([prefix, xbuf, ybuf]);
|
||||||
return pubkey;
|
return pubkey;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
var parent = imports.parent || require('../util/VersionedData');
|
var parent = imports.parent || require('../util/VersionedData');
|
||||||
var networks= imports.networks || require('../networks');
|
var networks = imports.networks || require('../networks');
|
||||||
|
|
||||||
//compressed is true if public key is compressed; false otherwise
|
//compressed is true if public key is compressed; false otherwise
|
||||||
function PrivateKey(version, buf, compressed) {
|
function PrivateKey(version, buf, compressed) {
|
||||||
|
@ -16,7 +16,7 @@ parent.applyEncodingsTo(PrivateKey);
|
||||||
PrivateKey.prototype.validate = function() {
|
PrivateKey.prototype.validate = function() {
|
||||||
this.doAsBinary(function() {
|
this.doAsBinary(function() {
|
||||||
PrivateKey.super(this, 'validate', arguments);
|
PrivateKey.super(this, 'validate', arguments);
|
||||||
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
|
if (this.data.length < 32 || (this.data.length > 1 + 32 && !this.compressed()) || (this.data.length == 1 + 32 + 1 && this.data[1 + 32 + 1 - 1] != 1) || this.data.length > 1 + 32 + 1)
|
||||||
throw new Error('invalid data length');
|
throw new Error('invalid data length');
|
||||||
});
|
});
|
||||||
if (typeof this.network() === 'undefined') throw new Error('invalid network');
|
if (typeof this.network() === 'undefined') throw new Error('invalid network');
|
||||||
|
@ -25,38 +25,39 @@ PrivateKey.prototype.validate = function() {
|
||||||
// get or set the payload data (as a Buffer object)
|
// get or set the payload data (as a Buffer object)
|
||||||
// overloaded from VersionedData
|
// overloaded from VersionedData
|
||||||
PrivateKey.prototype.payload = function(data) {
|
PrivateKey.prototype.payload = function(data) {
|
||||||
if(data) {
|
if (data) {
|
||||||
this.doAsBinary(function() {data.copy(this.data,1);});
|
this.doAsBinary(function() {
|
||||||
|
data.copy(this.data, 1);
|
||||||
|
});
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
var buf=this.as('binary');
|
var buf = this.as('binary');
|
||||||
if (buf.length==1+32+1)
|
if (buf.length == 1 + 32 + 1)
|
||||||
return buf.slice(1,1+32);
|
return buf.slice(1, 1 + 32);
|
||||||
else if (buf.length==1+32)
|
else if (buf.length == 1 + 32)
|
||||||
return buf.slice(1);
|
return buf.slice(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// get or set whether the corresponding public key is compressed
|
// get or set whether the corresponding public key is compressed
|
||||||
PrivateKey.prototype.compressed = function(compressed) {
|
PrivateKey.prototype.compressed = function(compressed) {
|
||||||
if (compressed !== undefined) {
|
if (compressed !== undefined) {
|
||||||
this.doAsBinary(function(){
|
this.doAsBinary(function() {
|
||||||
var len=1+32+1;
|
var len = 1 + 32 + 1;
|
||||||
if (compressed) {
|
if (compressed) {
|
||||||
var data=new Buffer(len);
|
var data = new Buffer(len);
|
||||||
this.data.copy(data);
|
this.data.copy(data);
|
||||||
this.data=data;
|
this.data = data;
|
||||||
this.data[len-1]=1;
|
this.data[len - 1] = 1;
|
||||||
} else {
|
} else {
|
||||||
this.data=this.data.slice(0,len-1);
|
this.data = this.data.slice(0, len - 1);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
else {
|
var len = 1 + 32 + 1;
|
||||||
var len=1+32+1;
|
var data = this.as('binary');
|
||||||
var data=this.as('binary');
|
if (data.length == len && data[len - 1] == 1)
|
||||||
if (data.length==len && data[len-1]==1)
|
|
||||||
return true;
|
return true;
|
||||||
else if (data.length==len-1)
|
else if (data.length == len - 1)
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
throw new Error('invalid private key');
|
throw new Error('invalid private key');
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
// Copyright 2013 BitPay, Inc.
|
// Copyright 2013 BitPay, Inc.
|
||||||
//
|
//
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var http = imports.http || require('http');
|
var http = imports.http || require('http');
|
||||||
var https = imports.https || require('https');
|
var https = imports.https || require('https');
|
||||||
var log = imports.log || require('../util/log');
|
var log = imports.log || require('../util/log');
|
||||||
|
|
||||||
function RpcClient(opts) {
|
function RpcClient(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
|
@ -15,9 +15,9 @@ function RpcClient(opts) {
|
||||||
this.pass = opts.pass || 'pass';
|
this.pass = opts.pass || 'pass';
|
||||||
this.protocol = (opts.protocol == 'http') ? http : https;
|
this.protocol = (opts.protocol == 'http') ? http : https;
|
||||||
this.batchedCalls = null;
|
this.batchedCalls = null;
|
||||||
this.disableAgent = opts.disableAgent || false;
|
this.disableAgent = opts.disableAgent || false;
|
||||||
}
|
}
|
||||||
|
|
||||||
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
|
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
|
||||||
this.batchedCalls = [];
|
this.batchedCalls = [];
|
||||||
batchCallback();
|
batchCallback();
|
||||||
|
@ -77,7 +77,7 @@ var callspec = {
|
||||||
lockUnspent: '',
|
lockUnspent: '',
|
||||||
move: 'str str float int str',
|
move: 'str str float int str',
|
||||||
sendFrom: 'str str float int str str',
|
sendFrom: 'str str float int str str',
|
||||||
sendMany: 'str str int str', //not sure this is will work
|
sendMany: 'str str int str', //not sure this is will work
|
||||||
sendRawTransaction: '',
|
sendRawTransaction: '',
|
||||||
sendToAddress: 'str float str str',
|
sendToAddress: 'str float str str',
|
||||||
setAccount: '',
|
setAccount: '',
|
||||||
|
@ -102,30 +102,45 @@ function generateRPCMethods(constructor, apiCalls, rpc) {
|
||||||
function createRPCMethod(methodName, argMap) {
|
function createRPCMethod(methodName, argMap) {
|
||||||
return function() {
|
return function() {
|
||||||
var limit = arguments.length - 1;
|
var limit = arguments.length - 1;
|
||||||
if(this.batchedCalls) var limit = arguments.length;
|
if (this.batchedCalls) var limit = arguments.length;
|
||||||
for (var i=0; i<limit; i++) {
|
for (var i = 0; i < limit; i++) {
|
||||||
if(argMap[i]) arguments[i] = argMap[i](arguments[i]);
|
if (argMap[i]) arguments[i] = argMap[i](arguments[i]);
|
||||||
};
|
};
|
||||||
if(this.batchedCalls) {
|
if (this.batchedCalls) {
|
||||||
this.batchedCalls.push({jsonrpc: '2.0', method: methodName, params: slice(arguments)});
|
this.batchedCalls.push({
|
||||||
|
jsonrpc: '2.0',
|
||||||
|
method: methodName,
|
||||||
|
params: slice(arguments)
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
rpc.call(this, {method: methodName, params: slice(arguments, 0, arguments.length - 1)}, arguments[arguments.length - 1]);
|
rpc.call(this, {
|
||||||
|
method: methodName,
|
||||||
|
params: slice(arguments, 0, arguments.length - 1)
|
||||||
|
}, arguments[arguments.length - 1]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var types = {
|
var types = {
|
||||||
str: function(arg) {return arg.toString();},
|
str: function(arg) {
|
||||||
int: function(arg) {return parseFloat(arg);},
|
return arg.toString();
|
||||||
float: function(arg) {return parseFloat(arg);},
|
},
|
||||||
bool: function(arg) {return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');},
|
int: function(arg) {
|
||||||
|
return parseFloat(arg);
|
||||||
|
},
|
||||||
|
float: function(arg) {
|
||||||
|
return parseFloat(arg);
|
||||||
|
},
|
||||||
|
bool: function(arg) {
|
||||||
|
return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
for(var k in apiCalls) {
|
for (var k in apiCalls) {
|
||||||
if (apiCalls.hasOwnProperty(k)) {
|
if (apiCalls.hasOwnProperty(k)) {
|
||||||
var spec = apiCalls[k].split(' ');
|
var spec = apiCalls[k].split(' ');
|
||||||
for (var i = 0; i < spec.length; i++) {
|
for (var i = 0; i < spec.length; i++) {
|
||||||
if(types[spec[i]]) {
|
if (types[spec[i]]) {
|
||||||
spec[i] = types[spec[i]];
|
spec[i] = types[spec[i]];
|
||||||
} else {
|
} else {
|
||||||
spec[i] = types.string;
|
spec[i] = types.string;
|
||||||
|
@ -149,10 +164,10 @@ function rpc(request, callback) {
|
||||||
path: '/',
|
path: '/',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
port: self.port,
|
port: self.port,
|
||||||
agent: self.disableAgent ? false : undefined,
|
agent: self.disableAgent ? false : undefined,
|
||||||
};
|
};
|
||||||
if(self.httpOptions) {
|
if (self.httpOptions) {
|
||||||
for(var k in self.httpOptions) {
|
for (var k in self.httpOptions) {
|
||||||
options[k] = self.httpOptions[k];
|
options[k] = self.httpOptions[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,25 +176,25 @@ function rpc(request, callback) {
|
||||||
|
|
||||||
var buf = '';
|
var buf = '';
|
||||||
res.on('data', function(data) {
|
res.on('data', function(data) {
|
||||||
buf += data;
|
buf += data;
|
||||||
});
|
});
|
||||||
res.on('end', function() {
|
res.on('end', function() {
|
||||||
if(res.statusCode == 401) {
|
if (res.statusCode == 401) {
|
||||||
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized'));
|
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(res.statusCode == 403) {
|
if (res.statusCode == 403) {
|
||||||
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden'));
|
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden'));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(err) {
|
if (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var parsedBuf = JSON.parse(buf);
|
var parsedBuf = JSON.parse(buf);
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
log.err(e.stack);
|
log.err(e.stack);
|
||||||
log.err(buf);
|
log.err(buf);
|
||||||
log.err('HTTP Status code:' + res.statusCode);
|
log.err('HTTP Status code:' + res.statusCode);
|
||||||
|
@ -190,11 +205,11 @@ function rpc(request, callback) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
req.on('error', function(e) {
|
req.on('error', function(e) {
|
||||||
var err = new Error('Could not connect to bitcoin via RPC: '+e.message);
|
var err = new Error('Could not connect to bitcoin via RPC: ' + e.message);
|
||||||
log.err(err);
|
log.err(err);
|
||||||
callback(err);
|
callback(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
req.setHeader('Content-Length', request.length);
|
req.setHeader('Content-Length', request.length);
|
||||||
req.setHeader('Content-Type', 'application/json');
|
req.setHeader('Content-Type', 'application/json');
|
||||||
req.setHeader('Authorization', 'Basic ' + auth);
|
req.setHeader('Authorization', 'Basic ' + auth);
|
||||||
|
@ -205,4 +220,3 @@ function rpc(request, callback) {
|
||||||
generateRPCMethods(RpcClient, callspec, rpc);
|
generateRPCMethods(RpcClient, callspec, rpc);
|
||||||
|
|
||||||
module.exports = require('soop')(RpcClient);
|
module.exports = require('soop')(RpcClient);
|
||||||
|
|
||||||
|
|
24
lib/SIN.js
24
lib/SIN.js
|
@ -1,5 +1,5 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var parent = imports.parent || require('../util/VersionedData');
|
var parent = imports.parent || require('../util/VersionedData');
|
||||||
|
|
||||||
function SIN(type, payload) {
|
function SIN(type, payload) {
|
||||||
if (typeof type != 'number') {
|
if (typeof type != 'number') {
|
||||||
|
@ -8,7 +8,7 @@ function SIN(type, payload) {
|
||||||
};
|
};
|
||||||
this.data = new Buffer(1 + 1 + payload.length);
|
this.data = new Buffer(1 + 1 + payload.length);
|
||||||
this.__proto__ = this.encodings['binary'];
|
this.__proto__ = this.encodings['binary'];
|
||||||
this.prefix(0x0F); // SIN magic number, in numberspace
|
this.prefix(0x0F); // SIN magic number, in numberspace
|
||||||
this.type(type);
|
this.type(type);
|
||||||
this.payload(payload);
|
this.payload(payload);
|
||||||
};
|
};
|
||||||
|
@ -17,12 +17,14 @@ parent.applyEncodingsTo(SIN);
|
||||||
|
|
||||||
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
||||||
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
||||||
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
||||||
|
|
||||||
// get or set the prefix data (the first byte of the address)
|
// get or set the prefix data (the first byte of the address)
|
||||||
SIN.prototype.prefix = function(num) {
|
SIN.prototype.prefix = function(num) {
|
||||||
if(num || (num === 0)) {
|
if (num || (num === 0)) {
|
||||||
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
|
this.doAsBinary(function() {
|
||||||
|
this.data.writeUInt8(num, 0);
|
||||||
|
});
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
return this.as('binary').readUInt8(0);
|
return this.as('binary').readUInt8(0);
|
||||||
|
@ -30,8 +32,10 @@ SIN.prototype.prefix = function(num) {
|
||||||
|
|
||||||
// get or set the SIN-type data (the second byte of the address)
|
// get or set the SIN-type data (the second byte of the address)
|
||||||
SIN.prototype.type = function(num) {
|
SIN.prototype.type = function(num) {
|
||||||
if(num || (num === 0)) {
|
if (num || (num === 0)) {
|
||||||
this.doAsBinary(function() {this.data.writeUInt8(num, 1);});
|
this.doAsBinary(function() {
|
||||||
|
this.data.writeUInt8(num, 1);
|
||||||
|
});
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
return this.as('binary').readUInt8(1);
|
return this.as('binary').readUInt8(1);
|
||||||
|
@ -39,8 +43,10 @@ SIN.prototype.type = function(num) {
|
||||||
|
|
||||||
// get or set the payload data (as a Buffer object)
|
// get or set the payload data (as a Buffer object)
|
||||||
SIN.prototype.payload = function(data) {
|
SIN.prototype.payload = function(data) {
|
||||||
if(data) {
|
if (data) {
|
||||||
this.doAsBinary(function() {data.copy(this.data, 2);});
|
this.doAsBinary(function() {
|
||||||
|
data.copy(this.data, 2);
|
||||||
|
});
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
return this.as('binary').slice(1);
|
return this.as('binary').slice(1);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
var coinUtil = require('../util');
|
var coinUtil = require('../util');
|
||||||
var timeUtil = require('../util/time');
|
var timeUtil = require('../util/time');
|
||||||
var Key = require('./Key');
|
var Key = require('./Key');
|
||||||
var SIN = require('./SIN');
|
var SIN = require('./SIN');
|
||||||
|
|
||||||
function SINKey(cfg) {
|
function SINKey(cfg) {
|
||||||
if (typeof cfg != 'object')
|
if (typeof cfg != 'object')
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var config = imports.config || require('../config');
|
var config = imports.config || require('../config');
|
||||||
var log = imports.log || require('../util/log');
|
var log = imports.log || require('../util/log');
|
||||||
var Opcode = imports.Opcode || require('./Opcode');
|
var Opcode = imports.Opcode || require('./Opcode');
|
||||||
var buffertools = imports.buffertools || require('buffertools');
|
var buffertools = imports.buffertools || require('buffertools');
|
||||||
|
|
||||||
var util = imports.util || require('../util/util');
|
var util = imports.util || require('../util/util');
|
||||||
var Parser = imports.Parser || require('../util/BinaryParser');
|
var Parser = imports.Parser || require('../util/BinaryParser');
|
||||||
var Put = imports.Put || require('bufferput');
|
var Put = imports.Put || require('bufferput');
|
||||||
|
|
||||||
var TX_UNKNOWN = 0;
|
var TX_UNKNOWN = 0;
|
||||||
var TX_PUBKEY = 1;
|
var TX_PUBKEY = 1;
|
||||||
|
@ -110,40 +110,41 @@ function isSmallIntOp(opcode) {
|
||||||
Script.prototype.isMultiSig = function() {
|
Script.prototype.isMultiSig = function() {
|
||||||
return (this.chunks.length > 3 &&
|
return (this.chunks.length > 3 &&
|
||||||
isSmallIntOp(this.chunks[0]) &&
|
isSmallIntOp(this.chunks[0]) &&
|
||||||
this.chunks.slice(1,this.chunks.length-2).every(function(i){return Buffer.isBuffer(i);}) &&
|
this.chunks.slice(1, this.chunks.length - 2).every(function(i) {
|
||||||
|
return Buffer.isBuffer(i);
|
||||||
|
}) &&
|
||||||
isSmallIntOp(this.chunks[this.chunks.length - 2]) &&
|
isSmallIntOp(this.chunks[this.chunks.length - 2]) &&
|
||||||
this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG);
|
this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG);
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.isP2shScriptSig = function() {
|
Script.prototype.isP2shScriptSig = function() {
|
||||||
if( !isSmallIntOp(this.chunks[0]) || this.chunks[0] !==0 )
|
if (!isSmallIntOp(this.chunks[0]) || this.chunks[0] !== 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var redeemScript = new Script(this.chunks[this.chunks.length-1]);
|
var redeemScript = new Script(this.chunks[this.chunks.length - 1]);
|
||||||
var type=redeemScript.classify();
|
var type = redeemScript.classify();
|
||||||
return type !== TX_UNKNOWN;
|
return type !== TX_UNKNOWN;
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.isMultiSigScriptSig = function() {
|
Script.prototype.isMultiSigScriptSig = function() {
|
||||||
if( !isSmallIntOp(this.chunks[0]) || this.chunks[0] !==0 )
|
if (!isSmallIntOp(this.chunks[0]) || this.chunks[0] !== 0)
|
||||||
return false;
|
return false;
|
||||||
return !this.isP2shScriptSig();
|
return !this.isP2shScriptSig();
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.countSignatures = function() {
|
Script.prototype.countSignatures = function() {
|
||||||
var ret = 0;
|
var ret = 0;
|
||||||
var l =this.chunks.length;
|
var l = this.chunks.length;
|
||||||
|
|
||||||
// Multisig?
|
// Multisig?
|
||||||
if (this.isMultiSigScriptSig()){
|
if (this.isMultiSigScriptSig()) {
|
||||||
ret = l - 1;
|
ret = l - 1;
|
||||||
}
|
} else if (this.isP2shScriptSig()) {
|
||||||
else if (this.isP2shScriptSig()) {
|
|
||||||
ret = l - 2;
|
ret = l - 2;
|
||||||
}
|
}
|
||||||
// p2pubkey or p2pubkeyhash
|
// p2pubkey or p2pubkeyhash
|
||||||
else {
|
else {
|
||||||
ret = buffertools.compare(this.getBuffer(), util.EMPTY_BUFFER)===0?0:1;
|
ret = buffertools.compare(this.getBuffer(), util.EMPTY_BUFFER) === 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
@ -155,14 +156,13 @@ Script.prototype.countMissingSignatures = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = 0;
|
var ret = 0;
|
||||||
var l =this.chunks.length;
|
var l = this.chunks.length;
|
||||||
// P2SH?
|
// P2SH?
|
||||||
if (isSmallIntOp(this.chunks[0]) && this.chunks[0] ===0) {
|
if (isSmallIntOp(this.chunks[0]) && this.chunks[0] === 0) {
|
||||||
var redeemScript = new Script(this.chunks[l-1]);
|
var redeemScript = new Script(this.chunks[l - 1]);
|
||||||
if (!isSmallIntOp(redeemScript.chunks[0])) {
|
if (!isSmallIntOp(redeemScript.chunks[0])) {
|
||||||
log.debug("Unrecognized script type");
|
log.debug("Unrecognized script type");
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var nreq = redeemScript.chunks[0] - 80; //see OP_2-OP_16
|
var nreq = redeemScript.chunks[0] - 80; //see OP_2-OP_16
|
||||||
ret = nreq - (l - 2); // 2-> marked 0 + redeemScript
|
ret = nreq - (l - 2); // 2-> marked 0 + redeemScript
|
||||||
}
|
}
|
||||||
|
@ -201,9 +201,9 @@ Script.prototype.getMultiSigInfo = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nsigs : nsigs,
|
nsigs: nsigs,
|
||||||
npubkeys : npubkeys,
|
npubkeys: npubkeys,
|
||||||
pubkeys : pubkeys
|
pubkeys: pubkeys
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ Script.prototype.toHumanReadable = function() {
|
||||||
} else {
|
} else {
|
||||||
var opcode = Opcode.reverseMap[chunk];
|
var opcode = Opcode.reverseMap[chunk];
|
||||||
if (typeof opcode === 'undefined') {
|
if (typeof opcode === 'undefined') {
|
||||||
opcode = '0x'+chunk.toString(16);
|
opcode = '0x' + chunk.toString(16);
|
||||||
}
|
}
|
||||||
s += opcode;
|
s += opcode;
|
||||||
}
|
}
|
||||||
|
@ -598,17 +598,17 @@ Script.stringToBuffer = function(s) {
|
||||||
//console.log('integer');
|
//console.log('integer');
|
||||||
var data = util.intToBufferSM(integer);
|
var data = util.intToBufferSM(integer);
|
||||||
buf.put(Script.chunksToBuffer([data]));
|
buf.put(Script.chunksToBuffer([data]));
|
||||||
} else if (word[0] === '\'' && word[word.length-1] === '\'') {
|
} else if (word[0] === '\'' && word[word.length - 1] === '\'') {
|
||||||
// string
|
// string
|
||||||
//console.log('string');
|
//console.log('string');
|
||||||
word = word.substring(1,word.length-1);
|
word = word.substring(1, word.length - 1);
|
||||||
var hexString = '';
|
var hexString = '';
|
||||||
for(var c=0;c<word.length;c++) {
|
for (var c = 0; c < word.length; c++) {
|
||||||
hexString += ''+word.charCodeAt(c).toString(16);
|
hexString += '' + word.charCodeAt(c).toString(16);
|
||||||
}
|
}
|
||||||
buf.put(Script.chunksToBuffer([new Buffer(word)]));
|
buf.put(Script.chunksToBuffer([new Buffer(word)]));
|
||||||
} else {
|
} else {
|
||||||
throw new Error('Could not parse word "' +word+'" from script "'+s+'"');
|
throw new Error('Could not parse word "' + word + '" from script "' + s + '"');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1015,7 +1015,7 @@ var checkSig = ScriptInterpreter.checkSig =
|
||||||
key.public = pubkey;
|
key.public = pubkey;
|
||||||
|
|
||||||
key.verifySignature(hash, sig, callback);
|
key.verifySignature(hash, sig, callback);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScriptInterpreter.prototype.isCanonicalSignature = function(sig) {
|
ScriptInterpreter.prototype.isCanonicalSignature = function(sig) {
|
||||||
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
||||||
|
|
127
lib/Sign.js
127
lib/Sign.js
|
@ -1,6 +1,4 @@
|
||||||
|
function signOne(hash, addrStr, keys) {
|
||||||
function signOne(hash, addrStr, keys)
|
|
||||||
{
|
|
||||||
var keyObj = keys[addrStr];
|
var keyObj = keys[addrStr];
|
||||||
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
|
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
|
||||||
var key = new KeyModule.Key();
|
var key = new KeyModule.Key();
|
||||||
|
@ -10,8 +8,7 @@ function signOne(hash, addrStr, keys)
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
function signTxIn(nIn, tx, txInputs, network, keys, scripts)
|
function signTxIn(nIn, tx, txInputs, network, keys, scripts) {
|
||||||
{
|
|
||||||
// locate TX input needing a signature
|
// locate TX input needing a signature
|
||||||
var txin = tx.ins[nIn];
|
var txin = tx.ins[nIn];
|
||||||
var scriptSig = txin.getScript();
|
var scriptSig = txin.getScript();
|
||||||
|
@ -55,79 +52,77 @@ function signTxIn(nIn, tx, txInputs, network, keys, scripts)
|
||||||
var hash = tx.hashForSignature(scriptPubKey, i, 0);
|
var hash = tx.hashForSignature(scriptPubKey, i, 0);
|
||||||
|
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case TX_PUBKEY:
|
case TX_PUBKEY:
|
||||||
// already signed
|
// already signed
|
||||||
if (scriptSig.chunks.length > 0)
|
if (scriptSig.chunks.length > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var pubkeyhash = util.sha256ripe160(scriptData[0]);
|
var pubkeyhash = util.sha256ripe160(scriptData[0]);
|
||||||
var addr = new Address(network.addressVersion, pubkeyhash);
|
|
||||||
var addrStr = addr.toString();
|
|
||||||
if (!(addrStr in keys))
|
|
||||||
throw new Error("unknown pubkey");
|
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
|
||||||
scriptSig.writeBytes(signature);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TX_PUBKEYHASH:
|
|
||||||
// already signed
|
|
||||||
if (scriptSig.chunks.length > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var addr = new Address(network.addressVersion, scriptData[0]);
|
|
||||||
var addrStr = addr.toString();
|
|
||||||
if (!(addrStr in keys))
|
|
||||||
throw new Error("unknown pubkey hash address");
|
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
|
||||||
scriptSig.writeBytes(signature);
|
|
||||||
scriptSig.writeBytes(key.public);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TX_SCRIPTHASH:
|
|
||||||
// already signed
|
|
||||||
if (scriptSig.chunks.length > 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var addr = new Address(network.addressVersion, subData[0]);
|
|
||||||
var addrStr = addr.toString();
|
|
||||||
if (!(addrStr in keys))
|
|
||||||
throw new Error("unknown script(pubkey hash) address");
|
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
|
||||||
scriptSig.writeBytes(signature);
|
|
||||||
scriptSig.writeBytes(key.public);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TX_MULTISIG:
|
|
||||||
while (scriptSig.chunks.length < scriptData.length) {
|
|
||||||
scriptSig.writeBytes(util.EMPTY_BUFFER);
|
|
||||||
}
|
|
||||||
for (var i = 0; i < scriptData.length; i++) {
|
|
||||||
// skip already signed
|
|
||||||
if (scriptSig.chunks[i].length > 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
|
|
||||||
var addr = new Address(network.addressVersion, pubkeyhash);
|
var addr = new Address(network.addressVersion, pubkeyhash);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in keys))
|
if (!(addrStr in keys))
|
||||||
continue;
|
throw new Error("unknown pubkey");
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
var signature = signOne(hash, addrStr, keys);
|
||||||
scriptSig.chunks[i] = signature;
|
scriptSig.writeBytes(signature);
|
||||||
}
|
break;
|
||||||
break;
|
|
||||||
|
case TX_PUBKEYHASH:
|
||||||
|
// already signed
|
||||||
|
if (scriptSig.chunks.length > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var addr = new Address(network.addressVersion, scriptData[0]);
|
||||||
|
var addrStr = addr.toString();
|
||||||
|
if (!(addrStr in keys))
|
||||||
|
throw new Error("unknown pubkey hash address");
|
||||||
|
|
||||||
|
var signature = signOne(hash, addrStr, keys);
|
||||||
|
scriptSig.writeBytes(signature);
|
||||||
|
scriptSig.writeBytes(key.public);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TX_SCRIPTHASH:
|
||||||
|
// already signed
|
||||||
|
if (scriptSig.chunks.length > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var addr = new Address(network.addressVersion, subData[0]);
|
||||||
|
var addrStr = addr.toString();
|
||||||
|
if (!(addrStr in keys))
|
||||||
|
throw new Error("unknown script(pubkey hash) address");
|
||||||
|
|
||||||
|
var signature = signOne(hash, addrStr, keys);
|
||||||
|
scriptSig.writeBytes(signature);
|
||||||
|
scriptSig.writeBytes(key.public);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TX_MULTISIG:
|
||||||
|
while (scriptSig.chunks.length < scriptData.length) {
|
||||||
|
scriptSig.writeBytes(util.EMPTY_BUFFER);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < scriptData.length; i++) {
|
||||||
|
// skip already signed
|
||||||
|
if (scriptSig.chunks[i].length > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
|
||||||
|
var addr = new Address(network.addressVersion, pubkeyhash);
|
||||||
|
var addrStr = addr.toString();
|
||||||
|
if (!(addrStr in keys))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var signature = signOne(hash, addrStr, keys);
|
||||||
|
scriptSig.chunks[i] = signature;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txtype == TX_SCRIPTHASH)
|
if (txtype == TX_SCRIPTHASH)
|
||||||
scriptSig.writeBytes(subscriptRaw);
|
scriptSig.writeBytes(subscriptRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts)
|
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts) {
|
||||||
{
|
|
||||||
for (var i = 0; i < tx.ins.length; i++)
|
for (var i = 0; i < tx.ins.length; i++)
|
||||||
signTxIn(i, tx, txInputs, network, keys, scripts);
|
signTxIn(i, tx, txInputs, network, keys, scripts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -199,13 +199,13 @@ Transaction.prototype.getHash = function getHash() {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Transaction.prototype.calcNormalizedHash = function () {
|
Transaction.prototype.calcNormalizedHash = function() {
|
||||||
this.normalizedHash = this.hashForSignature(new Script(),0, SIGHASH_ALL);
|
this.normalizedHash = this.hashForSignature(new Script(), 0, SIGHASH_ALL);
|
||||||
return this.normalizedHash;
|
return this.normalizedHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Transaction.prototype.getNormalizedHash = function () {
|
Transaction.prototype.getNormalizedHash = function() {
|
||||||
if (!this.normalizedHash || !this.normalizedHash.length) {
|
if (!this.normalizedHash || !this.normalizedHash.length) {
|
||||||
this.normalizedHash = this.calcNormalizedHash();
|
this.normalizedHash = this.calcNormalizedHash();
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,7 @@ var oneBuffer = function() {
|
||||||
// see https://bitcointalk.org/index.php?topic=260595
|
// see https://bitcointalk.org/index.php?topic=260595
|
||||||
var ret = new Buffer(32);
|
var ret = new Buffer(32);
|
||||||
ret.writeUInt8(1, 0);
|
ret.writeUInt8(1, 0);
|
||||||
for (var i=1; i<32; i++) ret.writeUInt8(0, i);
|
for (var i = 1; i < 32; i++) ret.writeUInt8(0, i);
|
||||||
return ret; // return 1 bug
|
return ret; // return 1 bug
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -586,7 +586,7 @@ Transaction.prototype.calcSize = function() {
|
||||||
return totalSize;
|
return totalSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
Transaction.prototype.getSize = function () {
|
Transaction.prototype.getSize = function() {
|
||||||
if (!this.size) {
|
if (!this.size) {
|
||||||
this.size = this.calcSize();
|
this.size = this.calcSize();
|
||||||
}
|
}
|
||||||
|
@ -609,17 +609,17 @@ Transaction.prototype.countInputMissingSignatures = function(index) {
|
||||||
// Works on p2pubkey, p2pubkeyhash & p2sh (no normal multisig)
|
// Works on p2pubkey, p2pubkeyhash & p2sh (no normal multisig)
|
||||||
Transaction.prototype.isInputComplete = function(index) {
|
Transaction.prototype.isInputComplete = function(index) {
|
||||||
var m = this.countInputMissingSignatures(index);
|
var m = this.countInputMissingSignatures(index);
|
||||||
if (m===null) return null;
|
if (m === null) return null;
|
||||||
return m === 0;
|
return m === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Works on p2pubkey, p2pubkeyhash & p2sh (no normal multisig)
|
// Works on p2pubkey, p2pubkeyhash & p2sh (no normal multisig)
|
||||||
Transaction.prototype.isComplete = function() {
|
Transaction.prototype.isComplete = function() {
|
||||||
var ret = true;
|
var ret = true;
|
||||||
var l = this.ins.length;
|
var l = this.ins.length;
|
||||||
|
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
if (!this.isInputComplete(i)){
|
if (!this.isInputComplete(i)) {
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,8 +97,8 @@ var FEE_PER_1000B_SAT = parseInt(0.0001 * util.COIN);
|
||||||
// ```
|
// ```
|
||||||
|
|
||||||
function TransactionBuilder(opts) {
|
function TransactionBuilder(opts) {
|
||||||
opts = opts || {};
|
opts = opts || {};
|
||||||
this.lockTime = opts.lockTime || 0;
|
this.lockTime = opts.lockTime || 0;
|
||||||
this.spendUnconfirmed = opts.spendUnconfirmed || false;
|
this.spendUnconfirmed = opts.spendUnconfirmed || false;
|
||||||
|
|
||||||
if (opts.fee || opts.feeSat) {
|
if (opts.fee || opts.feeSat) {
|
||||||
|
@ -107,9 +107,9 @@ function TransactionBuilder(opts) {
|
||||||
this.remainderOut = opts.remainderOut;
|
this.remainderOut = opts.remainderOut;
|
||||||
this.signhash = opts.signhash || Transaction.SIGHASH_ALL;
|
this.signhash = opts.signhash || Transaction.SIGHASH_ALL;
|
||||||
|
|
||||||
this.tx = {};
|
this.tx = {};
|
||||||
this.inputsSigned= 0;
|
this.inputsSigned = 0;
|
||||||
this.signaturesAdded= 0;
|
this.signaturesAdded = 0;
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -119,10 +119,10 @@ TransactionBuilder.FEE_PER_1000B_SAT = FEE_PER_1000B_SAT;
|
||||||
TransactionBuilder._scriptForPubkeys = function(out) {
|
TransactionBuilder._scriptForPubkeys = function(out) {
|
||||||
|
|
||||||
var l = out.pubkeys.length;
|
var l = out.pubkeys.length;
|
||||||
var pubKeyBuf=[];
|
var pubKeyBuf = [];
|
||||||
|
|
||||||
for (var i=0; i<l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
pubKeyBuf.push(new Buffer(out.pubkeys[i],'hex'));
|
pubKeyBuf.push(new Buffer(out.pubkeys[i], 'hex'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Script.createMultisig(out.nreq, pubKeyBuf);
|
return Script.createMultisig(out.nreq, pubKeyBuf);
|
||||||
|
@ -143,7 +143,7 @@ TransactionBuilder._scriptForOut = function(out) {
|
||||||
|
|
||||||
TransactionBuilder.infoForP2sh = function(opts, networkName) {
|
TransactionBuilder.infoForP2sh = function(opts, networkName) {
|
||||||
var script = this._scriptForOut(opts);
|
var script = this._scriptForOut(opts);
|
||||||
var hash = util.sha256ripe160(script.getBuffer());
|
var hash = util.sha256ripe160(script.getBuffer());
|
||||||
|
|
||||||
var version = networkName === 'testnet' ?
|
var version = networkName === 'testnet' ?
|
||||||
networks.testnet.P2SHVersion : networks.livenet.P2SHVersion;
|
networks.testnet.P2SHVersion : networks.livenet.P2SHVersion;
|
||||||
|
@ -187,14 +187,14 @@ TransactionBuilder.prototype._setInputMap = function() {
|
||||||
|
|
||||||
var l = this.selectedUtxos.length;
|
var l = this.selectedUtxos.length;
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var utxo = this.selectedUtxos[i];
|
var utxo = this.selectedUtxos[i];
|
||||||
var scriptBuf = new Buffer(utxo.scriptPubKey, 'hex');
|
var scriptBuf = new Buffer(utxo.scriptPubKey, 'hex');
|
||||||
var scriptPubKey = new Script(scriptBuf);
|
var scriptPubKey = new Script(scriptBuf);
|
||||||
var scriptType = scriptPubKey.classify();
|
var scriptType = scriptPubKey.classify();
|
||||||
|
|
||||||
if (scriptType === Script.TX_UNKNOWN)
|
if (scriptType === Script.TX_UNKNOWN)
|
||||||
throw new Error('unkown output type at:' + i +
|
throw new Error('unkown output type at:' + i +
|
||||||
' Type:' + scriptPubKey.getRawOutType());
|
' Type:' + scriptPubKey.getRawOutType());
|
||||||
|
|
||||||
inputMap.push({
|
inputMap.push({
|
||||||
address: utxo.address,
|
address: utxo.address,
|
||||||
|
@ -218,10 +218,10 @@ TransactionBuilder.prototype.getSelectedUnspent = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* _selectUnspent
|
/* _selectUnspent
|
||||||
* TODO(?): sort sel (at the end) and check is some inputs can be avoided.
|
* TODO(?): sort sel (at the end) and check is some inputs can be avoided.
|
||||||
* If the initial utxos are sorted, this step would be necesary only if
|
* If the initial utxos are sorted, this step would be necesary only if
|
||||||
* utxos were selected from different minConfirmationSteps.
|
* utxos were selected from different minConfirmationSteps.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
|
TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
|
||||||
|
|
||||||
|
@ -231,11 +231,11 @@ TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
|
||||||
var minConfirmationSteps = [6, 1];
|
var minConfirmationSteps = [6, 1];
|
||||||
if (this.spendUnconfirmed) minConfirmationSteps.push(0);
|
if (this.spendUnconfirmed) minConfirmationSteps.push(0);
|
||||||
|
|
||||||
var sel = [],
|
var sel = [],
|
||||||
totalSat = bignum(0),
|
totalSat = bignum(0),
|
||||||
fulfill = false,
|
fulfill = false,
|
||||||
maxConfirmations = null,
|
maxConfirmations = null,
|
||||||
l = this.utxos.length;
|
l = this.utxos.length;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
var minConfirmations = minConfirmationSteps.shift();
|
var minConfirmations = minConfirmationSteps.shift();
|
||||||
|
@ -259,7 +259,7 @@ TransactionBuilder.prototype._selectUnspent = function(neededAmountSat) {
|
||||||
|
|
||||||
if (!fulfill)
|
if (!fulfill)
|
||||||
throw new Error('not enough unspent tx outputs to fulfill totalNeededAmount [SAT]:' +
|
throw new Error('not enough unspent tx outputs to fulfill totalNeededAmount [SAT]:' +
|
||||||
neededAmountSat);
|
neededAmountSat);
|
||||||
|
|
||||||
this.selectedUtxos = sel;
|
this.selectedUtxos = sel;
|
||||||
this._setInputMap();
|
this._setInputMap();
|
||||||
|
@ -271,7 +271,7 @@ TransactionBuilder.prototype._setInputs = function(txobj) {
|
||||||
var l = ins.length;
|
var l = ins.length;
|
||||||
var valueInSat = bignum(0);
|
var valueInSat = bignum(0);
|
||||||
|
|
||||||
txobj.ins=[];
|
txobj.ins = [];
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
valueInSat = valueInSat.add(util.parseValue(ins[i].amount));
|
valueInSat = valueInSat.add(util.parseValue(ins[i].amount));
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ TransactionBuilder.prototype._setInputs = function(txobj) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._setFee = function(feeSat) {
|
TransactionBuilder.prototype._setFee = function(feeSat) {
|
||||||
if ( typeof this.valueOutSat === 'undefined')
|
if (typeof this.valueOutSat === 'undefined')
|
||||||
throw new Error('valueOutSat undefined');
|
throw new Error('valueOutSat undefined');
|
||||||
|
|
||||||
|
|
||||||
|
@ -312,13 +312,13 @@ TransactionBuilder.prototype._setFee = function(feeSat) {
|
||||||
|
|
||||||
TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
||||||
|
|
||||||
if ( typeof this.valueInSat === 'undefined' ||
|
if (typeof this.valueInSat === 'undefined' ||
|
||||||
typeof this.valueOutSat === 'undefined')
|
typeof this.valueOutSat === 'undefined')
|
||||||
throw new Error('valueInSat / valueOutSat undefined');
|
throw new Error('valueInSat / valueOutSat undefined');
|
||||||
|
|
||||||
/* add remainder (without modifying outs[]) */
|
/* add remainder (without modifying outs[]) */
|
||||||
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
var remainderSat = this.valueInSat.sub(this.valueOutSat).sub(this.feeSat);
|
||||||
var l =txobj.outs.length;
|
var l = txobj.outs.length;
|
||||||
this.remainderSat = bignum(0);
|
this.remainderSat = bignum(0);
|
||||||
|
|
||||||
/*remove old remainder? */
|
/*remove old remainder? */
|
||||||
|
@ -344,7 +344,8 @@ TransactionBuilder.prototype._setRemainder = function(txobj, remainderIndex) {
|
||||||
TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
|
|
||||||
/* starting size estimation */
|
/* starting size estimation */
|
||||||
var size = 500, maxSizeK, remainderIndex = txobj.outs.length;
|
var size = 500,
|
||||||
|
maxSizeK, remainderIndex = txobj.outs.length;
|
||||||
do {
|
do {
|
||||||
/* based on https://en.bitcoin.it/wiki/Transaction_fees */
|
/* based on https://en.bitcoin.it/wiki/Transaction_fees */
|
||||||
maxSizeK = parseInt(size / 1000) + 1;
|
maxSizeK = parseInt(size / 1000) + 1;
|
||||||
|
@ -355,11 +356,11 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
var neededAmountSat = this.valueOutSat.add(feeSat);
|
var neededAmountSat = this.valueOutSat.add(feeSat);
|
||||||
|
|
||||||
this._selectUnspent(neededAmountSat)
|
this._selectUnspent(neededAmountSat)
|
||||||
._setInputs(txobj)
|
._setInputs(txobj)
|
||||||
._setFee(feeSat)
|
._setFee(feeSat)
|
||||||
._setRemainder(txobj, remainderIndex);
|
._setRemainder(txobj, remainderIndex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size = new Transaction(txobj).getSize();
|
size = new Transaction(txobj).getSize();
|
||||||
} while (size > (maxSizeK + 1) * 1000);
|
} while (size > (maxSizeK + 1) * 1000);
|
||||||
return this;
|
return this;
|
||||||
|
@ -383,13 +384,13 @@ TransactionBuilder.prototype._setFeeAndRemainder = function(txobj) {
|
||||||
TransactionBuilder.prototype.setOutputs = function(outs) {
|
TransactionBuilder.prototype.setOutputs = function(outs) {
|
||||||
var valueOutSat = bignum(0);
|
var valueOutSat = bignum(0);
|
||||||
|
|
||||||
var txobj = {};
|
var txobj = {};
|
||||||
txobj.version = 1;
|
txobj.version = 1;
|
||||||
txobj.lock_time = this.lockTime || 0;
|
txobj.lock_time = this.lockTime || 0;
|
||||||
txobj.ins = [];
|
txobj.ins = [];
|
||||||
txobj.outs = [];
|
txobj.outs = [];
|
||||||
|
|
||||||
var l =outs.length;
|
var l = outs.length;
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var amountSat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
var amountSat = outs[i].amountSat || util.parseValue(outs[i].amount);
|
||||||
var value = util.bigIntToValue(amountSat);
|
var value = util.bigIntToValue(amountSat);
|
||||||
|
@ -422,13 +423,15 @@ TransactionBuilder._mapKeys = function(keys) {
|
||||||
|
|
||||||
if (typeof k === 'string') {
|
if (typeof k === 'string') {
|
||||||
var pk = new PrivateKey(k);
|
var pk = new PrivateKey(k);
|
||||||
wk = new WalletKey({ network: pk.network() });
|
wk = new WalletKey({
|
||||||
wk.fromObj({ priv: k });
|
network: pk.network()
|
||||||
}
|
});
|
||||||
else if (k instanceof WalletKey) {
|
wk.fromObj({
|
||||||
|
priv: k
|
||||||
|
});
|
||||||
|
} else if (k instanceof WalletKey) {
|
||||||
wk = k;
|
wk = k;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw new Error('argument must be an array of strings (WIF format) or WalletKey objects');
|
throw new Error('argument must be an array of strings (WIF format) or WalletKey objects');
|
||||||
}
|
}
|
||||||
walletKeyMap[wk.storeObj().addr] = wk;
|
walletKeyMap[wk.storeObj().addr] = wk;
|
||||||
|
@ -437,30 +440,31 @@ TransactionBuilder._mapKeys = function(keys) {
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder._signHashAndVerify = function(wk, txSigHash) {
|
TransactionBuilder._signHashAndVerify = function(wk, txSigHash) {
|
||||||
var triesLeft = 10, sigRaw;
|
var triesLeft = 10,
|
||||||
|
sigRaw;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
sigRaw = wk.privKey.signSync(txSigHash);
|
sigRaw = wk.privKey.signSync(txSigHash);
|
||||||
} while (wk.privKey.verifySignatureSync(txSigHash, sigRaw) === false &&
|
} while (wk.privKey.verifySignatureSync(txSigHash, sigRaw) === false &&
|
||||||
triesLeft--);
|
triesLeft--);
|
||||||
|
|
||||||
if (triesLeft<0)
|
if (triesLeft < 0)
|
||||||
throw new Error('could not sign input: verification failed');
|
throw new Error('could not sign input: verification failed');
|
||||||
|
|
||||||
return sigRaw;
|
return sigRaw;
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._checkTx = function() {
|
TransactionBuilder.prototype._checkTx = function() {
|
||||||
if (! this.tx || !this.tx.ins.length || !this.tx.outs.length)
|
if (!this.tx || !this.tx.ins.length || !this.tx.outs.length)
|
||||||
throw new Error('tx is not defined');
|
throw new Error('tx is not defined');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._multiFindKey = function(walletKeyMap,pubKeyHash) {
|
TransactionBuilder.prototype._multiFindKey = function(walletKeyMap, pubKeyHash) {
|
||||||
var wk;
|
var wk;
|
||||||
[ networks.livenet, networks.testnet].forEach(function(n) {
|
[networks.livenet, networks.testnet].forEach(function(n) {
|
||||||
[ n.addressVersion, n.P2SHVersion].forEach(function(v) {
|
[n.addressVersion, n.P2SHVersion].forEach(function(v) {
|
||||||
var a = new Address(v,pubKeyHash);
|
var a = new Address(v, pubKeyHash);
|
||||||
if (!wk && walletKeyMap[a]) {
|
if (!wk && walletKeyMap[a]) {
|
||||||
wk = walletKeyMap[a];
|
wk = walletKeyMap[a];
|
||||||
}
|
}
|
||||||
|
@ -474,14 +478,12 @@ TransactionBuilder.prototype._findWalletKey = function(walletKeyMap, input) {
|
||||||
var wk;
|
var wk;
|
||||||
|
|
||||||
if (input.address) {
|
if (input.address) {
|
||||||
wk = walletKeyMap[input.address];
|
wk = walletKeyMap[input.address];
|
||||||
}
|
} else if (input.pubKeyHash) {
|
||||||
else if (input.pubKeyHash) {
|
wk = this._multiFindKey(walletKeyMap, input.pubKeyHash);
|
||||||
wk = this._multiFindKey(walletKeyMap, input.pubKeyHash);
|
} else if (input.pubKeyBuf) {
|
||||||
}
|
|
||||||
else if (input.pubKeyBuf) {
|
|
||||||
var pubKeyHash = util.sha256ripe160(input.pubKeyBuf);
|
var pubKeyHash = util.sha256ripe160(input.pubKeyBuf);
|
||||||
wk = this._multiFindKey(walletKeyMap, pubKeyHash);
|
wk = this._multiFindKey(walletKeyMap, pubKeyHash);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('no infomation at input to find keys');
|
throw new Error('no infomation at input to find keys');
|
||||||
}
|
}
|
||||||
|
@ -491,37 +493,45 @@ TransactionBuilder.prototype._findWalletKey = function(walletKeyMap, input) {
|
||||||
TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signPubKey = function(walletKeyMap, input, txSigHash) {
|
||||||
if (this.tx.ins[input.i].s.length > 0) return {};
|
if (this.tx.ins[input.i].s.length > 0) return {};
|
||||||
|
|
||||||
var wk = this._findWalletKey(walletKeyMap, input);
|
var wk = this._findWalletKey(walletKeyMap, input);
|
||||||
if (!wk) return;
|
if (!wk) return;
|
||||||
|
|
||||||
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
||||||
var sigType = new Buffer(1);
|
var sigType = new Buffer(1);
|
||||||
sigType[0] = this.signhash;
|
sigType[0] = this.signhash;
|
||||||
var sig = Buffer.concat([sigRaw, sigType]);
|
var sig = Buffer.concat([sigRaw, sigType]);
|
||||||
|
|
||||||
var scriptSig = new Script();
|
var scriptSig = new Script();
|
||||||
scriptSig.chunks.push(sig);
|
scriptSig.chunks.push(sig);
|
||||||
scriptSig.updateBuffer();
|
scriptSig.updateBuffer();
|
||||||
return {inputFullySigned: true, signaturesAdded: 1, script: scriptSig.getBuffer()};
|
return {
|
||||||
|
inputFullySigned: true,
|
||||||
|
signaturesAdded: 1,
|
||||||
|
script: scriptSig.getBuffer()
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signPubKeyHash = function(walletKeyMap, input, txSigHash) {
|
||||||
|
|
||||||
if (this.tx.ins[input.i].s.length > 0) return {};
|
if (this.tx.ins[input.i].s.length > 0) return {};
|
||||||
|
|
||||||
var wk = this._findWalletKey(walletKeyMap, input);
|
var wk = this._findWalletKey(walletKeyMap, input);
|
||||||
if (!wk) return;
|
if (!wk) return;
|
||||||
|
|
||||||
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
||||||
var sigType = new Buffer(1);
|
var sigType = new Buffer(1);
|
||||||
sigType[0] = this.signhash;
|
sigType[0] = this.signhash;
|
||||||
var sig = Buffer.concat([sigRaw, sigType]);
|
var sig = Buffer.concat([sigRaw, sigType]);
|
||||||
|
|
||||||
var scriptSig = new Script();
|
var scriptSig = new Script();
|
||||||
scriptSig.chunks.push(sig);
|
scriptSig.chunks.push(sig);
|
||||||
scriptSig.chunks.push(wk.privKey.public);
|
scriptSig.chunks.push(wk.privKey.public);
|
||||||
scriptSig.updateBuffer();
|
scriptSig.updateBuffer();
|
||||||
return {inputFullySigned: true, signaturesAdded: 1, script: scriptSig.getBuffer()};
|
return {
|
||||||
|
inputFullySigned: true,
|
||||||
|
signaturesAdded: 1,
|
||||||
|
script: scriptSig.getBuffer()
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FOR TESTING
|
/* FOR TESTING
|
||||||
|
@ -537,13 +547,13 @@ var _dumpChunks = function (scriptSig, label) {
|
||||||
TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash, publicKey) {
|
TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash, publicKey) {
|
||||||
var ret;
|
var ret;
|
||||||
var k = new Key();
|
var k = new Key();
|
||||||
k.public =publicKey;
|
k.public = publicKey;
|
||||||
|
|
||||||
for(var i=1; i<= scriptSig.countSignatures(); i++) {
|
for (var i = 1; i <= scriptSig.countSignatures(); i++) {
|
||||||
var chunk = scriptSig.chunks[i];
|
var chunk = scriptSig.chunks[i];
|
||||||
var sigRaw = new Buffer(chunk.slice(0,chunk.length-1));
|
var sigRaw = new Buffer(chunk.slice(0, chunk.length - 1));
|
||||||
if (k.verifySignatureSync(txSigHash, sigRaw) ) {
|
if (k.verifySignatureSync(txSigHash, sigRaw)) {
|
||||||
ret=chunk;
|
ret = chunk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -551,10 +561,10 @@ TransactionBuilder.prototype._chunkSignedWithKey = function(scriptSig, txSigHash
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._getSignatureOrder = function(sigPrio, sigRaw, txSigHash, pubkeys) {
|
TransactionBuilder.prototype._getSignatureOrder = function(sigPrio, sigRaw, txSigHash, pubkeys) {
|
||||||
var l=pubkeys.length;
|
var l = pubkeys.length;
|
||||||
for(var j=0; j<l; j++) {
|
for (var j = 0; j < l; j++) {
|
||||||
var k = new Key();
|
var k = new Key();
|
||||||
k.public = new Buffer(pubkeys[j],'hex');
|
k.public = new Buffer(pubkeys[j], 'hex');
|
||||||
if (k.verifySignatureSync(txSigHash, sigRaw))
|
if (k.verifySignatureSync(txSigHash, sigRaw))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -563,17 +573,17 @@ TransactionBuilder.prototype._getSignatureOrder = function(sigPrio, sigRaw, txSi
|
||||||
|
|
||||||
TransactionBuilder.prototype._getNewSignatureOrder = function(sigPrio, scriptSig, txSigHash, pubkeys) {
|
TransactionBuilder.prototype._getNewSignatureOrder = function(sigPrio, scriptSig, txSigHash, pubkeys) {
|
||||||
var iPrio;
|
var iPrio;
|
||||||
for(var i=1; i<= scriptSig.countSignatures(); i++) {
|
for (var i = 1; i <= scriptSig.countSignatures(); i++) {
|
||||||
var chunk = scriptSig.chunks[i];
|
var chunk = scriptSig.chunks[i];
|
||||||
var sigRaw = new Buffer(chunk.slice(0,chunk.length-1));
|
var sigRaw = new Buffer(chunk.slice(0, chunk.length - 1));
|
||||||
iPrio = this._getSignatureOrder(sigPrio, sigRaw, txSigHash, pubkeys);
|
iPrio = this._getSignatureOrder(sigPrio, sigRaw, txSigHash, pubkeys);
|
||||||
if (sigPrio <= iPrio) break;
|
if (sigPrio <= iPrio) break;
|
||||||
}
|
}
|
||||||
return (sigPrio === iPrio? -1: i-1);
|
return (sigPrio === iPrio ? -1 : i - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._chunkIsEmpty = function(chunk) {
|
TransactionBuilder.prototype._chunkIsEmpty = function(chunk) {
|
||||||
return chunk === 0 || // when serializing and back, EMPTY_BUFFER becomes 0
|
return chunk === 0 || // when serializing and back, EMPTY_BUFFER becomes 0
|
||||||
buffertools.compare(chunk, util.EMPTY_BUFFER) === 0;
|
buffertools.compare(chunk, util.EMPTY_BUFFER) === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -593,16 +603,16 @@ TransactionBuilder.prototype._updateMultiSig = function(sigPrio, wk, scriptSig,
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// Create signature
|
// Create signature
|
||||||
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
var sigRaw = TransactionBuilder._signHashAndVerify(wk, txSigHash);
|
||||||
var sigType = new Buffer(1);
|
var sigType = new Buffer(1);
|
||||||
sigType[0] = this.signhash;
|
sigType[0] = this.signhash;
|
||||||
var sig = Buffer.concat([sigRaw, sigType]);
|
var sig = Buffer.concat([sigRaw, sigType]);
|
||||||
|
|
||||||
// Add signature
|
// Add signature
|
||||||
var order = this._getNewSignatureOrder(sigPrio,scriptSig,txSigHash,pubkeys);
|
var order = this._getNewSignatureOrder(sigPrio, scriptSig, txSigHash, pubkeys);
|
||||||
scriptSig.chunks.splice(order+1,0,sig);
|
scriptSig.chunks.splice(order + 1, 0, sig);
|
||||||
scriptSig.updateBuffer();
|
scriptSig.updateBuffer();
|
||||||
wasUpdated=true;
|
wasUpdated = true;
|
||||||
|
|
||||||
return wasUpdated ? scriptSig : null;
|
return wasUpdated ? scriptSig : null;
|
||||||
};
|
};
|
||||||
|
@ -610,15 +620,17 @@ TransactionBuilder.prototype._updateMultiSig = function(sigPrio, wk, scriptSig,
|
||||||
|
|
||||||
TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSigHash) {
|
||||||
var pubkeys = input.scriptPubKey.capture(),
|
var pubkeys = input.scriptPubKey.capture(),
|
||||||
nreq = input.scriptPubKey.chunks[0] - 80, //see OP_2-OP_16
|
nreq = input.scriptPubKey.chunks[0] - 80, //see OP_2-OP_16
|
||||||
l = pubkeys.length,
|
l = pubkeys.length,
|
||||||
originalScriptBuf = this.tx.ins[input.i].s;
|
originalScriptBuf = this.tx.ins[input.i].s;
|
||||||
|
|
||||||
var scriptSig = new Script (originalScriptBuf);
|
var scriptSig = new Script(originalScriptBuf);
|
||||||
var signaturesAdded = 0;
|
var signaturesAdded = 0;
|
||||||
|
|
||||||
for(var j=0; j<l && scriptSig.countSignatures() < nreq ; j++) {
|
for (var j = 0; j < l && scriptSig.countSignatures() < nreq; j++) {
|
||||||
var wk = this._findWalletKey(walletKeyMap, {pubKeyBuf: pubkeys[j]});
|
var wk = this._findWalletKey(walletKeyMap, {
|
||||||
|
pubKeyBuf: pubkeys[j]
|
||||||
|
});
|
||||||
if (!wk) continue;
|
if (!wk) continue;
|
||||||
|
|
||||||
var newScriptSig = this._updateMultiSig(j, wk, scriptSig, txSigHash, pubkeys);
|
var newScriptSig = this._updateMultiSig(j, wk, scriptSig, txSigHash, pubkeys);
|
||||||
|
@ -629,22 +641,22 @@ TransactionBuilder.prototype._signMultiSig = function(walletKeyMap, input, txSig
|
||||||
}
|
}
|
||||||
|
|
||||||
var ret = {
|
var ret = {
|
||||||
inputFullySigned: scriptSig.countSignatures() === nreq,
|
inputFullySigned: scriptSig.countSignatures() === nreq,
|
||||||
signaturesAdded: signaturesAdded,
|
signaturesAdded: signaturesAdded,
|
||||||
script: scriptSig.getBuffer(),
|
script: scriptSig.getBuffer(),
|
||||||
};
|
};
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
var fnToSign = {};
|
var fnToSign = {};
|
||||||
TransactionBuilder.prototype._scriptIsAppended = function(script, scriptToAddBuf) {
|
TransactionBuilder.prototype._scriptIsAppended = function(script, scriptToAddBuf) {
|
||||||
var len = script.chunks.length;
|
var len = script.chunks.length;
|
||||||
|
|
||||||
if (script.chunks[len-1] === undefined)
|
if (script.chunks[len - 1] === undefined)
|
||||||
return false;
|
return false;
|
||||||
if (typeof script.chunks[len-1] === 'number')
|
if (typeof script.chunks[len - 1] === 'number')
|
||||||
return false;
|
return false;
|
||||||
if (buffertools.compare(script.chunks[len-1] , scriptToAddBuf) !==0 )
|
if (buffertools.compare(script.chunks[len - 1], scriptToAddBuf) !== 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -659,17 +671,17 @@ TransactionBuilder.prototype._addScript = function(scriptBuf, scriptToAddBuf) {
|
||||||
}
|
}
|
||||||
return s.getBuffer();
|
return s.getBuffer();
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionBuilder.prototype._getInputForP2sh = function(script, index) {
|
TransactionBuilder.prototype._getInputForP2sh = function(script, index) {
|
||||||
var scriptType = script.classify();
|
var scriptType = script.classify();
|
||||||
/* pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys. */
|
/* pubKeyHash is needed for TX_PUBKEYHASH and TX_PUBKEY to retrieve the keys. */
|
||||||
var pubKeyHash;
|
var pubKeyHash;
|
||||||
switch(scriptType) {
|
switch (scriptType) {
|
||||||
case Script.TX_PUBKEYHASH:
|
case Script.TX_PUBKEYHASH:
|
||||||
pubKeyHash = script.captureOne();
|
pubKeyHash = script.captureOne();
|
||||||
break;
|
break;
|
||||||
case Script.TX_PUBKEY:
|
case Script.TX_PUBKEY:
|
||||||
var chunk = script.captureOne();
|
var chunk = script.captureOne();
|
||||||
pubKeyHash = util.sha256ripe160(chunk);
|
pubKeyHash = util.sha256ripe160(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,16 +701,16 @@ TransactionBuilder.prototype._p2shInput = function(input) {
|
||||||
var scriptHex = this.hashToScriptMap[input.address];
|
var scriptHex = this.hashToScriptMap[input.address];
|
||||||
if (!scriptHex) return;
|
if (!scriptHex) return;
|
||||||
|
|
||||||
var scriptBuf = new Buffer(scriptHex,'hex');
|
var scriptBuf = new Buffer(scriptHex, 'hex');
|
||||||
var script = new Script(scriptBuf);
|
var script = new Script(scriptBuf);
|
||||||
var scriptType = script.classify();
|
var scriptType = script.classify();
|
||||||
|
|
||||||
if (!fnToSign[scriptType] || scriptType === Script.TX_SCRIPTHASH)
|
if (!fnToSign[scriptType] || scriptType === Script.TX_SCRIPTHASH)
|
||||||
throw new Error('dont know how to sign p2sh script type:'+ script.getRawOutType());
|
throw new Error('dont know how to sign p2sh script type:' + script.getRawOutType());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
input: this._getInputForP2sh(script, input.i),
|
input: this._getInputForP2sh(script, input.i),
|
||||||
txSigHash: this.tx.hashForSignature( script, input.i, this.signhash),
|
txSigHash: this.tx.hashForSignature(script, input.i, this.signhash),
|
||||||
scriptType: script.classify(),
|
scriptType: script.classify(),
|
||||||
scriptBuf: scriptBuf,
|
scriptBuf: scriptBuf,
|
||||||
};
|
};
|
||||||
|
@ -706,9 +718,9 @@ TransactionBuilder.prototype._p2shInput = function(input) {
|
||||||
|
|
||||||
TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txSigHash) {
|
TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txSigHash) {
|
||||||
|
|
||||||
var p2sh = this._p2shInput(input);
|
var p2sh = this._p2shInput(input);
|
||||||
|
|
||||||
var ret = fnToSign[p2sh.scriptType].call(this, walletKeyMap, p2sh.input, p2sh.txSigHash);
|
var ret = fnToSign[p2sh.scriptType].call(this, walletKeyMap, p2sh.input, p2sh.txSigHash);
|
||||||
if (ret && ret.script && ret.signaturesAdded) {
|
if (ret && ret.script && ret.signaturesAdded) {
|
||||||
ret.script = this._addScript(ret.script, p2sh.scriptBuf);
|
ret.script = this._addScript(ret.script, p2sh.scriptBuf);
|
||||||
}
|
}
|
||||||
|
@ -716,8 +728,8 @@ TransactionBuilder.prototype._signScriptHash = function(walletKeyMap, input, txS
|
||||||
};
|
};
|
||||||
|
|
||||||
fnToSign[Script.TX_PUBKEYHASH] = TransactionBuilder.prototype._signPubKeyHash;
|
fnToSign[Script.TX_PUBKEYHASH] = TransactionBuilder.prototype._signPubKeyHash;
|
||||||
fnToSign[Script.TX_PUBKEY] = TransactionBuilder.prototype._signPubKey;
|
fnToSign[Script.TX_PUBKEY] = TransactionBuilder.prototype._signPubKey;
|
||||||
fnToSign[Script.TX_MULTISIG] = TransactionBuilder.prototype._signMultiSig;
|
fnToSign[Script.TX_MULTISIG] = TransactionBuilder.prototype._signMultiSig;
|
||||||
fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
|
fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
|
||||||
|
|
||||||
// sign
|
// sign
|
||||||
|
@ -736,10 +748,10 @@ fnToSign[Script.TX_SCRIPTHASH] = TransactionBuilder.prototype._signScriptHash;
|
||||||
//
|
//
|
||||||
TransactionBuilder.prototype.sign = function(keys) {
|
TransactionBuilder.prototype.sign = function(keys) {
|
||||||
this._checkTx();
|
this._checkTx();
|
||||||
var tx = this.tx,
|
var tx = this.tx,
|
||||||
ins = tx.ins,
|
ins = tx.ins,
|
||||||
l = ins.length,
|
l = ins.length,
|
||||||
walletKeyMap = TransactionBuilder._mapKeys(keys);
|
walletKeyMap = TransactionBuilder._mapKeys(keys);
|
||||||
|
|
||||||
for (var i = 0; i < l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var input = this.inputMap[i];
|
var input = this.inputMap[i];
|
||||||
|
@ -751,7 +763,7 @@ TransactionBuilder.prototype.sign = function(keys) {
|
||||||
if (ret && ret.script) {
|
if (ret && ret.script) {
|
||||||
tx.ins[i].s = ret.script;
|
tx.ins[i].s = ret.script;
|
||||||
if (ret.inputFullySigned) this.inputsSigned++;
|
if (ret.inputFullySigned) this.inputsSigned++;
|
||||||
if (ret.signaturesAdded) this.signaturesAdded +=ret.signaturesAdded;
|
if (ret.signaturesAdded) this.signaturesAdded += ret.signaturesAdded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
|
@ -764,7 +776,7 @@ TransactionBuilder.prototype.sign = function(keys) {
|
||||||
// for generate the input for this call.
|
// for generate the input for this call.
|
||||||
//
|
//
|
||||||
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
TransactionBuilder.prototype.setHashToScriptMap = function(hashToScriptMap) {
|
||||||
this.hashToScriptMap= hashToScriptMap;
|
this.hashToScriptMap = hashToScriptMap;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -792,23 +804,23 @@ TransactionBuilder.prototype.build = function() {
|
||||||
// See `.fromObj`
|
// See `.fromObj`
|
||||||
//
|
//
|
||||||
TransactionBuilder.prototype.toObj = function() {
|
TransactionBuilder.prototype.toObj = function() {
|
||||||
var data = {
|
var data = {
|
||||||
valueInSat : this.valueInSat.toString(),
|
valueInSat: this.valueInSat.toString(),
|
||||||
valueOutSat : this.valueOutSat.toString(),
|
valueOutSat: this.valueOutSat.toString(),
|
||||||
feeSat : this.feeSat.toString(),
|
feeSat: this.feeSat.toString(),
|
||||||
remainderSat : this.remainderSat.toString(),
|
remainderSat: this.remainderSat.toString(),
|
||||||
|
|
||||||
hashToScriptMap : this.hashToScriptMap,
|
hashToScriptMap: this.hashToScriptMap,
|
||||||
selectedUtxos : this.selectedUtxos,
|
selectedUtxos: this.selectedUtxos,
|
||||||
|
|
||||||
inputsSigned : this.inputsSigned,
|
inputsSigned: this.inputsSigned,
|
||||||
signaturesAdded : this.signaturesAdded,
|
signaturesAdded: this.signaturesAdded,
|
||||||
|
|
||||||
signhash : this.signhash,
|
signhash: this.signhash,
|
||||||
spendUnconfirmed : this.spendUnconfirmed,
|
spendUnconfirmed: this.spendUnconfirmed,
|
||||||
};
|
};
|
||||||
if (this.tx) {
|
if (this.tx) {
|
||||||
data.tx =this.tx.serialize().toString('hex');
|
data.tx = this.tx.serialize().toString('hex');
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
@ -821,18 +833,18 @@ TransactionBuilder.prototype.toObj = function() {
|
||||||
|
|
||||||
TransactionBuilder.fromObj = function(data) {
|
TransactionBuilder.fromObj = function(data) {
|
||||||
var b = new TransactionBuilder();
|
var b = new TransactionBuilder();
|
||||||
b.valueInSat = data.valueInSat.toString();
|
b.valueInSat = data.valueInSat.toString();
|
||||||
b.valueOutSat = data.valueOutSat.toString();
|
b.valueOutSat = data.valueOutSat.toString();
|
||||||
b.feeSat = data.feeSat.toString();
|
b.feeSat = data.feeSat.toString();
|
||||||
b.remainderSat = data.remainderSat.toString();
|
b.remainderSat = data.remainderSat.toString();
|
||||||
|
|
||||||
b.hashToScriptMap = data.hashToScriptMap;
|
b.hashToScriptMap = data.hashToScriptMap;
|
||||||
b.selectedUtxos = data.selectedUtxos;
|
b.selectedUtxos = data.selectedUtxos;
|
||||||
|
|
||||||
b.inputsSigned = data.inputsSigned;
|
b.inputsSigned = data.inputsSigned;
|
||||||
b.signaturesAdded = data.signaturesAdded;
|
b.signaturesAdded = data.signaturesAdded;
|
||||||
|
|
||||||
b.signhash = data.signhash;
|
b.signhash = data.signhash;
|
||||||
b.spendUnconfirmed = data.spendUnconfirmed;
|
b.spendUnconfirmed = data.spendUnconfirmed;
|
||||||
|
|
||||||
b._setInputMap();
|
b._setInputMap();
|
||||||
|
@ -840,7 +852,7 @@ TransactionBuilder.fromObj = function(data) {
|
||||||
if (data.tx) {
|
if (data.tx) {
|
||||||
// Tx may have signatures, that are not on txobj
|
// Tx may have signatures, that are not on txobj
|
||||||
var t = new Transaction();
|
var t = new Transaction();
|
||||||
t.parse(new Buffer(data.tx,'hex'));
|
t.parse(new Buffer(data.tx, 'hex'));
|
||||||
b.tx = t;
|
b.tx = t;
|
||||||
}
|
}
|
||||||
return b;
|
return b;
|
||||||
|
@ -848,79 +860,80 @@ TransactionBuilder.fromObj = function(data) {
|
||||||
|
|
||||||
|
|
||||||
TransactionBuilder.prototype._checkMergeability = function(b) {
|
TransactionBuilder.prototype._checkMergeability = function(b) {
|
||||||
var self=this;
|
var self = this;
|
||||||
|
|
||||||
// Builder should have the same params
|
// Builder should have the same params
|
||||||
['valueInSat', 'valueOutSat', 'feeSat', 'remainderSat', 'signhash', 'spendUnconfirmed']
|
['valueInSat', 'valueOutSat', 'feeSat', 'remainderSat', 'signhash', 'spendUnconfirmed']
|
||||||
.forEach(function (k) {
|
.forEach(function(k) {
|
||||||
|
|
||||||
if (self[k].toString() !== b[k].toString()) {
|
if (self[k].toString() !== b[k].toString()) {
|
||||||
throw new Error('mismatch at TransactionBuilder match: '
|
throw new Error('mismatch at TransactionBuilder match: ' + k + ': ' + self[k] + ' vs. ' + b[k]);
|
||||||
+ k + ': ' + self[k] + ' vs. ' + b[k]);
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (self.hashToScriptMap) {
|
if (self.hashToScriptMap) {
|
||||||
var err = 0;
|
var err = 0;
|
||||||
if(! b.hashToScriptMap) err=1;
|
if (!b.hashToScriptMap) err = 1;
|
||||||
Object.keys(self.hashToScriptMap).forEach(function(k) {
|
Object.keys(self.hashToScriptMap).forEach(function(k) {
|
||||||
if (!b.hashToScriptMap[k]) err=1;
|
if (!b.hashToScriptMap[k]) err = 1;
|
||||||
if (self.hashToScriptMap[k] !== b.hashToScriptMap[k]) err=1;
|
if (self.hashToScriptMap[k] !== b.hashToScriptMap[k]) err = 1;
|
||||||
});
|
});
|
||||||
if (err)
|
if (err)
|
||||||
throw new Error('mismatch at TransactionBuilder hashToScriptMap');
|
throw new Error('mismatch at TransactionBuilder hashToScriptMap');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var err = 0, i=0;;
|
var err = 0,
|
||||||
|
i = 0;;
|
||||||
self.selectedUtxos.forEach(function(u) {
|
self.selectedUtxos.forEach(function(u) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
var v=b.selectedUtxos[i++];
|
var v = b.selectedUtxos[i++];
|
||||||
if (!v) err=1;
|
if (!v) err = 1;
|
||||||
// confirmations could differ
|
// confirmations could differ
|
||||||
['address', 'hash', 'scriptPubKey', 'vout', 'amount'].forEach(function(k) {
|
['address', 'hash', 'scriptPubKey', 'vout', 'amount'].forEach(function(k) {
|
||||||
if (u[k] !== v[k])
|
if (u[k] !== v[k])
|
||||||
err=k;
|
err = k;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (err)
|
if (err)
|
||||||
throw new Error('mismatch at TransactionBuilder selectedUtxos #' + i-1+ ' Key:' + err);
|
throw new Error('mismatch at TransactionBuilder selectedUtxos #' + i - 1 + ' Key:' + err);
|
||||||
|
|
||||||
|
|
||||||
err = 0; i=0;;
|
err = 0;
|
||||||
|
i = 0;;
|
||||||
self.inputMap.forEach(function(u) {
|
self.inputMap.forEach(function(u) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
var v=b.inputMap[i++];
|
var v = b.inputMap[i++];
|
||||||
if (!v) err=1;
|
if (!v) err = 1;
|
||||||
// confirmations could differ
|
// confirmations could differ
|
||||||
['address', 'scriptType', 'scriptPubKey', 'i'].forEach(function(k) {
|
['address', 'scriptType', 'scriptPubKey', 'i'].forEach(function(k) {
|
||||||
if (u[k].toString() !== v[k].toString())
|
if (u[k].toString() !== v[k].toString())
|
||||||
err=k;
|
err = k;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (err)
|
if (err)
|
||||||
throw new Error('mismatch at TransactionBuilder inputMap #' + i-1 + ' Key:' + err);
|
throw new Error('mismatch at TransactionBuilder inputMap #' + i - 1 + ' Key:' + err);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO this could be on Script class
|
// TODO this could be on Script class
|
||||||
TransactionBuilder.prototype._mergeInputSigP2sh = function(input,s0,s1) {
|
TransactionBuilder.prototype._mergeInputSigP2sh = function(input, s0, s1) {
|
||||||
var p2sh = this._p2shInput(input);
|
var p2sh = this._p2shInput(input);
|
||||||
var redeemScript = new Script(p2sh.scriptBuf);
|
var redeemScript = new Script(p2sh.scriptBuf);
|
||||||
var pubkeys = redeemScript.capture();
|
var pubkeys = redeemScript.capture();
|
||||||
|
|
||||||
// Look for differences
|
// Look for differences
|
||||||
var s0keys = {};
|
var s0keys = {};
|
||||||
var l = pubkeys.length;
|
var l = pubkeys.length;
|
||||||
for (var j=0; j<l; j++) {
|
for (var j = 0; j < l; j++) {
|
||||||
if ( this._chunkSignedWithKey(s0, p2sh.txSigHash, pubkeys[j]))
|
if (this._chunkSignedWithKey(s0, p2sh.txSigHash, pubkeys[j]))
|
||||||
s0keys[pubkeys[j].toString('hex')] = 1;
|
s0keys[pubkeys[j].toString('hex')] = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
var diff = [];
|
var diff = [];
|
||||||
for (var j=0; j<l; j++) {
|
for (var j = 0; j < l; j++) {
|
||||||
var chunk = this._chunkSignedWithKey(s1, p2sh.txSigHash, pubkeys[j]);
|
var chunk = this._chunkSignedWithKey(s1, p2sh.txSigHash, pubkeys[j]);
|
||||||
var pubHex = pubkeys[j].toString('hex');
|
var pubHex = pubkeys[j].toString('hex');
|
||||||
if (chunk && !s0keys[pubHex]) {
|
if (chunk && !s0keys[pubHex]) {
|
||||||
|
@ -933,10 +946,10 @@ TransactionBuilder.prototype._mergeInputSigP2sh = function(input,s0,s1) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add signatures
|
// Add signatures
|
||||||
for(var j in diff) {
|
for (var j in diff) {
|
||||||
var newSig = diff[j];
|
var newSig = diff[j];
|
||||||
var order = this._getNewSignatureOrder(newSig.prio,s0,p2sh.txSigHash,pubkeys);
|
var order = this._getNewSignatureOrder(newSig.prio, s0, p2sh.txSigHash, pubkeys);
|
||||||
s0.chunks.splice(order+1,0,newSig.chunk);
|
s0.chunks.splice(order + 1, 0, newSig.chunk);
|
||||||
this.signaturesAdded++;
|
this.signaturesAdded++;
|
||||||
}
|
}
|
||||||
s0.updateBuffer();
|
s0.updateBuffer();
|
||||||
|
@ -945,7 +958,7 @@ TransactionBuilder.prototype._mergeInputSigP2sh = function(input,s0,s1) {
|
||||||
|
|
||||||
// TODO this could be on Script class
|
// TODO this could be on Script class
|
||||||
TransactionBuilder.prototype._mergeInputSig = function(index, s0buf, s1buf) {
|
TransactionBuilder.prototype._mergeInputSig = function(index, s0buf, s1buf) {
|
||||||
if (buffertools.compare(s0buf,s1buf) === 0)
|
if (buffertools.compare(s0buf, s1buf) === 0)
|
||||||
return s0buf;
|
return s0buf;
|
||||||
|
|
||||||
var s0 = new Script(s0buf);
|
var s0 = new Script(s0buf);
|
||||||
|
@ -954,53 +967,52 @@ TransactionBuilder.prototype._mergeInputSig = function(index, s0buf, s1buf) {
|
||||||
var l1 = s1.chunks.length;
|
var l1 = s1.chunks.length;
|
||||||
var s0map = {};
|
var s0map = {};
|
||||||
|
|
||||||
if (l0 && l1 && ((l0<2 && l1>2) || (l1<2 && l0>2 )))
|
if (l0 && l1 && ((l0 < 2 && l1 > 2) || (l1 < 2 && l0 > 2)))
|
||||||
throw new Error('TX sig types mismatch in merge');
|
throw new Error('TX sig types mismatch in merge');
|
||||||
|
|
||||||
if ((!l0 && !l1) || ( l0 && !l1) || (!l0 && l1))
|
if ((!l0 && !l1) || (l0 && !l1) || (!l0 && l1))
|
||||||
return s1buf;
|
return s1buf;
|
||||||
|
|
||||||
// Get the pubkeys
|
// Get the pubkeys
|
||||||
var input = this.inputMap[index];
|
var input = this.inputMap[index];
|
||||||
var type = input.scriptPubKey.classify();
|
var type = input.scriptPubKey.classify();
|
||||||
|
|
||||||
//p2pubkey or p2pubkeyhash
|
//p2pubkey or p2pubkeyhash
|
||||||
if (type === Script.TX_PUBKEYHASH || type === Script.TX_PUBKEY) {
|
if (type === Script.TX_PUBKEYHASH || type === Script.TX_PUBKEY) {
|
||||||
log.debug('Merging two signed inputs type:' +
|
log.debug('Merging two signed inputs type:' +
|
||||||
input.scriptPubKey.getRawOutType() + '. Signatures differs. Using the first version.');
|
input.scriptPubKey.getRawOutType() + '. Signatures differs. Using the first version.');
|
||||||
return s0buf;
|
return s0buf;
|
||||||
}
|
} else if (type !== Script.TX_SCRIPTHASH) {
|
||||||
else if (type!== Script.TX_SCRIPTHASH) {
|
|
||||||
// No support for normal multisig or strange txs.
|
// No support for normal multisig or strange txs.
|
||||||
throw new Error('Script type:'+input.scriptPubKey.getRawOutType()+'not supported at #merge');
|
throw new Error('Script type:' + input.scriptPubKey.getRawOutType() + 'not supported at #merge');
|
||||||
}
|
}
|
||||||
return this._mergeInputSigP2sh(input,s0, s1);
|
return this._mergeInputSigP2sh(input, s0, s1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO this could be on Transaction class
|
// TODO this could be on Transaction class
|
||||||
TransactionBuilder.prototype._mergeTx = function(tx) {
|
TransactionBuilder.prototype._mergeTx = function(tx) {
|
||||||
var v0 = this.tx;
|
var v0 = this.tx;
|
||||||
var v1 = tx;
|
var v1 = tx;
|
||||||
|
|
||||||
var l = v0.ins.length;
|
var l = v0.ins.length;
|
||||||
if (l !== v1.ins.length)
|
if (l !== v1.ins.length)
|
||||||
throw new Error('TX in length mismatch in merge');
|
throw new Error('TX in length mismatch in merge');
|
||||||
|
|
||||||
this.inputsSigned =0;
|
this.inputsSigned = 0;
|
||||||
for(var i=0; i<l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
var i0 = v0.ins[i];
|
var i0 = v0.ins[i];
|
||||||
var i1 = v1.ins[i];
|
var i1 = v1.ins[i];
|
||||||
|
|
||||||
if (i0.q !== i1.q)
|
if (i0.q !== i1.q)
|
||||||
throw new Error('TX sequence ins mismatch in merge. Input:',i);
|
throw new Error('TX sequence ins mismatch in merge. Input:', i);
|
||||||
|
|
||||||
if (buffertools.compare(i0.o,i1.o) !== 0)
|
if (buffertools.compare(i0.o, i1.o) !== 0)
|
||||||
throw new Error('TX .o in mismatch in merge. Input:',i);
|
throw new Error('TX .o in mismatch in merge. Input:', i);
|
||||||
|
|
||||||
i0.s=this._mergeInputSig(i, i0.s,i1.s);
|
i0.s = this._mergeInputSig(i, i0.s, i1.s);
|
||||||
|
|
||||||
if (v0.isInputComplete(i)) this.inputsSigned++;
|
if (v0.isInputComplete(i)) this.inputsSigned++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// merge
|
// merge
|
||||||
|
@ -1013,11 +1025,10 @@ TransactionBuilder.prototype.merge = function(b) {
|
||||||
|
|
||||||
// Does this tX have any signature already?
|
// Does this tX have any signature already?
|
||||||
if (this.tx || b.tx) {
|
if (this.tx || b.tx) {
|
||||||
if (this.tx.getNormalizedHash().toString('hex')
|
if (this.tx.getNormalizedHash().toString('hex') !== b.tx.getNormalizedHash().toString('hex'))
|
||||||
!== b.tx.getNormalizedHash().toString('hex'))
|
|
||||||
throw new Error('mismatch at TransactionBuilder NTXID');
|
throw new Error('mismatch at TransactionBuilder NTXID');
|
||||||
|
|
||||||
this._mergeTx(b.tx);
|
this._mergeTx(b.tx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
|
|
||||||
var hex = function(hex) {return new Buffer(hex, 'hex');};
|
var hex = function(hex) {
|
||||||
|
return new Buffer(hex, 'hex');
|
||||||
|
};
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var EncFile = require('../util/EncFile');
|
var EncFile = require('../util/EncFile');
|
||||||
var Address = require('./Address');
|
var Address = require('./Address');
|
||||||
var networks = require('../networks');
|
var networks = require('../networks');
|
||||||
var util = imports.util || require('../util');
|
var util = imports.util || require('../util');
|
||||||
var ENC_METHOD = 'aes-256-cbc';
|
var ENC_METHOD = 'aes-256-cbc';
|
||||||
|
|
||||||
var skeleton = {
|
var skeleton = {
|
||||||
|
@ -37,7 +39,7 @@ function Wallet(cfg) {
|
||||||
|
|
||||||
Wallet.prototype.readSync = function(filename, passphrase) {
|
Wallet.prototype.readSync = function(filename, passphrase) {
|
||||||
this.datastore = EncFile.readJFileSync(ENC_METHOD,
|
this.datastore = EncFile.readJFileSync(ENC_METHOD,
|
||||||
passphrase, filename);
|
passphrase, filename);
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ Wallet.prototype.writeSync = function(filename, passphrase) {
|
||||||
var tmp_fn = filename + ".tmp";
|
var tmp_fn = filename + ".tmp";
|
||||||
|
|
||||||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
|
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
|
||||||
this.datastore);
|
this.datastore);
|
||||||
fs.renameSync(tmp_fn, filename);
|
fs.renameSync(tmp_fn, filename);
|
||||||
|
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
|
@ -56,15 +58,15 @@ Wallet.prototype.setNetwork = function(netname) {
|
||||||
netname = this.datastore.network;
|
netname = this.datastore.network;
|
||||||
|
|
||||||
switch (netname) {
|
switch (netname) {
|
||||||
case "mainnet":
|
case "mainnet":
|
||||||
case "livenet":
|
case "livenet":
|
||||||
this.network = networks.livenet;
|
this.network = networks.livenet;
|
||||||
break;
|
break;
|
||||||
case "testnet":
|
case "testnet":
|
||||||
this.network = networks.testnet;
|
this.network = networks.testnet;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Unsupported network");
|
throw new Error("Unsupported network");
|
||||||
}
|
}
|
||||||
|
|
||||||
// store+canonicalize name
|
// store+canonicalize name
|
||||||
|
@ -105,7 +107,7 @@ Wallet.prototype.expandKey = function(key) {
|
||||||
var b = addr.payload();
|
var b = addr.payload();
|
||||||
var obj = this.findKeyHash(b);
|
var obj = this.findKeyHash(b);
|
||||||
key = obj.pub;
|
key = obj.pub;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,4 +139,3 @@ Wallet.prototype.addScript = function(script) {
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = require('soop')(Wallet);
|
module.exports = require('soop')(Wallet);
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ WalletKey.prototype.fromObj = function(obj) {
|
||||||
this.privKey = new Key();
|
this.privKey = new Key();
|
||||||
if (obj.priv.length == 64) {
|
if (obj.priv.length == 64) {
|
||||||
this.privKey.private = new Buffer(obj.priv, 'hex');
|
this.privKey.private = new Buffer(obj.priv, 'hex');
|
||||||
this.privKey.compressed = typeof obj.compressed === 'undefined'? true: obj.compressed;
|
this.privKey.compressed = typeof obj.compressed === 'undefined' ? true : obj.compressed;
|
||||||
} else {
|
} else {
|
||||||
var priv = new PrivateKey(obj.priv);
|
var priv = new PrivateKey(obj.priv);
|
||||||
priv.validate();
|
priv.validate();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -9,7 +9,13 @@ ECIES.symmetricEncrypt = function(key, iv, message) {
|
||||||
var smessage = sjcl.codec.hex.toBits(message.toString('hex'));
|
var smessage = sjcl.codec.hex.toBits(message.toString('hex'));
|
||||||
|
|
||||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
|
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
|
||||||
var params = {iv: siv, ks: 256, ts: 128, iter: 1000, mode: 'cbc'};
|
var params = {
|
||||||
|
iv: siv,
|
||||||
|
ks: 256,
|
||||||
|
ts: 128,
|
||||||
|
iter: 1000,
|
||||||
|
mode: 'cbc'
|
||||||
|
};
|
||||||
var encrypted = sjcl.encrypt(skey, smessage, params);
|
var encrypted = sjcl.encrypt(skey, smessage, params);
|
||||||
var enchex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(JSON.parse(encrypted).ct));
|
var enchex = sjcl.codec.hex.fromBits(sjcl.codec.base64.toBits(JSON.parse(encrypted).ct));
|
||||||
|
|
||||||
|
@ -24,12 +30,22 @@ ECIES.symmetricDecrypt = function(key, encrypted) {
|
||||||
var skey = sjcl.codec.hex.toBits(key.toString('hex'));
|
var skey = sjcl.codec.hex.toBits(key.toString('hex'));
|
||||||
var iv = encrypted.slice(0, 16);
|
var iv = encrypted.slice(0, 16);
|
||||||
var todecrypt = encrypted.slice(16, encrypted.length);
|
var todecrypt = encrypted.slice(16, encrypted.length);
|
||||||
|
|
||||||
var siv = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(iv.toString('hex')));
|
var siv = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(iv.toString('hex')));
|
||||||
var sct = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(todecrypt.toString('hex')));
|
var sct = sjcl.codec.base64.fromBits(sjcl.codec.hex.toBits(todecrypt.toString('hex')));
|
||||||
|
|
||||||
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
|
sjcl.beware["CBC mode is dangerous because it doesn't protect message integrity."]();
|
||||||
var obj = {iv: siv, v: 1, iter: 1000, ks: 256, ts: 128, mode: 'cbc', adata: '', cipher: 'aes', ct: sct};
|
var obj = {
|
||||||
|
iv: siv,
|
||||||
|
v: 1,
|
||||||
|
iter: 1000,
|
||||||
|
ks: 256,
|
||||||
|
ts: 128,
|
||||||
|
mode: 'cbc',
|
||||||
|
adata: '',
|
||||||
|
cipher: 'aes',
|
||||||
|
ct: sct
|
||||||
|
};
|
||||||
var str = JSON.stringify(obj);
|
var str = JSON.stringify(obj);
|
||||||
|
|
||||||
var decrypted = sjcl.decrypt(skey, str);
|
var decrypted = sjcl.decrypt(skey, str);
|
||||||
|
|
|
@ -12,7 +12,7 @@ var bufferToArray = Key.bufferToArray = function(buffer) {
|
||||||
var ret = [];
|
var ret = [];
|
||||||
|
|
||||||
var l = buffer.length;
|
var l = buffer.length;
|
||||||
for(var i =0; i<l; i++) {
|
for (var i = 0; i < l; i++) {
|
||||||
ret.push(buffer.readUInt8(i));
|
ret.push(buffer.readUInt8(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,15 +20,15 @@ var bufferToArray = Key.bufferToArray = function(buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.defineProperty(Key.prototype, 'public', {
|
Object.defineProperty(Key.prototype, 'public', {
|
||||||
set: function(p){
|
set: function(p) {
|
||||||
if (!Buffer.isBuffer(p) ) {
|
if (!Buffer.isBuffer(p)) {
|
||||||
throw new Error('Arg should be a buffer');
|
throw new Error('Arg should be a buffer');
|
||||||
}
|
}
|
||||||
var type = p[0];
|
var type = p[0];
|
||||||
this._compressed = type!==0x04;
|
this._compressed = type !== 0x04;
|
||||||
this._pub = p;
|
this._pub = p;
|
||||||
},
|
},
|
||||||
get: function(){
|
get: function() {
|
||||||
return this._pub;
|
return this._pub;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -59,9 +59,11 @@ Object.defineProperty(Key.prototype, 'compressed', {
|
||||||
Key.generateSync = function() {
|
Key.generateSync = function() {
|
||||||
var privbuf;
|
var privbuf;
|
||||||
|
|
||||||
while(true) {
|
while (true) {
|
||||||
privbuf = SecureRandom.getRandomBuffer(32);
|
privbuf = SecureRandom.getRandomBuffer(32);
|
||||||
if ((bignum.fromBuffer(privbuf, {size: 32})).cmp(Curve.getN()) < 0)
|
if ((bignum.fromBuffer(privbuf, {
|
||||||
|
size: 32
|
||||||
|
})).cmp(Curve.getN()) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,13 +106,13 @@ Key.prototype.signSync = function(hash) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var getBigRandom = function (limit) {
|
var getBigRandom = function(limit) {
|
||||||
return new BigInteger(limit.bitLength(), rng)
|
return new BigInteger(limit.bitLength(), rng)
|
||||||
.mod(limit.subtract(BigInteger.ONE))
|
.mod(limit.subtract(BigInteger.ONE))
|
||||||
.add(BigInteger.ONE);
|
.add(BigInteger.ONE);
|
||||||
};
|
};
|
||||||
|
|
||||||
var sign = function (hash, priv) {
|
var sign = function(hash, priv) {
|
||||||
var d = priv;
|
var d = priv;
|
||||||
var n = ecparams.getN();
|
var n = ecparams.getN();
|
||||||
var e = BigInteger.fromByteArrayUnsigned(hash);
|
var e = BigInteger.fromByteArrayUnsigned(hash);
|
||||||
|
@ -126,7 +128,7 @@ Key.prototype.signSync = function(hash) {
|
||||||
return serializeSig(r, s);
|
return serializeSig(r, s);
|
||||||
};
|
};
|
||||||
|
|
||||||
var serializeSig = function (r, s) {
|
var serializeSig = function(r, s) {
|
||||||
var rBa = r.toByteArraySigned();
|
var rBa = r.toByteArraySigned();
|
||||||
var sBa = s.toByteArraySigned();
|
var sBa = s.toByteArraySigned();
|
||||||
|
|
||||||
|
@ -185,7 +187,7 @@ Key.prototype.verifySignatureSync = function(hash, sig) {
|
||||||
eck.setPub(bufferToArray(self.public));
|
eck.setPub(bufferToArray(self.public));
|
||||||
eck.setCompressed(self._compressed);
|
eck.setCompressed(self._compressed);
|
||||||
var sigA = bufferToArray(sig);
|
var sigA = bufferToArray(sig);
|
||||||
var ret = eck.verify(bufferToArray(hash),sigA);
|
var ret = eck.verify(bufferToArray(hash), sigA);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var Key = imports.Key || require('./Key');
|
var Key = imports.Key || require('./Key');
|
||||||
var bignum = imports.bignum || require('bignum');
|
var bignum = imports.bignum || require('bignum');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var ECPointFp = require('../../browser/vendor-bundle.js').ECPointFp;
|
var ECPointFp = require('../../browser/vendor-bundle.js').ECPointFp;
|
||||||
|
@ -19,17 +19,25 @@ var Point = function(x, y) {
|
||||||
Point.add = function(p1, p2) {
|
Point.add = function(p1, p2) {
|
||||||
var ecparams = getSECCurveByName('secp256k1');
|
var ecparams = getSECCurveByName('secp256k1');
|
||||||
|
|
||||||
var p1xhex = p1.x.toBuffer({size: 32}).toString('hex');
|
var p1xhex = p1.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p1x = new BigInteger(p1xhex, 16);
|
var p1x = new BigInteger(p1xhex, 16);
|
||||||
var p1yhex = p1.y.toBuffer({size: 32}).toString('hex');
|
var p1yhex = p1.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p1y = new BigInteger(p1yhex, 16);
|
var p1y = new BigInteger(p1yhex, 16);
|
||||||
var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x);
|
var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x);
|
||||||
var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y);
|
var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y);
|
||||||
var p1p = new ECPointFp(ecparams.getCurve(), p1px, p1py);
|
var p1p = new ECPointFp(ecparams.getCurve(), p1px, p1py);
|
||||||
|
|
||||||
var p2xhex = p2.x.toBuffer({size: 32}).toString('hex');
|
var p2xhex = p2.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p2x = new BigInteger(p2xhex, 16);
|
var p2x = new BigInteger(p2xhex, 16);
|
||||||
var p2yhex = p2.y.toBuffer({size: 32}).toString('hex');
|
var p2yhex = p2.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p2y = new BigInteger(p2yhex, 16);
|
var p2y = new BigInteger(p2yhex, 16);
|
||||||
var p2px = new ECFieldElementFp(ecparams.getCurve().getQ(), p2x);
|
var p2px = new ECFieldElementFp(ecparams.getCurve().getQ(), p2x);
|
||||||
var p2py = new ECFieldElementFp(ecparams.getCurve().getQ(), p2y);
|
var p2py = new ECFieldElementFp(ecparams.getCurve().getQ(), p2y);
|
||||||
|
@ -39,11 +47,15 @@ Point.add = function(p1, p2) {
|
||||||
|
|
||||||
var point = new Point();
|
var point = new Point();
|
||||||
var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned());
|
var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned());
|
||||||
point.x = bignum.fromBuffer(pointxbuf, {size: pointxbuf.length});
|
point.x = bignum.fromBuffer(pointxbuf, {
|
||||||
|
size: pointxbuf.length
|
||||||
|
});
|
||||||
assert(pointxbuf.length <= 32);
|
assert(pointxbuf.length <= 32);
|
||||||
var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned());
|
var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned());
|
||||||
assert(pointybuf.length <= 32);
|
assert(pointybuf.length <= 32);
|
||||||
point.y = bignum.fromBuffer(pointybuf, {size: pointybuf.length});
|
point.y = bignum.fromBuffer(pointybuf, {
|
||||||
|
size: pointybuf.length
|
||||||
|
});
|
||||||
|
|
||||||
return point;
|
return point;
|
||||||
};
|
};
|
||||||
|
@ -53,9 +65,13 @@ Point.multiply = function(p1, x) {
|
||||||
|
|
||||||
var ecparams = getSECCurveByName('secp256k1');
|
var ecparams = getSECCurveByName('secp256k1');
|
||||||
|
|
||||||
var p1xhex = p1.x.toBuffer({size: 32}).toString('hex');
|
var p1xhex = p1.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p1x = new BigInteger(p1xhex, 16);
|
var p1x = new BigInteger(p1xhex, 16);
|
||||||
var p1yhex = p1.y.toBuffer({size: 32}).toString('hex');
|
var p1yhex = p1.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
}).toString('hex');
|
||||||
var p1y = new BigInteger(p1yhex, 16);
|
var p1y = new BigInteger(p1yhex, 16);
|
||||||
var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x);
|
var p1px = new ECFieldElementFp(ecparams.getCurve().getQ(), p1x);
|
||||||
var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y);
|
var p1py = new ECFieldElementFp(ecparams.getCurve().getQ(), p1y);
|
||||||
|
@ -65,11 +81,15 @@ Point.multiply = function(p1, x) {
|
||||||
|
|
||||||
var point = new Point();
|
var point = new Point();
|
||||||
var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned());
|
var pointxbuf = new Buffer(p.getX().toBigInteger().toByteArrayUnsigned());
|
||||||
point.x = bignum.fromBuffer(pointxbuf, {size: pointxbuf.length});
|
point.x = bignum.fromBuffer(pointxbuf, {
|
||||||
|
size: pointxbuf.length
|
||||||
|
});
|
||||||
assert(pointxbuf.length <= 32);
|
assert(pointxbuf.length <= 32);
|
||||||
var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned());
|
var pointybuf = new Buffer(p.getY().toBigInteger().toByteArrayUnsigned());
|
||||||
assert(pointybuf.length <= 32);
|
assert(pointybuf.length <= 32);
|
||||||
point.y = bignum.fromBuffer(pointybuf, {size: pointybuf.length});
|
point.y = bignum.fromBuffer(pointybuf, {
|
||||||
|
size: pointybuf.length
|
||||||
|
});
|
||||||
|
|
||||||
return point;
|
return point;
|
||||||
};
|
};
|
||||||
|
@ -77,15 +97,23 @@ Point.multiply = function(p1, x) {
|
||||||
//convert the public key of a Key into a Point
|
//convert the public key of a Key into a Point
|
||||||
Point.fromUncompressedPubKey = function(pubkey) {
|
Point.fromUncompressedPubKey = function(pubkey) {
|
||||||
var point = new Point();
|
var point = new Point();
|
||||||
point.x = bignum.fromBuffer((new Buffer(pubkey)).slice(1, 33), {size: 32});
|
point.x = bignum.fromBuffer((new Buffer(pubkey)).slice(1, 33), {
|
||||||
point.y = bignum.fromBuffer((new Buffer(pubkey)).slice(33, 65), {size: 32});
|
size: 32
|
||||||
|
});
|
||||||
|
point.y = bignum.fromBuffer((new Buffer(pubkey)).slice(33, 65), {
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
return point;
|
return point;
|
||||||
};
|
};
|
||||||
|
|
||||||
//convert the Point into the Key containing a compressed public key
|
//convert the Point into the Key containing a compressed public key
|
||||||
Point.prototype.toUncompressedPubKey = function() {
|
Point.prototype.toUncompressedPubKey = function() {
|
||||||
var xbuf = this.x.toBuffer({size: 32});
|
var xbuf = this.x.toBuffer({
|
||||||
var ybuf = this.y.toBuffer({size: 32});
|
size: 32
|
||||||
|
});
|
||||||
|
var ybuf = this.y.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var prefix = new Buffer([0x04]);
|
var prefix = new Buffer([0x04]);
|
||||||
var pub = Buffer.concat([prefix, xbuf, ybuf]);
|
var pub = Buffer.concat([prefix, xbuf, ybuf]);
|
||||||
return pub;
|
return pub;
|
||||||
|
|
|
@ -6,8 +6,7 @@ var SecureRandom = imports.SecureRandom || require('../SecureRandom');
|
||||||
var Key = imports.Key || require('../Key');
|
var Key = imports.Key || require('../Key');
|
||||||
|
|
||||||
// http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
|
// http://en.wikipedia.org/wiki/Integrated_Encryption_Scheme
|
||||||
var ECIES = function() {
|
var ECIES = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
ECIES.encryptObj = function(pubkey, message, r, iv) {
|
ECIES.encryptObj = function(pubkey, message, r, iv) {
|
||||||
var ecies = new ECIES();
|
var ecies = new ECIES();
|
||||||
|
@ -42,7 +41,9 @@ ECIES.decryptObj = function(ecies) {
|
||||||
var c = ecies.c;
|
var c = ecies.c;
|
||||||
var d = ecies.d;
|
var d = ecies.d;
|
||||||
var P = Point.multiply(R, kB);
|
var P = Point.multiply(R, kB);
|
||||||
var S = P.x.toBuffer({size: 32});
|
var S = P.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
var buf = ECIES.kdf(S);
|
var buf = ECIES.kdf(S);
|
||||||
var kE = ecies.kE = buf.slice(0, 32);
|
var kE = ecies.kE = buf.slice(0, 32);
|
||||||
var kM = ecies.kM = buf.slice(32, 64);
|
var kM = ecies.kM = buf.slice(32, 64);
|
||||||
|
@ -98,7 +99,9 @@ ECIES.prototype.getSfromPubkey = function() {
|
||||||
key2.compressed = false;
|
key2.compressed = false;
|
||||||
var KBP = Point.fromUncompressedPubKey(key2.public);
|
var KBP = Point.fromUncompressedPubKey(key2.public);
|
||||||
this.P = Point.multiply(KBP, this.r);
|
this.P = Point.multiply(KBP, this.r);
|
||||||
this.S = this.P.x.toBuffer({size: 32});
|
this.S = this.P.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
return this.S;
|
return this.S;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +109,9 @@ ECIES.prototype.getSfromPrivkey = function() {
|
||||||
var R = this.R;
|
var R = this.R;
|
||||||
var kB = this.kB;
|
var kB = this.kB;
|
||||||
var SP = Point.multiply(R, kB);
|
var SP = Point.multiply(R, kB);
|
||||||
var S = SP.x.toBuffer({size: 32});
|
var S = SP.x.toBuffer({
|
||||||
|
size: 32
|
||||||
|
});
|
||||||
return S;
|
return S;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
var imports = require('soop');
|
var imports = require('soop');
|
||||||
|
|
||||||
var SecureRandom = function() {
|
var SecureRandom = function() {};
|
||||||
};
|
|
||||||
|
|
||||||
/* secure random bytes that sometimes throws an error due to lack of entropy */
|
/* secure random bytes that sometimes throws an error due to lack of entropy */
|
||||||
SecureRandom.getRandomBuffer = function() {};
|
SecureRandom.getRandomBuffer = function() {};
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
var Put = require('bufferput');
|
var Put = require('bufferput');
|
||||||
var buffertools = require('buffertools');
|
var buffertools = require('buffertools');
|
||||||
var hex = function(hex) {return new Buffer(hex, 'hex');};
|
var hex = function(hex) {
|
||||||
|
return new Buffer(hex, 'hex');
|
||||||
|
};
|
||||||
|
|
||||||
exports.livenet = {
|
exports.livenet = {
|
||||||
name: 'livenet',
|
name: 'livenet',
|
||||||
|
|
|
@ -2,15 +2,15 @@
|
||||||
* Simple synchronous parser based on node-binary.
|
* Simple synchronous parser based on node-binary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
function Parser(buffer)
|
|
||||||
{
|
function Parser(buffer) {
|
||||||
this.subject = buffer;
|
this.subject = buffer;
|
||||||
this.pos = 0;
|
this.pos = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser.prototype.buffer = function buffer(len) {
|
Parser.prototype.buffer = function buffer(len) {
|
||||||
var buf = this.subject.slice(this.pos, this.pos+len);
|
var buf = this.subject.slice(this.pos, this.pos + len);
|
||||||
this.pos += len;
|
this.pos += len;
|
||||||
return buf;
|
return buf;
|
||||||
};
|
};
|
||||||
|
@ -32,7 +32,7 @@ Parser.prototype.search = function search(needle) {
|
||||||
for (var i = this.pos, l = this.subject.length; i < l; i++) {
|
for (var i = this.pos, l = this.subject.length; i < l; i++) {
|
||||||
if (this.subject[i] == needle) {
|
if (this.subject[i] == needle) {
|
||||||
len = i - this.pos;
|
len = i - this.pos;
|
||||||
this.pos = i+1;
|
this.pos = i + 1;
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,13 +41,13 @@ Parser.prototype.search = function search(needle) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like search(), but returns the skipped bytes
|
* Like search(), but returns the skipped bytes
|
||||||
*/
|
*/
|
||||||
Parser.prototype.scan = function scan(needle) {
|
Parser.prototype.scan = function scan(needle) {
|
||||||
var startPos = this.pos;
|
var startPos = this.pos;
|
||||||
var len = this.search(needle);
|
var len = this.search(needle);
|
||||||
if (len !== -1) {
|
if (len !== -1) {
|
||||||
return this.subject.slice(startPos, startPos+len);
|
return this.subject.slice(startPos, startPos + len);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('No match');
|
throw new Error('No match');
|
||||||
}
|
}
|
||||||
|
@ -58,16 +58,16 @@ Parser.prototype.eof = function eof() {
|
||||||
};
|
};
|
||||||
|
|
||||||
// convert byte strings to unsigned little endian numbers
|
// convert byte strings to unsigned little endian numbers
|
||||||
function decodeLEu (bytes) {
|
function decodeLEu(bytes) {
|
||||||
var acc = 0;
|
var acc = 0;
|
||||||
for (var i = 0; i < bytes.length; i++) {
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
acc += Math.pow(256,i) * bytes[i];
|
acc += Math.pow(256, i) * bytes[i];
|
||||||
}
|
}
|
||||||
return acc;
|
return acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert byte strings to unsigned big endian numbers
|
// convert byte strings to unsigned big endian numbers
|
||||||
function decodeBEu (bytes) {
|
function decodeBEu(bytes) {
|
||||||
var acc = 0;
|
var acc = 0;
|
||||||
for (var i = 0; i < bytes.length; i++) {
|
for (var i = 0; i < bytes.length; i++) {
|
||||||
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
|
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
|
||||||
|
@ -76,7 +76,7 @@ function decodeBEu (bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert byte strings to signed big endian numbers
|
// convert byte strings to signed big endian numbers
|
||||||
function decodeBEs (bytes) {
|
function decodeBEs(bytes) {
|
||||||
var val = decodeBEu(bytes);
|
var val = decodeBEu(bytes);
|
||||||
if ((bytes[0] & 0x80) == 0x80) {
|
if ((bytes[0] & 0x80) == 0x80) {
|
||||||
val -= Math.pow(256, bytes.length);
|
val -= Math.pow(256, bytes.length);
|
||||||
|
@ -85,7 +85,7 @@ function decodeBEs (bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert byte strings to signed little endian numbers
|
// convert byte strings to signed little endian numbers
|
||||||
function decodeLEs (bytes) {
|
function decodeLEs(bytes) {
|
||||||
var val = decodeLEu(bytes);
|
var val = decodeLEu(bytes);
|
||||||
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
|
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
|
||||||
val -= Math.pow(256, bytes.length);
|
val -= Math.pow(256, bytes.length);
|
||||||
|
@ -94,51 +94,44 @@ function decodeLEs (bytes) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDecoder(len, fn) {
|
function getDecoder(len, fn) {
|
||||||
return function () {
|
return function() {
|
||||||
var buf = this.buffer(len);
|
var buf = this.buffer(len);
|
||||||
return fn(buf);
|
return fn(buf);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
[ 1, 2, 4, 8 ].forEach(function (bytes) {
|
[1, 2, 4, 8].forEach(function(bytes) {
|
||||||
var bits = bytes * 8;
|
var bits = bytes * 8;
|
||||||
|
|
||||||
Parser.prototype['word' + bits + 'le']
|
Parser.prototype['word' + bits + 'le'] = Parser.prototype['word' + bits + 'lu'] = getDecoder(bytes, decodeLEu);
|
||||||
= Parser.prototype['word' + bits + 'lu']
|
|
||||||
= getDecoder(bytes, decodeLEu);
|
Parser.prototype['word' + bits + 'ls'] = getDecoder(bytes, decodeLEs);
|
||||||
|
|
||||||
Parser.prototype['word' + bits + 'ls']
|
Parser.prototype['word' + bits + 'be'] = Parser.prototype['word' + bits + 'bu'] = getDecoder(bytes, decodeBEu);
|
||||||
= getDecoder(bytes, decodeLEs);
|
|
||||||
|
Parser.prototype['word' + bits + 'bs'] = getDecoder(bytes, decodeBEs);
|
||||||
Parser.prototype['word' + bits + 'be']
|
|
||||||
= Parser.prototype['word' + bits + 'bu']
|
|
||||||
= getDecoder(bytes, decodeBEu);
|
|
||||||
|
|
||||||
Parser.prototype['word' + bits + 'bs']
|
|
||||||
= getDecoder(bytes, decodeBEs);
|
|
||||||
|
|
||||||
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
|
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
|
||||||
Parser.prototype.word8s = Parser.prototype.word8bs;
|
Parser.prototype.word8s = Parser.prototype.word8bs;
|
||||||
});
|
});
|
||||||
|
|
||||||
Parser.prototype.varInt = function ()
|
Parser.prototype.varInt = function() {
|
||||||
{
|
|
||||||
var firstByte = this.word8();
|
var firstByte = this.word8();
|
||||||
switch (firstByte) {
|
switch (firstByte) {
|
||||||
case 0xFD:
|
case 0xFD:
|
||||||
return this.word16le();
|
return this.word16le();
|
||||||
|
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
return this.word32le();
|
return this.word32le();
|
||||||
|
|
||||||
case 0xFF:
|
case 0xFF:
|
||||||
return this.word64le();
|
return this.word64le();
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return firstByte;
|
return firstByte;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Parser.prototype.varStr = function () {
|
Parser.prototype.varStr = function() {
|
||||||
var len = this.varInt();
|
var len = this.varInt();
|
||||||
return this.buffer(len);
|
return this.buffer(len);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var crypto = require('crypto');
|
var crypto = require('crypto');
|
||||||
|
|
||||||
exports.readFileSync = function(enc_method, enc_passphrase, filename)
|
exports.readFileSync = function(enc_method, enc_passphrase, filename) {
|
||||||
{
|
|
||||||
// read entire file into memory
|
// read entire file into memory
|
||||||
var fileData = fs.readFileSync(filename, 'binary');
|
var fileData = fs.readFileSync(filename, 'binary');
|
||||||
if (fileData.length < 32)
|
if (fileData.length < 32)
|
||||||
|
@ -28,14 +26,12 @@ exports.readFileSync = function(enc_method, enc_passphrase, filename)
|
||||||
return dec;
|
return dec;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.readJFileSync = function(enc_method, enc_passphrase, filename)
|
exports.readJFileSync = function(enc_method, enc_passphrase, filename) {
|
||||||
{
|
|
||||||
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
|
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
|
||||||
return JSON.parse(raw);
|
return JSON.parse(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.writeFileSync = function(enc_method, enc_passphrase, filename, data)
|
exports.writeFileSync = function(enc_method, enc_passphrase, filename, data) {
|
||||||
{
|
|
||||||
// encrypt to ciphertext
|
// encrypt to ciphertext
|
||||||
var cipher = crypto.createCipher(enc_method, enc_passphrase);
|
var cipher = crypto.createCipher(enc_method, enc_passphrase);
|
||||||
var crypted = cipher.update(data, 'binary', 'binary');
|
var crypted = cipher.update(data, 'binary', 'binary');
|
||||||
|
@ -51,9 +47,7 @@ exports.writeFileSync = function(enc_method, enc_passphrase, filename, data)
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.writeJFileSync = function(enc_method, enc_passphrase, filename, obj)
|
exports.writeJFileSync = function(enc_method, enc_passphrase, filename, obj) {
|
||||||
{
|
|
||||||
var raw = JSON.stringify(obj);
|
var raw = JSON.stringify(obj);
|
||||||
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
|
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ var base58 = imports.base58 || require('../lib/Base58').base58Check;
|
||||||
// new EncodedData(<version>, <20-byte-hash>)
|
// new EncodedData(<version>, <20-byte-hash>)
|
||||||
function EncodedData(data, encoding) {
|
function EncodedData(data, encoding) {
|
||||||
this.data = data;
|
this.data = data;
|
||||||
if(!encoding && (typeof data == 'string')) {
|
if (!encoding && (typeof data == 'string')) {
|
||||||
this.__proto__ = this.encodings['base58'];
|
this.__proto__ = this.encodings['base58'];
|
||||||
} else {
|
} else {
|
||||||
this.__proto__ = this.encodings[encoding || 'binary'];
|
this.__proto__ = this.encodings[encoding || 'binary'];
|
||||||
|
@ -18,7 +18,7 @@ function EncodedData(data, encoding) {
|
||||||
|
|
||||||
// get or set the encoding used (transforms data)
|
// get or set the encoding used (transforms data)
|
||||||
EncodedData.prototype.encoding = function(encoding) {
|
EncodedData.prototype.encoding = function(encoding) {
|
||||||
if(encoding && (encoding != this._encoding)) {
|
if (encoding && (encoding != this._encoding)) {
|
||||||
this.data = this.as(encoding);
|
this.data = this.as(encoding);
|
||||||
this.__proto__ = this.encodings[encoding];
|
this.__proto__ = this.encodings[encoding];
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ EncodedData.prototype.withEncoding = function(encoding) {
|
||||||
|
|
||||||
// answer the data in the given encoding
|
// answer the data in the given encoding
|
||||||
EncodedData.prototype.as = function(encoding) {
|
EncodedData.prototype.as = function(encoding) {
|
||||||
if(!encodings[encoding]) throw new Error('invalid encoding');
|
if (!encodings[encoding]) throw new Error('invalid encoding');
|
||||||
return this.converters[encoding].call(this);
|
return this.converters[encoding].call(this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ EncodedData.prototype.isValid = function() {
|
||||||
try {
|
try {
|
||||||
this.validate();
|
this.validate();
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -61,7 +61,7 @@ EncodedData.prototype.isValid = function() {
|
||||||
try {
|
try {
|
||||||
this.validate();
|
this.validate();
|
||||||
return true;
|
return true;
|
||||||
} catch(e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -129,10 +129,12 @@ var encodings = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var no_conversion = function() {return this.data;};
|
var no_conversion = function() {
|
||||||
for(var k in encodings) {
|
return this.data;
|
||||||
if(encodings.hasOwnProperty(k)){
|
};
|
||||||
if(!encodings[k].converters[k])
|
for (var k in encodings) {
|
||||||
|
if (encodings.hasOwnProperty(k)) {
|
||||||
|
if (!encodings[k].converters[k])
|
||||||
encodings[k].converters[k] = no_conversion;
|
encodings[k].converters[k] = no_conversion;
|
||||||
encodings[k]._encoding = k;
|
encodings[k]._encoding = k;
|
||||||
}
|
}
|
||||||
|
@ -140,10 +142,10 @@ for(var k in encodings) {
|
||||||
|
|
||||||
EncodedData.applyEncodingsTo = function(aClass) {
|
EncodedData.applyEncodingsTo = function(aClass) {
|
||||||
var tmp = {};
|
var tmp = {};
|
||||||
for(var k in encodings) {
|
for (var k in encodings) {
|
||||||
var enc = encodings[k];
|
var enc = encodings[k];
|
||||||
var obj = {};
|
var obj = {};
|
||||||
for(var j in enc) {
|
for (var j in enc) {
|
||||||
obj[j] = enc[j];
|
obj[j] = enc[j];
|
||||||
}
|
}
|
||||||
obj.__proto__ = aClass.prototype;
|
obj.__proto__ = aClass.prototype;
|
||||||
|
@ -155,4 +157,3 @@ EncodedData.applyEncodingsTo = function(aClass) {
|
||||||
EncodedData.applyEncodingsTo(EncodedData);
|
EncodedData.applyEncodingsTo(EncodedData);
|
||||||
|
|
||||||
module.exports = require('soop')(EncodedData);
|
module.exports = require('soop')(EncodedData);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
var imports = require('soop').imports();
|
var imports = require('soop').imports();
|
||||||
var base58 = imports.base58 || require('../lib/Base58').base58Check;
|
var base58 = imports.base58 || require('../lib/Base58').base58Check;
|
||||||
var parent = imports.parent || require('./EncodedData');
|
var parent = imports.parent || require('./EncodedData');
|
||||||
|
|
||||||
|
|
||||||
function VersionedData(version, payload) {
|
function VersionedData(version, payload) {
|
||||||
if(typeof version != 'number') {
|
if (typeof version != 'number') {
|
||||||
VersionedData.super(this, arguments);
|
VersionedData.super(this, arguments);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
@ -19,8 +19,10 @@ parent.applyEncodingsTo(VersionedData);
|
||||||
|
|
||||||
// get or set the version data (the first byte of the address)
|
// get or set the version data (the first byte of the address)
|
||||||
VersionedData.prototype.version = function(num) {
|
VersionedData.prototype.version = function(num) {
|
||||||
if(num || (num === 0)) {
|
if (num || (num === 0)) {
|
||||||
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
|
this.doAsBinary(function() {
|
||||||
|
this.data.writeUInt8(num, 0);
|
||||||
|
});
|
||||||
return num;
|
return num;
|
||||||
}
|
}
|
||||||
return this.as('binary').readUInt8(0);
|
return this.as('binary').readUInt8(0);
|
||||||
|
@ -28,8 +30,10 @@ VersionedData.prototype.version = function(num) {
|
||||||
|
|
||||||
// get or set the payload data (as a Buffer object)
|
// get or set the payload data (as a Buffer object)
|
||||||
VersionedData.prototype.payload = function(data) {
|
VersionedData.prototype.payload = function(data) {
|
||||||
if(data) {
|
if (data) {
|
||||||
this.doAsBinary(function() {data.copy(this.data,1);});
|
this.doAsBinary(function() {
|
||||||
|
data.copy(this.data, 1);
|
||||||
|
});
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
return this.as('binary').slice(1);
|
return this.as('binary').slice(1);
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used during transcation verification when a source txout is missing.
|
* Used during transcation verification when a source txout is missing.
|
||||||
*
|
*
|
||||||
|
@ -9,8 +8,8 @@ function MissingSourceError(msg, missingTxHash) {
|
||||||
// TODO: Since this happens in normal operation, perhaps we should
|
// TODO: Since this happens in normal operation, perhaps we should
|
||||||
// avoid generating a whole stack trace.
|
// avoid generating a whole stack trace.
|
||||||
Error.call(this);
|
Error.call(this);
|
||||||
// This is not compatible with firefox.
|
// This is not compatible with firefox.
|
||||||
// Error.captureStackTrace(this, arguments.callee);
|
// Error.captureStackTrace(this, arguments.callee);
|
||||||
this.message = msg;
|
this.message = msg;
|
||||||
this.missingTxHash = missingTxHash;
|
this.missingTxHash = missingTxHash;
|
||||||
this.name = 'MissingSourceError';
|
this.name = 'MissingSourceError';
|
||||||
|
@ -32,8 +31,8 @@ function VerificationError(msg, missingTxHash) {
|
||||||
// avoid generating a whole stack trace.
|
// avoid generating a whole stack trace.
|
||||||
Error.call(this);
|
Error.call(this);
|
||||||
|
|
||||||
// This is not compatible with firefox.
|
// This is not compatible with firefox.
|
||||||
// Error.captureStackTrace(this, arguments.callee);
|
// Error.captureStackTrace(this, arguments.callee);
|
||||||
this.message = msg;
|
this.message = msg;
|
||||||
this.missingTxHash = missingTxHash;
|
this.missingTxHash = missingTxHash;
|
||||||
this.name = 'VerificationError';
|
this.name = 'VerificationError';
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
module.exports = require('./util');
|
module.exports = require('./util');
|
||||||
|
|
23
util/log.js
23
util/log.js
|
@ -6,13 +6,28 @@ var cl = function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
var loggers = {
|
var loggers = {
|
||||||
none: {info: noop, warn: noop, err: noop, debug: noop},
|
none: {
|
||||||
normal: {info: cl, warn: cl, err: cl, debug: noop},
|
info: noop,
|
||||||
debug: {info: cl, warn: cl, err: cl, debug: cl},
|
warn: noop,
|
||||||
|
err: noop,
|
||||||
|
debug: noop
|
||||||
|
},
|
||||||
|
normal: {
|
||||||
|
info: cl,
|
||||||
|
warn: cl,
|
||||||
|
err: cl,
|
||||||
|
debug: noop
|
||||||
|
},
|
||||||
|
debug: {
|
||||||
|
info: cl,
|
||||||
|
warn: cl,
|
||||||
|
err: cl,
|
||||||
|
debug: cl
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
var config = require('../config');
|
var config = require('../config');
|
||||||
if(config.log) {
|
if (config.log) {
|
||||||
module.exports = config.log;
|
module.exports = config.log;
|
||||||
} else {
|
} else {
|
||||||
module.exports = loggers[config.logger || 'normal'];
|
module.exports = loggers[config.logger || 'normal'];
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
|
|
||||||
// current time, in seconds
|
// current time, in seconds
|
||||||
exports.curtime = function curtime()
|
exports.curtime = function curtime() {
|
||||||
{
|
|
||||||
return Math.round(Date.now() / 1000);
|
return Math.round(Date.now() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ var sha512 = exports.sha512 = function(data) {
|
||||||
return new Buffer(crypto.createHash('sha512').update(data).digest('binary'), 'binary');
|
return new Buffer(crypto.createHash('sha512').update(data).digest('binary'), 'binary');
|
||||||
};
|
};
|
||||||
|
|
||||||
var sha512hmac = exports.sha512hmac = function (data, key) {
|
var sha512hmac = exports.sha512hmac = function(data, key) {
|
||||||
if (inBrowser) {
|
if (inBrowser) {
|
||||||
var skey = sjcl.codec.hex.toBits(key.toString('hex'));
|
var skey = sjcl.codec.hex.toBits(key.toString('hex'));
|
||||||
var sdata = sjcl.codec.hex.toBits(data.toString('hex'));
|
var sdata = sjcl.codec.hex.toBits(data.toString('hex'));
|
||||||
|
@ -41,7 +41,7 @@ var sha512hmac = exports.sha512hmac = function (data, key) {
|
||||||
return hash;
|
return hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
var ripe160 = exports.ripe160 = function (data) {
|
var ripe160 = exports.ripe160 = function(data) {
|
||||||
if (!Buffer.isBuffer(data)) {
|
if (!Buffer.isBuffer(data)) {
|
||||||
throw new Error('arg should be a buffer');
|
throw new Error('arg should be a buffer');
|
||||||
}
|
}
|
||||||
|
@ -360,12 +360,12 @@ var decodeDiffBits = exports.decodeDiffBits = function(diffBits, asBigInt) {
|
||||||
|
|
||||||
var target = bignum(diffBits & 0xffffff);
|
var target = bignum(diffBits & 0xffffff);
|
||||||
/*
|
/*
|
||||||
* shiftLeft is not implemented on the bignum browser
|
* shiftLeft is not implemented on the bignum browser
|
||||||
*
|
*
|
||||||
* target = target.shiftLeft(8*((diffBits >>> 24) - 3));
|
* target = target.shiftLeft(8*((diffBits >>> 24) - 3));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var mov = 8*((diffBits >>> 24) - 3);
|
var mov = 8 * ((diffBits >>> 24) - 3);
|
||||||
while (mov-- > 0)
|
while (mov-- > 0)
|
||||||
target = target.mul(2);
|
target = target.mul(2);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue