replace tabs with 2 spaces using "expand"
This commit is contained in:
parent
c24ae73cf5
commit
f35c03544b
12
Block.js
12
Block.js
@ -39,12 +39,12 @@ function spec(b) {
|
|||||||
Block.prototype.getHeader = function getHeader() {
|
Block.prototype.getHeader = function getHeader() {
|
||||||
var buf = new Buffer(80);
|
var buf = new Buffer(80);
|
||||||
var ofs = 0;
|
var ofs = 0;
|
||||||
buf.writeUInt32LE(this.version, ofs); ofs += 4;
|
buf.writeUInt32LE(this.version, ofs); ofs += 4;
|
||||||
this.prev_hash.copy(buf, ofs); ofs += 32;
|
this.prev_hash.copy(buf, ofs); ofs += 32;
|
||||||
this.merkle_root.copy(buf, ofs); ofs += 32;
|
this.merkle_root.copy(buf, ofs); ofs += 32;
|
||||||
buf.writeUInt32LE(this.timestamp, ofs); ofs += 4;
|
buf.writeUInt32LE(this.timestamp, ofs); ofs += 4;
|
||||||
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
|
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
|
||||||
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
|
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
|
||||||
return buf;
|
return buf;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
180
Bloom.js
180
Bloom.js
@ -1,116 +1,116 @@
|
|||||||
require('classtool');
|
require('classtool');
|
||||||
|
|
||||||
function ClassSpec(b) {
|
function ClassSpec(b) {
|
||||||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||||
var MAX_HASH_FUNCS = 50;
|
var MAX_HASH_FUNCS = 50;
|
||||||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
|
||||||
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
|
||||||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
|
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
|
||||||
|
|
||||||
function Bloom() {
|
function Bloom() {
|
||||||
this.data = '';
|
this.data = '';
|
||||||
this.hashFuncs = 0;
|
this.hashFuncs = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
function ROTL32(x, r) {
|
function ROTL32(x, r) {
|
||||||
return (x << r) | (x >> (32 - r));
|
return (x << r) | (x >> (32 - r));
|
||||||
};
|
};
|
||||||
|
|
||||||
function getBlockU32(blockIdx, data) {
|
function getBlockU32(blockIdx, data) {
|
||||||
var idx = blockIdx * 4;
|
var idx = blockIdx * 4;
|
||||||
var v = (data[idx + 0] << (0 * 8)) |
|
var v = (data[idx + 0] << (0 * 8)) |
|
||||||
(data[idx + 1] << (1 * 8)) |
|
(data[idx + 1] << (1 * 8)) |
|
||||||
(data[idx + 2] << (2 * 8)) |
|
(data[idx + 2] << (2 * 8)) |
|
||||||
(data[idx + 3] << (3 * 8));
|
(data[idx + 3] << (3 * 8));
|
||||||
return v;
|
return v;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bloom.prototype.hash = function(hashNum, data) {
|
Bloom.prototype.hash = function(hashNum, data) {
|
||||||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
|
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
|
||||||
var c1 = 0xcc9e2d51;
|
var c1 = 0xcc9e2d51;
|
||||||
var c2 = 0x1b873593;
|
var c2 = 0x1b873593;
|
||||||
var nBlocks = data.length / 4;
|
var nBlocks = data.length / 4;
|
||||||
|
|
||||||
// data body
|
// data body
|
||||||
for (var i = -nBlocks; i; i++) {
|
for (var i = -nBlocks; i; i++) {
|
||||||
var k1 = getBlockU32(i);
|
var k1 = getBlockU32(i);
|
||||||
|
|
||||||
k1 *= c1;
|
k1 *= c1;
|
||||||
k1 = ROTLF32(k1, 15);
|
k1 = ROTLF32(k1, 15);
|
||||||
k1 *= c2;
|
k1 *= c2;
|
||||||
|
|
||||||
h1 ^= k1;
|
h1 ^= k1;
|
||||||
h1 = ROTFL(h1, 13);
|
h1 = ROTFL(h1, 13);
|
||||||
h1 = h1 * 5 + 0xe6546b64;
|
h1 = h1 * 5 + 0xe6546b64;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tail (trailing 1-3 bytes)
|
// tail (trailing 1-3 bytes)
|
||||||
var tail = data.slice(nBlocks * 4);
|
var tail = data.slice(nBlocks * 4);
|
||||||
|
|
||||||
var k1 = 0;
|
var k1 = 0;
|
||||||
|
|
||||||
switch (data.length & 3) {
|
switch (data.length & 3) {
|
||||||
case 3: k1 ^= tail[2] << 16;
|
case 3: k1 ^= tail[2] << 16;
|
||||||
case 2: k1 ^= tail[1] << 8;
|
case 2: k1 ^= tail[1] << 8;
|
||||||
case 1: k1 ^= tail[0];
|
case 1: k1 ^= tail[0];
|
||||||
k1 *= c1;
|
k1 *= c1;
|
||||||
k1 = ROTL32(k1, 15);
|
k1 = ROTL32(k1, 15);
|
||||||
k1 *= c2;
|
k1 *= c2;
|
||||||
h1 ^= k1;
|
h1 ^= k1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finalize
|
// finalize
|
||||||
h1 ^= data.length;
|
h1 ^= data.length;
|
||||||
h1 ^= h1 >> 16;
|
h1 ^= h1 >> 16;
|
||||||
h1 *= 0x85ebca6b;
|
h1 *= 0x85ebca6b;
|
||||||
h1 ^= h1 >> 13;
|
h1 ^= h1 >> 13;
|
||||||
h1 *= 0xc2b2ae35;
|
h1 *= 0xc2b2ae35;
|
||||||
h1 ^= h1 >> 16;
|
h1 ^= h1 >> 16;
|
||||||
|
|
||||||
return h1 % (this.data.length * 8);
|
return h1 % (this.data.length * 8);
|
||||||
};
|
};
|
||||||
|
|
||||||
Bloom.prototype.insert = function(data) {
|
Bloom.prototype.insert = function(data) {
|
||||||
for (var i = 0; i < this.hashFuncs; i++) {
|
for (var i = 0; i < this.hashFuncs; i++) {
|
||||||
var index = this.hash(i, data);
|
var index = this.hash(i, data);
|
||||||
this.data[index >> 3] |= bit_mask[7 & index];
|
this.data[index >> 3] |= bit_mask[7 & index];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Bloom.prototype.contains = function(data) {
|
Bloom.prototype.contains = function(data) {
|
||||||
for (var i = 0; i < this.hashFuncs; i++) {
|
for (var i = 0; i < this.hashFuncs; i++) {
|
||||||
var index = this.hash(i, data);
|
var index = this.hash(i, data);
|
||||||
if (!(this.data[index >> 3] & bit_mask[7 & index]))
|
if (!(this.data[index >> 3] & bit_mask[7 & index]))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Bloom.prototype.sizeOk = function() {
|
Bloom.prototype.sizeOk = function() {
|
||||||
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
|
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
|
||||||
this.hashFuncs <= MAX_HASH_FUNCS;
|
this.hashFuncs <= MAX_HASH_FUNCS;
|
||||||
};
|
};
|
||||||
|
|
||||||
function toInt(v) {
|
function toInt(v) {
|
||||||
return ~~v;
|
return ~~v;
|
||||||
}
|
}
|
||||||
|
|
||||||
function min(a, b) {
|
function min(a, b) {
|
||||||
if (a < b)
|
if (a < b)
|
||||||
return a;
|
return a;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
Bloom.prototype.init = function(elements, FPRate) {
|
Bloom.prototype.init = function(elements, FPRate) {
|
||||||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
|
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
|
||||||
MAX_BLOOM_FILTER_SIZE * 8) / 8;
|
MAX_BLOOM_FILTER_SIZE * 8) / 8;
|
||||||
this.data[filterSize] = 0;
|
this.data[filterSize] = 0;
|
||||||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
|
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
|
||||||
MAX_HASH_FUNCS);
|
MAX_HASH_FUNCS);
|
||||||
};
|
};
|
||||||
|
|
||||||
return Bloom;
|
return Bloom;
|
||||||
};
|
};
|
||||||
module.defineClass(ClassSpec);
|
module.defineClass(ClassSpec);
|
||||||
|
|
||||||
|
|||||||
@ -443,8 +443,8 @@ function spec(b) {
|
|||||||
data.headers = [];
|
data.headers = [];
|
||||||
for (i = 0; i < data.count; i++) {
|
for (i = 0; i < data.count; i++) {
|
||||||
var header = new Block();
|
var header = new Block();
|
||||||
header.parse(parser);
|
header.parse(parser);
|
||||||
data.headers.push(header);
|
data.headers.push(header);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -474,7 +474,7 @@ function spec(b) {
|
|||||||
lock_time: tx.lock_time,
|
lock_time: tx.lock_time,
|
||||||
ins: tx.ins,
|
ins: tx.ins,
|
||||||
outs: tx.outs,
|
outs: tx.outs,
|
||||||
tx: tx,
|
tx: tx,
|
||||||
};
|
};
|
||||||
|
|
||||||
case 'getblocks':
|
case 'getblocks':
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
exports.intFromCompact = function(c)
|
exports.intFromCompact = function(c)
|
||||||
{
|
{
|
||||||
var bytes = ((c >>> 24) & 0xff) >>> 0;
|
var bytes = ((c >>> 24) & 0xff) >>> 0;
|
||||||
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
|
var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0;
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
8
SIN.js
8
SIN.js
@ -11,16 +11,16 @@ function ClassSpec(b) {
|
|||||||
};
|
};
|
||||||
this.data = new Buffer(1 + 1 + payload.length);
|
this.data = new Buffer(1 + 1 + payload.length);
|
||||||
this.__proto__ = this.encodings['binary'];
|
this.__proto__ = this.encodings['binary'];
|
||||||
this.prefix(0x0F); // SIN magic number, in numberspace
|
this.prefix(0x0F); // SIN magic number, in numberspace
|
||||||
this.type(type);
|
this.type(type);
|
||||||
this.payload(payload);
|
this.payload(payload);
|
||||||
};
|
};
|
||||||
SIN.superclass = superclass;
|
SIN.superclass = superclass;
|
||||||
superclass.applyEncodingsTo(SIN);
|
superclass.applyEncodingsTo(SIN);
|
||||||
|
|
||||||
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
|
||||||
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
|
||||||
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
|
||||||
|
|
||||||
// get or set the prefix data (the first byte of the address)
|
// get or set the prefix data (the first byte of the address)
|
||||||
SIN.prototype.prefix = function(num) {
|
SIN.prototype.prefix = function(num) {
|
||||||
|
|||||||
60
SINKey.js
60
SINKey.js
@ -1,43 +1,43 @@
|
|||||||
require('classtool');
|
require('classtool');
|
||||||
|
|
||||||
function ClassSpec(b) {
|
function ClassSpec(b) {
|
||||||
var coinUtil = require('./util/util');
|
var coinUtil = require('./util/util');
|
||||||
var timeUtil = require('./util/time');
|
var timeUtil = require('./util/time');
|
||||||
var KeyModule = require('./Key');
|
var KeyModule = require('./Key');
|
||||||
var SIN = require('./SIN').class();
|
var SIN = require('./SIN').class();
|
||||||
|
|
||||||
function SINKey(cfg) {
|
function SINKey(cfg) {
|
||||||
if (typeof cfg != 'object')
|
if (typeof cfg != 'object')
|
||||||
cfg = {};
|
cfg = {};
|
||||||
|
|
||||||
this.created = cfg.created;
|
this.created = cfg.created;
|
||||||
this.privKey = cfg.privKey;
|
this.privKey = cfg.privKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
SINKey.prototype.generate = function() {
|
SINKey.prototype.generate = function() {
|
||||||
this.privKey = KeyModule.Key.generateSync();
|
this.privKey = KeyModule.Key.generateSync();
|
||||||
this.created = timeUtil.curtime();
|
this.created = timeUtil.curtime();
|
||||||
};
|
};
|
||||||
|
|
||||||
SINKey.prototype.pubkeyHash = function() {
|
SINKey.prototype.pubkeyHash = function() {
|
||||||
return coinUtil.sha256ripe160(this.privKey.public);
|
return coinUtil.sha256ripe160(this.privKey.public);
|
||||||
};
|
};
|
||||||
|
|
||||||
SINKey.prototype.storeObj = function() {
|
SINKey.prototype.storeObj = function() {
|
||||||
var pubKey = this.privKey.public.toString('hex');
|
var pubKey = this.privKey.public.toString('hex');
|
||||||
var pubKeyHash = this.pubkeyHash();
|
var pubKeyHash = this.pubkeyHash();
|
||||||
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
|
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
|
||||||
var obj = {
|
var obj = {
|
||||||
created: this.created,
|
created: this.created,
|
||||||
priv: this.privKey.private.toString('hex'),
|
priv: this.privKey.private.toString('hex'),
|
||||||
pub: pubKey,
|
pub: pubKey,
|
||||||
sin: sin.toString(),
|
sin: sin.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
return SINKey;
|
return SINKey;
|
||||||
};
|
};
|
||||||
module.defineClass(ClassSpec);
|
module.defineClass(ClassSpec);
|
||||||
|
|
||||||
|
|||||||
106
Script.js
106
Script.js
@ -84,42 +84,42 @@ function spec(b) {
|
|||||||
Script.prototype.isP2SH = function ()
|
Script.prototype.isP2SH = function ()
|
||||||
{
|
{
|
||||||
return (this.chunks.length == 3 &&
|
return (this.chunks.length == 3 &&
|
||||||
this.chunks[0] == OP_HASH160 &&
|
this.chunks[0] == OP_HASH160 &&
|
||||||
Buffer.isBuffer(this.chunks[1]) &&
|
Buffer.isBuffer(this.chunks[1]) &&
|
||||||
this.chunks[1].length == 20 &&
|
this.chunks[1].length == 20 &&
|
||||||
this.chunks[2] == OP_EQUAL);
|
this.chunks[2] == OP_EQUAL);
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.isPubkey = function ()
|
Script.prototype.isPubkey = function ()
|
||||||
{
|
{
|
||||||
return (this.chunks.length == 2 &&
|
return (this.chunks.length == 2 &&
|
||||||
Buffer.isBuffer(this.chunks[0]) &&
|
Buffer.isBuffer(this.chunks[0]) &&
|
||||||
this.chunks[1] == OP_CHECKSIG);
|
this.chunks[1] == OP_CHECKSIG);
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.isPubkeyHash = function ()
|
Script.prototype.isPubkeyHash = function ()
|
||||||
{
|
{
|
||||||
return (this.chunks.length == 5 &&
|
return (this.chunks.length == 5 &&
|
||||||
this.chunks[0] == OP_DUP &&
|
this.chunks[0] == OP_DUP &&
|
||||||
this.chunks[1] == OP_HASH160 &&
|
this.chunks[1] == OP_HASH160 &&
|
||||||
Buffer.isBuffer(this.chunks[2]) &&
|
Buffer.isBuffer(this.chunks[2]) &&
|
||||||
this.chunks[2].length == 20 &&
|
this.chunks[2].length == 20 &&
|
||||||
this.chunks[3] == OP_EQUALVERIFY &&
|
this.chunks[3] == OP_EQUALVERIFY &&
|
||||||
this.chunks[4] == OP_CHECKSIG);
|
this.chunks[4] == OP_CHECKSIG);
|
||||||
};
|
};
|
||||||
|
|
||||||
function isSmallIntOp(opcode)
|
function isSmallIntOp(opcode)
|
||||||
{
|
{
|
||||||
return ((opcode == OP_0) ||
|
return ((opcode == OP_0) ||
|
||||||
((opcode >= OP_1) && (opcode <= OP_16)));
|
((opcode >= OP_1) && (opcode <= OP_16)));
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.isMultiSig = function ()
|
Script.prototype.isMultiSig = function ()
|
||||||
{
|
{
|
||||||
return (this.chunks.length > 3 &&
|
return (this.chunks.length > 3 &&
|
||||||
isSmallIntOp(this.chunks[0]) &&
|
isSmallIntOp(this.chunks[0]) &&
|
||||||
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
|
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
|
||||||
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
|
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.finishedMultiSig = function()
|
Script.prototype.finishedMultiSig = function()
|
||||||
@ -166,60 +166,60 @@ function spec(b) {
|
|||||||
// is this a script form we know?
|
// is this a script form we know?
|
||||||
Script.prototype.classify = function ()
|
Script.prototype.classify = function ()
|
||||||
{
|
{
|
||||||
if (this.isPubkeyHash())
|
if (this.isPubkeyHash())
|
||||||
return TX_PUBKEYHASH;
|
return TX_PUBKEYHASH;
|
||||||
if (this.isP2SH())
|
if (this.isP2SH())
|
||||||
return TX_SCRIPTHASH;
|
return TX_SCRIPTHASH;
|
||||||
if (this.isMultiSig())
|
if (this.isMultiSig())
|
||||||
return TX_MULTISIG;
|
return TX_MULTISIG;
|
||||||
if (this.isPubkey())
|
if (this.isPubkey())
|
||||||
return TX_PUBKEY;
|
return TX_PUBKEY;
|
||||||
return TX_UNKNOWN;
|
return TX_UNKNOWN;
|
||||||
};
|
};
|
||||||
|
|
||||||
// extract useful data items from known scripts
|
// extract useful data items from known scripts
|
||||||
Script.prototype.capture = function ()
|
Script.prototype.capture = function ()
|
||||||
{
|
{
|
||||||
var txType = this.classify();
|
var txType = this.classify();
|
||||||
var res = [];
|
var res = [];
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case TX_PUBKEY:
|
case TX_PUBKEY:
|
||||||
res.push(this.chunks[0]);
|
res.push(this.chunks[0]);
|
||||||
break;
|
break;
|
||||||
case TX_PUBKEYHASH:
|
case TX_PUBKEYHASH:
|
||||||
res.push(this.chunks[2]);
|
res.push(this.chunks[2]);
|
||||||
break;
|
break;
|
||||||
case TX_MULTISIG:
|
case TX_MULTISIG:
|
||||||
for (var i = 1; i < (this.chunks.length - 2); i++)
|
for (var i = 1; i < (this.chunks.length - 2); i++)
|
||||||
res.push(this.chunks[i]);
|
res.push(this.chunks[i]);
|
||||||
break;
|
break;
|
||||||
case TX_SCRIPTHASH:
|
case TX_SCRIPTHASH:
|
||||||
res.push(this.chunks[1]);
|
res.push(this.chunks[1]);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TX_UNKNOWN:
|
case TX_UNKNOWN:
|
||||||
default:
|
default:
|
||||||
// do nothing
|
// do nothing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
// return first extracted data item from script
|
// return first extracted data item from script
|
||||||
Script.prototype.captureOne = function ()
|
Script.prototype.captureOne = function ()
|
||||||
{
|
{
|
||||||
var arr = this.capture();
|
var arr = this.capture();
|
||||||
return arr[0];
|
return arr[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
Script.prototype.getOutType = function ()
|
Script.prototype.getOutType = function ()
|
||||||
{
|
{
|
||||||
var txType = this.classify();
|
var txType = this.classify();
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case TX_PUBKEY: return 'Pubkey';
|
case TX_PUBKEY: return 'Pubkey';
|
||||||
case TX_PUBKEYHASH: return 'Address';
|
case TX_PUBKEYHASH: return 'Address';
|
||||||
default: return 'Strange';
|
default: return 'Strange';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -446,7 +446,7 @@ function spec(b) {
|
|||||||
var script = new Script();
|
var script = new Script();
|
||||||
script.writeN(n_required);
|
script.writeN(n_required);
|
||||||
keys.forEach(function(key) {
|
keys.forEach(function(key) {
|
||||||
script.writeBytes(key);
|
script.writeBytes(key);
|
||||||
});
|
});
|
||||||
script.writeN(keys.length);
|
script.writeN(keys.length);
|
||||||
script.writeOp(OP_CHECKMULTISIG);
|
script.writeOp(OP_CHECKMULTISIG);
|
||||||
|
|||||||
@ -918,85 +918,85 @@ function spec(b) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy)
|
hashType, opts, callback, si, siCopy)
|
||||||
{
|
{
|
||||||
if (siCopy.stack.length == 0) {
|
if (siCopy.stack.length == 0) {
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback(null, castBool(siCopy.stackBack()));
|
callback(null, castBool(siCopy.stackBack()));
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy)
|
hashType, opts, callback, si, siCopy)
|
||||||
{
|
{
|
||||||
if (si.stack.length == 0) {
|
if (si.stack.length == 0) {
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (castBool(si.stackBack()) == false) {
|
if (castBool(si.stackBack()) == false) {
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if not P2SH, we're done
|
// if not P2SH, we're done
|
||||||
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
|
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scriptSig.isPushOnly()) {
|
if (!scriptSig.isPushOnly()) {
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.notEqual(siCopy.length, 0);
|
assert.notEqual(siCopy.length, 0);
|
||||||
|
|
||||||
var subscript = new Script(siCopy.stackPop());
|
var subscript = new Script(siCopy.stackPop());
|
||||||
|
|
||||||
ok = true;
|
ok = true;
|
||||||
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
|
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
|
||||||
if (err)
|
if (err)
|
||||||
callback(err);
|
callback(err);
|
||||||
else
|
else
|
||||||
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy);
|
hashType, opts, callback, si, siCopy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy)
|
hashType, opts, callback, si, siCopy)
|
||||||
{
|
{
|
||||||
if (opts.verifyP2SH) {
|
if (opts.verifyP2SH) {
|
||||||
si.stack.forEach(function(item) {
|
si.stack.forEach(function(item) {
|
||||||
siCopy.stack.push(item);
|
siCopy.stack.push(item);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
|
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
|
||||||
if (err)
|
if (err)
|
||||||
callback(err);
|
callback(err);
|
||||||
else
|
else
|
||||||
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy);
|
hashType, opts, callback, si, siCopy);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptInterpreter.verifyFull =
|
ScriptInterpreter.verifyFull =
|
||||||
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
|
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
|
||||||
opts, callback)
|
opts, callback)
|
||||||
{
|
{
|
||||||
var si = new ScriptInterpreter();
|
var si = new ScriptInterpreter();
|
||||||
var siCopy = new ScriptInterpreter();
|
var siCopy = new ScriptInterpreter();
|
||||||
|
|
||||||
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
|
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
|
||||||
if (err)
|
if (err)
|
||||||
callback(err);
|
callback(err);
|
||||||
else
|
else
|
||||||
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
|
||||||
hashType, opts, callback, si, siCopy);
|
hashType, opts, callback, si, siCopy);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var checkSig = ScriptInterpreter.checkSig =
|
var checkSig = ScriptInterpreter.checkSig =
|
||||||
|
|||||||
202
Sign.js
202
Sign.js
@ -1,133 +1,133 @@
|
|||||||
|
|
||||||
function signOne(hash, addrStr, keys)
|
function signOne(hash, addrStr, keys)
|
||||||
{
|
{
|
||||||
var keyObj = keys[addrStr];
|
var keyObj = keys[addrStr];
|
||||||
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
|
var rawPrivKey = new Buffer(keyObj.priv, 'hex');
|
||||||
var key = new KeyModule.Key();
|
var key = new KeyModule.Key();
|
||||||
key.private = rawPrivKey;
|
key.private = rawPrivKey;
|
||||||
var signature = key.signSync(hash);
|
var signature = key.signSync(hash);
|
||||||
|
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
function signTxIn(nIn, tx, txInputs, network, keys, scripts)
|
function signTxIn(nIn, tx, txInputs, network, keys, scripts)
|
||||||
{
|
{
|
||||||
// locate TX input needing a signature
|
// locate TX input needing a signature
|
||||||
var txin = tx.ins[nIn];
|
var txin = tx.ins[nIn];
|
||||||
var scriptSig = txin.getScript();
|
var scriptSig = txin.getScript();
|
||||||
|
|
||||||
// locate TX output, within txInputs
|
// locate TX output, within txInputs
|
||||||
var txoutHash = txin.getOutpointHash();
|
var txoutHash = txin.getOutpointHash();
|
||||||
if (!(txoutHash in txInputs))
|
if (!(txoutHash in txInputs))
|
||||||
throw new Error("signTxIn missing input hash");
|
throw new Error("signTxIn missing input hash");
|
||||||
var txFrom = txInputs[txoutHash];
|
var txFrom = txInputs[txoutHash];
|
||||||
var txoutIndex = txin.getOutpointIndex();
|
var txoutIndex = txin.getOutpointIndex();
|
||||||
if (txFrom.outs.length >= txoutIndex)
|
if (txFrom.outs.length >= txoutIndex)
|
||||||
throw new Error("signTxIn missing input index");
|
throw new Error("signTxIn missing input index");
|
||||||
var txout = txFrom.outs[txoutIndex];
|
var txout = txFrom.outs[txoutIndex];
|
||||||
var scriptPubKey = txout.getScript();
|
var scriptPubKey = txout.getScript();
|
||||||
|
|
||||||
// detect type of transaction, and extract useful elements
|
// detect type of transaction, and extract useful elements
|
||||||
var txType = scriptPubKey.classify();
|
var txType = scriptPubKey.classify();
|
||||||
if (txType == TX_UNKNOWN)
|
if (txType == TX_UNKNOWN)
|
||||||
throw new Error("unknown TX type");
|
throw new Error("unknown TX type");
|
||||||
var scriptData = scriptPubKey.capture();
|
var scriptData = scriptPubKey.capture();
|
||||||
|
|
||||||
// if P2SH, lookup the script
|
// if P2SH, lookup the script
|
||||||
var subscriptRaw = undefined;
|
var subscriptRaw = undefined;
|
||||||
var subscript = undefined;
|
var subscript = undefined;
|
||||||
var subType = undefined;
|
var subType = undefined;
|
||||||
var subData = undefined;
|
var subData = undefined;
|
||||||
if (txType == TX_SCRIPTHASH) {
|
if (txType == TX_SCRIPTHASH) {
|
||||||
var addr = new Address(network.addressScript, scriptData[0]);
|
var addr = new Address(network.addressScript, scriptData[0]);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in scripts))
|
if (!(addrStr in scripts))
|
||||||
throw new Error("unknown script hash address");
|
throw new Error("unknown script hash address");
|
||||||
|
|
||||||
subscriptRaw = new Buffer(scripts[addrStr], 'hex');
|
subscriptRaw = new Buffer(scripts[addrStr], 'hex');
|
||||||
subscript = new Script(subscriptRaw);
|
subscript = new Script(subscriptRaw);
|
||||||
subType = subscript.classify();
|
subType = subscript.classify();
|
||||||
if (subType == TX_UNKNOWN)
|
if (subType == TX_UNKNOWN)
|
||||||
throw new Error("unknown subscript TX type");
|
throw new Error("unknown subscript TX type");
|
||||||
subData = subscript.capture();
|
subData = subscript.capture();
|
||||||
}
|
}
|
||||||
|
|
||||||
var hash = tx.hashForSignature(scriptPubKey, i, 0);
|
var hash = tx.hashForSignature(scriptPubKey, i, 0);
|
||||||
|
|
||||||
switch (txType) {
|
switch (txType) {
|
||||||
case TX_PUBKEY:
|
case TX_PUBKEY:
|
||||||
// already signed
|
// already signed
|
||||||
if (scriptSig.chunks.length > 0)
|
if (scriptSig.chunks.length > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var pubkeyhash = util.sha256ripe160(scriptData[0]);
|
var pubkeyhash = util.sha256ripe160(scriptData[0]);
|
||||||
var addr = new Address(network.addressPubkey, pubkeyhash);
|
var addr = new Address(network.addressPubkey, pubkeyhash);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in keys))
|
if (!(addrStr in keys))
|
||||||
throw new Error("unknown pubkey");
|
throw new Error("unknown pubkey");
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
var signature = signOne(hash, addrStr, keys);
|
||||||
scriptSig.writeBytes(signature);
|
scriptSig.writeBytes(signature);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TX_PUBKEYHASH:
|
case TX_PUBKEYHASH:
|
||||||
// already signed
|
// already signed
|
||||||
if (scriptSig.chunks.length > 0)
|
if (scriptSig.chunks.length > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var addr = new Address(network.addressPubkey, scriptData[0]);
|
var addr = new Address(network.addressPubkey, scriptData[0]);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in keys))
|
if (!(addrStr in keys))
|
||||||
throw new Error("unknown pubkey hash address");
|
throw new Error("unknown pubkey hash address");
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
var signature = signOne(hash, addrStr, keys);
|
||||||
scriptSig.writeBytes(signature);
|
scriptSig.writeBytes(signature);
|
||||||
scriptSig.writeBytes(key.public);
|
scriptSig.writeBytes(key.public);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TX_SCRIPTHASH:
|
case TX_SCRIPTHASH:
|
||||||
// already signed
|
// already signed
|
||||||
if (scriptSig.chunks.length > 0)
|
if (scriptSig.chunks.length > 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var addr = new Address(network.addressPubkey, subData[0]);
|
var addr = new Address(network.addressPubkey, subData[0]);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in keys))
|
if (!(addrStr in keys))
|
||||||
throw new Error("unknown script(pubkey hash) address");
|
throw new Error("unknown script(pubkey hash) address");
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
var signature = signOne(hash, addrStr, keys);
|
||||||
scriptSig.writeBytes(signature);
|
scriptSig.writeBytes(signature);
|
||||||
scriptSig.writeBytes(key.public);
|
scriptSig.writeBytes(key.public);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TX_MULTISIG:
|
case TX_MULTISIG:
|
||||||
while (scriptSig.chunks.length < scriptData.length) {
|
while (scriptSig.chunks.length < scriptData.length) {
|
||||||
scriptSig.writeBytes(util.EMPTY_BUFFER);
|
scriptSig.writeBytes(util.EMPTY_BUFFER);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < scriptData.length; i++) {
|
for (var i = 0; i < scriptData.length; i++) {
|
||||||
// skip already signed
|
// skip already signed
|
||||||
if (scriptSig.chunks[i].length > 0)
|
if (scriptSig.chunks[i].length > 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
|
var pubkeyhash = util.sha256ripe160(scriptSig.chunks[i]);
|
||||||
var addr = new Address(network.addressPubkey, pubkeyhash);
|
var addr = new Address(network.addressPubkey, pubkeyhash);
|
||||||
var addrStr = addr.toString();
|
var addrStr = addr.toString();
|
||||||
if (!(addrStr in keys))
|
if (!(addrStr in keys))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var signature = signOne(hash, addrStr, keys);
|
var signature = signOne(hash, addrStr, keys);
|
||||||
scriptSig.chunks[i] = signature;
|
scriptSig.chunks[i] = signature;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (txtype == TX_SCRIPTHASH)
|
if (txtype == TX_SCRIPTHASH)
|
||||||
scriptSig.writeBytes(subscriptRaw);
|
scriptSig.writeBytes(subscriptRaw);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts)
|
exports.Transaction = function Transaction(tx, txInputs, network, keys, scripts)
|
||||||
{
|
{
|
||||||
for (var i = 0; i < tx.ins.length; i++)
|
for (var i = 0; i < tx.ins.length; i++)
|
||||||
signTxIn(i, tx, txInputs, network, keys, scripts);
|
signTxIn(i, tx, txInputs, network, keys, scripts);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
224
Wallet.js
224
Wallet.js
@ -2,141 +2,141 @@ require('classtool');
|
|||||||
var hex = function(hex) {return new Buffer(hex, 'hex');};
|
var hex = function(hex) {return new Buffer(hex, 'hex');};
|
||||||
|
|
||||||
function ClassSpec(b) {
|
function ClassSpec(b) {
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var EncFile = require('./util/EncFile');
|
var EncFile = require('./util/EncFile');
|
||||||
var Address = require('./Address').class();
|
var Address = require('./Address').class();
|
||||||
var networks = require('./networks');
|
var networks = require('./networks');
|
||||||
var util = b.util || require('./util/util');
|
var util = b.util || require('./util/util');
|
||||||
var ENC_METHOD = 'aes-256-cbc';
|
var ENC_METHOD = 'aes-256-cbc';
|
||||||
|
|
||||||
var skeleton = {
|
var skeleton = {
|
||||||
client: 'libcoin',
|
client: 'libcoin',
|
||||||
client_version: '0.0.1',
|
client_version: '0.0.1',
|
||||||
network: 'testnet',
|
network: 'testnet',
|
||||||
version: 1,
|
version: 1,
|
||||||
best_hash: null,
|
best_hash: null,
|
||||||
best_height: -1,
|
best_height: -1,
|
||||||
keys: [],
|
keys: [],
|
||||||
sin: {},
|
sin: {},
|
||||||
scripts: {},
|
scripts: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
function Wallet(cfg) {
|
function Wallet(cfg) {
|
||||||
if (typeof cfg !== 'object')
|
if (typeof cfg !== 'object')
|
||||||
cfg = {};
|
cfg = {};
|
||||||
|
|
||||||
// deep copy (no references)
|
// deep copy (no references)
|
||||||
if (cfg.datastore)
|
if (cfg.datastore)
|
||||||
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
|
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
|
||||||
else
|
else
|
||||||
this.datastore = JSON.parse(JSON.stringify(skeleton));
|
this.datastore = JSON.parse(JSON.stringify(skeleton));
|
||||||
|
|
||||||
this.network = undefined;
|
this.network = undefined;
|
||||||
this.dirty = cfg.dirty || true;
|
this.dirty = cfg.dirty || true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.readSync = function(filename, passphrase) {
|
Wallet.prototype.readSync = function(filename, passphrase) {
|
||||||
this.datastore = EncFile.readJFileSync(ENC_METHOD,
|
this.datastore = EncFile.readJFileSync(ENC_METHOD,
|
||||||
passphrase, filename);
|
passphrase, filename);
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.writeSync = function(filename, passphrase) {
|
Wallet.prototype.writeSync = function(filename, passphrase) {
|
||||||
var tmp_fn = filename + ".tmp";
|
var tmp_fn = filename + ".tmp";
|
||||||
|
|
||||||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
|
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
|
||||||
this.datastore);
|
this.datastore);
|
||||||
fs.renameSync(tmp_fn, filename);
|
fs.renameSync(tmp_fn, filename);
|
||||||
|
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.setNetwork = function(netname) {
|
Wallet.prototype.setNetwork = function(netname) {
|
||||||
if (!netname)
|
if (!netname)
|
||||||
netname = this.datastore.network;
|
netname = this.datastore.network;
|
||||||
|
|
||||||
switch (netname) {
|
switch (netname) {
|
||||||
case "mainnet":
|
case "mainnet":
|
||||||
case "livenet":
|
case "livenet":
|
||||||
this.network = networks.livenet;
|
this.network = networks.livenet;
|
||||||
break;
|
break;
|
||||||
case "testnet":
|
case "testnet":
|
||||||
this.network = networks.testnet;
|
this.network = networks.testnet;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Unsupported network");
|
throw new Error("Unsupported network");
|
||||||
}
|
}
|
||||||
|
|
||||||
// store+canonicalize name
|
// store+canonicalize name
|
||||||
this.datastore['network'] = this.network.name;
|
this.datastore['network'] = this.network.name;
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.addKey = function(wkey) {
|
Wallet.prototype.addKey = function(wkey) {
|
||||||
this.datastore.keys.push(wkey);
|
this.datastore.keys.push(wkey);
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.addSIN = function(sinObj) {
|
Wallet.prototype.addSIN = function(sinObj) {
|
||||||
this.datastore.sin[sinObj.sin] = sinObj;
|
this.datastore.sin[sinObj.sin] = sinObj;
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.findKeyHash = function(pubKeyHash) {
|
Wallet.prototype.findKeyHash = function(pubKeyHash) {
|
||||||
var pkhStr = pubKeyHash.toString();
|
var pkhStr = pubKeyHash.toString();
|
||||||
|
|
||||||
for (var i = 0; i < this.datastore.keys.length; i++) {
|
for (var i = 0; i < this.datastore.keys.length; i++) {
|
||||||
var obj = this.datastore.keys[i];
|
var obj = this.datastore.keys[i];
|
||||||
var addrStr = obj.addr;
|
var addrStr = obj.addr;
|
||||||
var addr = new Address(addrStr);
|
var addr = new Address(addrStr);
|
||||||
if (addr.payload().toString() == pkhStr)
|
if (addr.payload().toString() == pkhStr)
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.expandKey = function(key) {
|
Wallet.prototype.expandKey = function(key) {
|
||||||
var addr = new Address(key);
|
var addr = new Address(key);
|
||||||
var isAddr = true;
|
var isAddr = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
addr.validate();
|
addr.validate();
|
||||||
var b = addr.payload();
|
var b = addr.payload();
|
||||||
var obj = this.findKeyHash(b);
|
var obj = this.findKeyHash(b);
|
||||||
key = obj.pub;
|
key = obj.pub;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
var re = /^[a-fA-F0-9]+$/;
|
var re = /^[a-fA-F0-9]+$/;
|
||||||
if (!key.match(re))
|
if (!key.match(re))
|
||||||
throw new Error("Unknown key type");
|
throw new Error("Unknown key type");
|
||||||
return hex(key);
|
return hex(key);
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.expandKeys = function(keys) {
|
Wallet.prototype.expandKeys = function(keys) {
|
||||||
var res = [];
|
var res = [];
|
||||||
var us = this;
|
var us = this;
|
||||||
keys.forEach(function(key) {
|
keys.forEach(function(key) {
|
||||||
var expKey = us.expandKey(key);
|
var expKey = us.expandKey(key);
|
||||||
res.push(expKey);
|
res.push(expKey);
|
||||||
});
|
});
|
||||||
return res;
|
return res;
|
||||||
};
|
};
|
||||||
|
|
||||||
Wallet.prototype.addScript = function(script) {
|
Wallet.prototype.addScript = function(script) {
|
||||||
var buf = script.getBuffer();
|
var buf = script.getBuffer();
|
||||||
var hash = util.sha256ripe160(buf);
|
var hash = util.sha256ripe160(buf);
|
||||||
var addr = new Address(this.network.addressScript, hash);
|
var addr = new Address(this.network.addressScript, hash);
|
||||||
var addrStr = addr.as('base58');
|
var addrStr = addr.as('base58');
|
||||||
this.datastore.scripts[addrStr] = buf.toString('hex');
|
this.datastore.scripts[addrStr] = buf.toString('hex');
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|
||||||
return addrStr;
|
return addrStr;
|
||||||
};
|
};
|
||||||
|
|
||||||
return Wallet;
|
return Wallet;
|
||||||
};
|
};
|
||||||
module.defineClass(ClassSpec);
|
module.defineClass(ClassSpec);
|
||||||
|
|
||||||
|
|||||||
84
WalletKey.js
84
WalletKey.js
@ -1,53 +1,53 @@
|
|||||||
require('classtool');
|
require('classtool');
|
||||||
|
|
||||||
function ClassSpec(b) {
|
function ClassSpec(b) {
|
||||||
var coinUtil = require('./util/util');
|
var coinUtil = require('./util/util');
|
||||||
var timeUtil = require('./util/time');
|
var timeUtil = require('./util/time');
|
||||||
var KeyModule = require('./Key');
|
var KeyModule = require('./Key');
|
||||||
var PrivateKey = require('./PrivateKey').class();
|
var PrivateKey = require('./PrivateKey').class();
|
||||||
var Address = require('./Address').class();
|
var Address = require('./Address').class();
|
||||||
|
|
||||||
function WalletKey(cfg) {
|
function WalletKey(cfg) {
|
||||||
this.network = cfg.network; // required
|
this.network = cfg.network; // required
|
||||||
this.created = cfg.created;
|
this.created = cfg.created;
|
||||||
this.privKey = cfg.privKey;
|
this.privKey = cfg.privKey;
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletKey.prototype.generate = function() {
|
WalletKey.prototype.generate = function() {
|
||||||
this.privKey = KeyModule.Key.generateSync();
|
this.privKey = KeyModule.Key.generateSync();
|
||||||
this.created = timeUtil.curtime();
|
this.created = timeUtil.curtime();
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletKey.prototype.storeObj = function() {
|
WalletKey.prototype.storeObj = function() {
|
||||||
var pubKey = this.privKey.public.toString('hex');
|
var pubKey = this.privKey.public.toString('hex');
|
||||||
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
|
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
|
||||||
var addr = new Address(this.network.addressPubkey, pubKeyHash);
|
var addr = new Address(this.network.addressPubkey, pubKeyHash);
|
||||||
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed);
|
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed);
|
||||||
var obj = {
|
var obj = {
|
||||||
created: this.created,
|
created: this.created,
|
||||||
priv: priv.toString(),
|
priv: priv.toString(),
|
||||||
pub: pubKey,
|
pub: pubKey,
|
||||||
addr: addr.toString(),
|
addr: addr.toString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
};
|
};
|
||||||
|
|
||||||
WalletKey.prototype.fromObj = function(obj) {
|
WalletKey.prototype.fromObj = function(obj) {
|
||||||
this.created = obj.created;
|
this.created = obj.created;
|
||||||
this.privKey = new KeyModule.Key();
|
this.privKey = new KeyModule.Key();
|
||||||
if (obj.priv.length==64) {
|
if (obj.priv.length==64) {
|
||||||
this.privKey.private = new Buffer(obj.priv,'hex');
|
this.privKey.private = new Buffer(obj.priv,'hex');
|
||||||
this.privKey.compressed = true;
|
this.privKey.compressed = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var priv = new PrivateKey(obj.priv);
|
var priv = new PrivateKey(obj.priv);
|
||||||
this.privKey.private = new Buffer(priv.payload());
|
this.privKey.private = new Buffer(priv.payload());
|
||||||
this.privKey.compressed = priv.compressed();
|
this.privKey.compressed = priv.compressed();
|
||||||
}
|
}
|
||||||
this.privKey.regenerateSync();
|
this.privKey.regenerateSync();
|
||||||
};
|
};
|
||||||
|
|
||||||
return WalletKey;
|
return WalletKey;
|
||||||
};
|
};
|
||||||
module.defineClass(ClassSpec);
|
module.defineClass(ClassSpec);
|
||||||
|
|||||||
6
const.js
6
const.js
@ -1,8 +1,8 @@
|
|||||||
|
|
||||||
MSG = {
|
MSG = {
|
||||||
TX: 1,
|
TX: 1,
|
||||||
BLOCK: 2,
|
BLOCK: 2,
|
||||||
FILTERED_BLOCK: 3,
|
FILTERED_BLOCK: 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
MSG.to_str = function(t) {
|
MSG.to_str = function(t) {
|
||||||
|
|||||||
138
test/basic.js
138
test/basic.js
@ -10,104 +10,104 @@ suite('basic');
|
|||||||
|
|
||||||
function test_encode_priv(b58, payload, isTestnet, isCompressed)
|
function test_encode_priv(b58, payload, isTestnet, isCompressed)
|
||||||
{
|
{
|
||||||
var network = isTestnet ? networks.testnet : networks.livenet;
|
var network = isTestnet ? networks.testnet : networks.livenet;
|
||||||
var version = network.keySecret;
|
var version = network.keySecret;
|
||||||
|
|
||||||
var buf_pl = new Buffer(payload, 'hex');
|
var buf_pl = new Buffer(payload, 'hex');
|
||||||
var buf;
|
var buf;
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
buf = new Buffer(buf_pl.length + 1);
|
buf = new Buffer(buf_pl.length + 1);
|
||||||
buf_pl.copy(buf);
|
buf_pl.copy(buf);
|
||||||
buf[buf_pl.length] = 1;
|
buf[buf_pl.length] = 1;
|
||||||
} else
|
} else
|
||||||
buf = buf_pl;
|
buf = buf_pl;
|
||||||
|
|
||||||
var key = new KeyModule.Key();
|
var key = new KeyModule.Key();
|
||||||
key.private = buf;
|
key.private = buf;
|
||||||
key.compressed = isCompressed;
|
key.compressed = isCompressed;
|
||||||
|
|
||||||
var privkey = new PrivateKey(version, buf);
|
var privkey = new PrivateKey(version, buf);
|
||||||
assert.equal(privkey.toString(), b58);
|
assert.equal(privkey.toString(), b58);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_encode_pub(b58, payload, isTestnet, addrType)
|
function test_encode_pub(b58, payload, isTestnet, addrType)
|
||||||
{
|
{
|
||||||
var isScript = (addrType == 'script');
|
var isScript = (addrType == 'script');
|
||||||
var network = isTestnet ? networks.testnet : networks.livenet;
|
var network = isTestnet ? networks.testnet : networks.livenet;
|
||||||
var version = isScript ? network.addressScript : network.addressPubkey;
|
var version = isScript ? network.addressScript : network.addressPubkey;
|
||||||
var buf = new Buffer(payload, 'hex');
|
var buf = new Buffer(payload, 'hex');
|
||||||
var addr = new Address(version, buf);
|
var addr = new Address(version, buf);
|
||||||
assert.equal(addr.toString(), b58);
|
assert.equal(addr.toString(), b58);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_decode_priv(b58, payload, isTestnet, isCompressed)
|
function test_decode_priv(b58, payload, isTestnet, isCompressed)
|
||||||
{
|
{
|
||||||
var network = isTestnet ? networks.testnet : networks.livenet;
|
var network = isTestnet ? networks.testnet : networks.livenet;
|
||||||
var version = network.keySecret;
|
var version = network.keySecret;
|
||||||
|
|
||||||
var buf_pl = new Buffer(payload, 'hex');
|
var buf_pl = new Buffer(payload, 'hex');
|
||||||
var buf;
|
var buf;
|
||||||
if (isCompressed) {
|
if (isCompressed) {
|
||||||
buf = new Buffer(buf_pl.length + 1);
|
buf = new Buffer(buf_pl.length + 1);
|
||||||
buf_pl.copy(buf);
|
buf_pl.copy(buf);
|
||||||
buf[buf_pl.length] = 1;
|
buf[buf_pl.length] = 1;
|
||||||
} else
|
} else
|
||||||
buf = buf_pl;
|
buf = buf_pl;
|
||||||
|
|
||||||
var privkey = new PrivateKey(b58);
|
var privkey = new PrivateKey(b58);
|
||||||
assert.equal(version, privkey.version());
|
assert.equal(version, privkey.version());
|
||||||
assert.equal(buf_pl.toString(), privkey.payload().toString());
|
assert.equal(buf_pl.toString(), privkey.payload().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_decode_pub(b58, payload, isTestnet, addrType)
|
function test_decode_pub(b58, payload, isTestnet, addrType)
|
||||||
{
|
{
|
||||||
var isScript = (addrType == 'script');
|
var isScript = (addrType == 'script');
|
||||||
var network = isTestnet ? networks.testnet : networks.livenet;
|
var network = isTestnet ? networks.testnet : networks.livenet;
|
||||||
var version = isScript ? network.addressScript : network.addressPubkey;
|
var version = isScript ? network.addressScript : network.addressPubkey;
|
||||||
var buf = new Buffer(payload, 'hex');
|
var buf = new Buffer(payload, 'hex');
|
||||||
var addr = new Address(b58);
|
var addr = new Address(b58);
|
||||||
|
|
||||||
assert.equal(version, addr.version());
|
assert.equal(version, addr.version());
|
||||||
assert.equal(buf.toString(), addr.payload().toString());
|
assert.equal(buf.toString(), addr.payload().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_valid(datum)
|
function is_valid(datum)
|
||||||
{
|
{
|
||||||
var b58 = datum[0];
|
var b58 = datum[0];
|
||||||
var payload = datum[1];
|
var payload = datum[1];
|
||||||
var obj = datum[2];
|
var obj = datum[2];
|
||||||
var isPrivkey = obj['isPrivkey'];
|
var isPrivkey = obj['isPrivkey'];
|
||||||
var isTestnet = obj['isTestnet'];
|
var isTestnet = obj['isTestnet'];
|
||||||
|
|
||||||
if (isPrivkey) {
|
if (isPrivkey) {
|
||||||
var isCompressed = obj['isCompressed'];
|
var isCompressed = obj['isCompressed'];
|
||||||
test_encode_priv(b58, payload, isTestnet, isCompressed);
|
test_encode_priv(b58, payload, isTestnet, isCompressed);
|
||||||
test_decode_priv(b58, payload, isTestnet, isCompressed);
|
test_decode_priv(b58, payload, isTestnet, isCompressed);
|
||||||
} else {
|
} else {
|
||||||
var addrType = obj['addrType'];
|
var addrType = obj['addrType'];
|
||||||
test_encode_pub(b58, payload, isTestnet, addrType);
|
test_encode_pub(b58, payload, isTestnet, addrType);
|
||||||
test_decode_pub(b58, payload, isTestnet, addrType);
|
test_decode_pub(b58, payload, isTestnet, addrType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function is_invalid(datum)
|
function is_invalid(datum)
|
||||||
{
|
{
|
||||||
if (datum.length < 1)
|
if (datum.length < 1)
|
||||||
throw new Error("Bad test");
|
throw new Error("Bad test");
|
||||||
|
|
||||||
// ignore succeeding elements, as comments
|
// ignore succeeding elements, as comments
|
||||||
var b58 = datum[0];
|
var b58 = datum[0];
|
||||||
var privkey = new PrivateKey(b58);
|
var privkey = new PrivateKey(b58);
|
||||||
var addr = new Address(b58);
|
var addr = new Address(b58);
|
||||||
|
|
||||||
var valid = true;
|
var valid = true;
|
||||||
try {
|
try {
|
||||||
privkey.validate();
|
privkey.validate();
|
||||||
addr.validate();
|
addr.validate();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
valid = false;
|
valid = false;
|
||||||
}
|
}
|
||||||
assert.equal(valid, false);
|
assert.equal(valid, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataValid = JSON.parse(fs.readFileSync('test/base58_keys_valid.json'));
|
var dataValid = JSON.parse(fs.readFileSync('test/base58_keys_valid.json'));
|
||||||
|
|||||||
@ -4,56 +4,56 @@ var crypto = require('crypto');
|
|||||||
|
|
||||||
exports.readFileSync = function(enc_method, enc_passphrase, filename)
|
exports.readFileSync = function(enc_method, enc_passphrase, filename)
|
||||||
{
|
{
|
||||||
// read entire file into memory
|
// read entire file into memory
|
||||||
var fileData = fs.readFileSync(filename, 'binary');
|
var fileData = fs.readFileSync(filename, 'binary');
|
||||||
if (fileData.length < 32)
|
if (fileData.length < 32)
|
||||||
throw new Error("Crypted file " + filename + " truncated");
|
throw new Error("Crypted file " + filename + " truncated");
|
||||||
|
|
||||||
// separate into data, hmac parts
|
// separate into data, hmac parts
|
||||||
var fileCrypted = fileData.slice(0, -32);
|
var fileCrypted = fileData.slice(0, -32);
|
||||||
var fileHmac = fileData.slice(-32);
|
var fileHmac = fileData.slice(-32);
|
||||||
|
|
||||||
// generate and verify HMAC
|
// generate and verify HMAC
|
||||||
var hmac = crypto.createHmac('sha256', enc_passphrase);
|
var hmac = crypto.createHmac('sha256', enc_passphrase);
|
||||||
hmac.update(fileCrypted);
|
hmac.update(fileCrypted);
|
||||||
var digest = hmac.digest('binary');
|
var digest = hmac.digest('binary');
|
||||||
|
|
||||||
if (digest.toString() != fileHmac.toString())
|
if (digest.toString() != fileHmac.toString())
|
||||||
throw new Error("Crypted file " + filename + " failed HMAC checksum verification");
|
throw new Error("Crypted file " + filename + " failed HMAC checksum verification");
|
||||||
|
|
||||||
// decrypt to plaintext
|
// decrypt to plaintext
|
||||||
var decipher = crypto.createDecipher(enc_method, enc_passphrase);
|
var decipher = crypto.createDecipher(enc_method, enc_passphrase);
|
||||||
var dec = decipher.update(fileCrypted, 'binary', 'binary');
|
var dec = decipher.update(fileCrypted, 'binary', 'binary');
|
||||||
dec += decipher.final('binary');
|
dec += decipher.final('binary');
|
||||||
return dec;
|
return dec;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.readJFileSync = function(enc_method, enc_passphrase, filename)
|
exports.readJFileSync = function(enc_method, enc_passphrase, filename)
|
||||||
{
|
{
|
||||||
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
|
var raw = this.readFileSync(enc_method, enc_passphrase, filename);
|
||||||
return JSON.parse(raw);
|
return JSON.parse(raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.writeFileSync = function(enc_method, enc_passphrase, filename, data)
|
exports.writeFileSync = function(enc_method, enc_passphrase, filename, data)
|
||||||
{
|
{
|
||||||
// encrypt to ciphertext
|
// encrypt to ciphertext
|
||||||
var cipher = crypto.createCipher(enc_method, enc_passphrase);
|
var cipher = crypto.createCipher(enc_method, enc_passphrase);
|
||||||
var crypted = cipher.update(data, 'binary', 'binary');
|
var crypted = cipher.update(data, 'binary', 'binary');
|
||||||
crypted += cipher.final('binary');
|
crypted += cipher.final('binary');
|
||||||
|
|
||||||
// compute HMAC
|
// compute HMAC
|
||||||
var hmac = crypto.createHmac('sha256', enc_passphrase);
|
var hmac = crypto.createHmac('sha256', enc_passphrase);
|
||||||
hmac.update(crypted);
|
hmac.update(crypted);
|
||||||
var digest = hmac.digest('binary');
|
var digest = hmac.digest('binary');
|
||||||
|
|
||||||
fs.writeFileSync(filename, crypted + digest, 'binary');
|
fs.writeFileSync(filename, crypted + digest, 'binary');
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.writeJFileSync = function(enc_method, enc_passphrase, filename, obj)
|
exports.writeJFileSync = function(enc_method, enc_passphrase, filename, obj)
|
||||||
{
|
{
|
||||||
var raw = JSON.stringify(obj);
|
var raw = JSON.stringify(obj);
|
||||||
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
|
return this.writeFileSync(enc_method, enc_passphrase, filename, raw);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,6 @@
|
|||||||
// current time, in seconds
|
// current time, in seconds
|
||||||
exports.curtime = function curtime()
|
exports.curtime = function curtime()
|
||||||
{
|
{
|
||||||
return Math.round(Date.now() / 1000);
|
return Math.round(Date.now() / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
34
util/util.js
34
util/util.js
@ -113,42 +113,42 @@ var reWholeVal = /^\s*(\d+)/;
|
|||||||
|
|
||||||
function padFrac(frac)
|
function padFrac(frac)
|
||||||
{
|
{
|
||||||
frac=frac.substr(0,8); //truncate to 8 decimal places
|
frac=frac.substr(0,8); //truncate to 8 decimal places
|
||||||
while (frac.length < 8)
|
while (frac.length < 8)
|
||||||
frac = frac + '0';
|
frac = frac + '0';
|
||||||
return frac;
|
return frac;
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFullValue(res)
|
function parseFullValue(res)
|
||||||
{
|
{
|
||||||
return bignum(res[1]).mul('100000000').add(padFrac(res[2]));
|
return bignum(res[1]).mul('100000000').add(padFrac(res[2]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseFracValue(res)
|
function parseFracValue(res)
|
||||||
{
|
{
|
||||||
return bignum(padFrac(res[1]));
|
return bignum(padFrac(res[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseWholeValue(res)
|
function parseWholeValue(res)
|
||||||
{
|
{
|
||||||
return bignum(res[1]).mul('100000000');
|
return bignum(res[1]).mul('100000000');
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.parseValue = function parseValue(valueStr)
|
exports.parseValue = function parseValue(valueStr)
|
||||||
{
|
{
|
||||||
var res = valueStr.match(reFullVal);
|
var res = valueStr.match(reFullVal);
|
||||||
if (res)
|
if (res)
|
||||||
return parseFullValue(res);
|
return parseFullValue(res);
|
||||||
|
|
||||||
res = valueStr.match(reFracVal);
|
res = valueStr.match(reFracVal);
|
||||||
if (res)
|
if (res)
|
||||||
return parseFracValue(res);
|
return parseFracValue(res);
|
||||||
|
|
||||||
res = valueStr.match(reWholeVal);
|
res = valueStr.match(reWholeVal);
|
||||||
if (res)
|
if (res)
|
||||||
return parseWholeValue(res);
|
return parseWholeValue(res);
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Utility that synchronizes function calls based on a key
|
// Utility that synchronizes function calls based on a key
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user