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:
Ryan X. Charles 2014-06-23 10:57:02 -07:00
parent bba0945581
commit ca67786a77
60 changed files with 2756 additions and 2642 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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') {
} }
//// ////

View File

@ -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') {
} }
//// ////

View File

@ -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 = {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 + '"');
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() {};

View File

@ -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',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1 +1 @@
module.exports = require('./util'); module.exports = require('./util');

View File

@ -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'];

View File

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

View File

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