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