Matias Alejo Garcia
11 years ago
38 changed files with 4339 additions and 4402 deletions
@ -1,22 +1,19 @@ |
|||
require('classtool'); |
|||
'use strict'; |
|||
var imports = require('soop').imports(); |
|||
var parent = imports.parent || require('./util/VersionedData'); |
|||
|
|||
function ClassSpec(b) { |
|||
var superclass = b.superclass || require('./util/VersionedData').class(); |
|||
|
|||
function Address() { |
|||
Address.super(this, arguments); |
|||
} |
|||
function Address() { |
|||
Address.super(this, arguments); |
|||
} |
|||
|
|||
Address.superclass = superclass; |
|||
superclass.applyEncodingsTo(Address); |
|||
Address.parent = parent; |
|||
parent.applyEncodingsTo(Address); |
|||
|
|||
Address.prototype.validate = function() { |
|||
this.doAsBinary(function() { |
|||
Address.super(this, 'validate', arguments); |
|||
if(this.data.length !== 21) throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
Address.prototype.validate = function() { |
|||
this.doAsBinary(function() { |
|||
Address.super(this, 'validate', arguments); |
|||
if(this.data.length !== 21) throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
|
|||
return Address; |
|||
} |
|||
module.defineClass(ClassSpec); |
|||
module.exports = require('soop')(Address); |
|||
|
File diff suppressed because it is too large
@ -1,116 +1,111 @@ |
|||
require('classtool'); |
|||
|
|||
function ClassSpec(b) { |
|||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
|||
var MAX_HASH_FUNCS = 50; |
|||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; |
|||
var LN2 = 0.6931471805599453094172321214581765680755001343602552; |
|||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; |
|||
|
|||
function Bloom() { |
|||
this.data = ''; |
|||
this.hashFuncs = 0; |
|||
}; |
|||
|
|||
function ROTL32(x, r) { |
|||
return (x << r) | (x >> (32 - r)); |
|||
}; |
|||
|
|||
function getBlockU32(blockIdx, data) { |
|||
var idx = blockIdx * 4; |
|||
var v = (data[idx + 0] << (0 * 8)) | |
|||
(data[idx + 1] << (1 * 8)) | |
|||
(data[idx + 2] << (2 * 8)) | |
|||
(data[idx + 3] << (3 * 8)); |
|||
return v; |
|||
}; |
|||
|
|||
Bloom.prototype.hash = function(hashNum, data) { |
|||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); |
|||
var c1 = 0xcc9e2d51; |
|||
var c2 = 0x1b873593; |
|||
var nBlocks = data.length / 4; |
|||
|
|||
// data body
|
|||
for (var i = -nBlocks; i; i++) { |
|||
var k1 = getBlockU32(i); |
|||
|
|||
k1 *= c1; |
|||
k1 = ROTLF32(k1, 15); |
|||
k1 *= c2; |
|||
|
|||
h1 ^= k1; |
|||
h1 = ROTFL(h1, 13); |
|||
h1 = h1 * 5 + 0xe6546b64; |
|||
} |
|||
|
|||
// tail (trailing 1-3 bytes)
|
|||
var tail = data.slice(nBlocks * 4); |
|||
|
|||
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; |
|||
} |
|||
|
|||
// finalize
|
|||
h1 ^= data.length; |
|||
h1 ^= h1 >> 16; |
|||
h1 *= 0x85ebca6b; |
|||
h1 ^= h1 >> 13; |
|||
h1 *= 0xc2b2ae35; |
|||
h1 ^= h1 >> 16; |
|||
|
|||
return h1 % (this.data.length * 8); |
|||
}; |
|||
|
|||
Bloom.prototype.insert = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
this.data[index >> 3] |= bit_mask[7 & index]; |
|||
} |
|||
}; |
|||
|
|||
Bloom.prototype.contains = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
if (!(this.data[index >> 3] & bit_mask[7 & index])) |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
Bloom.prototype.sizeOk = function() { |
|||
return this.data.length <= MAX_BLOOM_FILTER_SIZE && |
|||
this.hashFuncs <= MAX_HASH_FUNCS; |
|||
}; |
|||
|
|||
function toInt(v) { |
|||
return ~~v; |
|||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
|||
var MAX_HASH_FUNCS = 50; |
|||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; |
|||
var LN2 = 0.6931471805599453094172321214581765680755001343602552; |
|||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; |
|||
|
|||
function Bloom() { |
|||
this.data = ''; |
|||
this.hashFuncs = 0; |
|||
}; |
|||
|
|||
function ROTL32(x, r) { |
|||
return (x << r) | (x >> (32 - r)); |
|||
}; |
|||
|
|||
function getBlockU32(blockIdx, data) { |
|||
var idx = blockIdx * 4; |
|||
var v = (data[idx + 0] << (0 * 8)) | |
|||
(data[idx + 1] << (1 * 8)) | |
|||
(data[idx + 2] << (2 * 8)) | |
|||
(data[idx + 3] << (3 * 8)); |
|||
return v; |
|||
}; |
|||
|
|||
Bloom.prototype.hash = function(hashNum, data) { |
|||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); |
|||
var c1 = 0xcc9e2d51; |
|||
var c2 = 0x1b873593; |
|||
var nBlocks = data.length / 4; |
|||
|
|||
// data body
|
|||
for (var i = -nBlocks; i; i++) { |
|||
var k1 = getBlockU32(i); |
|||
|
|||
k1 *= c1; |
|||
k1 = ROTLF32(k1, 15); |
|||
k1 *= c2; |
|||
|
|||
h1 ^= k1; |
|||
h1 = ROTFL(h1, 13); |
|||
h1 = h1 * 5 + 0xe6546b64; |
|||
} |
|||
|
|||
function min(a, b) { |
|||
if (a < b) |
|||
return a; |
|||
return b; |
|||
// tail (trailing 1-3 bytes)
|
|||
var tail = data.slice(nBlocks * 4); |
|||
|
|||
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; |
|||
} |
|||
|
|||
Bloom.prototype.init = function(elements, FPRate) { |
|||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), |
|||
MAX_BLOOM_FILTER_SIZE * 8) / 8; |
|||
this.data[filterSize] = 0; |
|||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), |
|||
MAX_HASH_FUNCS); |
|||
}; |
|||
// finalize
|
|||
h1 ^= data.length; |
|||
h1 ^= h1 >> 16; |
|||
h1 *= 0x85ebca6b; |
|||
h1 ^= h1 >> 13; |
|||
h1 *= 0xc2b2ae35; |
|||
h1 ^= h1 >> 16; |
|||
|
|||
return Bloom; |
|||
return h1 % (this.data.length * 8); |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
Bloom.prototype.insert = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
this.data[index >> 3] |= bit_mask[7 & index]; |
|||
} |
|||
}; |
|||
|
|||
Bloom.prototype.contains = function(data) { |
|||
for (var i = 0; i < this.hashFuncs; i++) { |
|||
var index = this.hash(i, data); |
|||
if (!(this.data[index >> 3] & bit_mask[7 & index])) |
|||
return false; |
|||
} |
|||
|
|||
return true; |
|||
}; |
|||
|
|||
Bloom.prototype.sizeOk = function() { |
|||
return this.data.length <= MAX_BLOOM_FILTER_SIZE && |
|||
this.hashFuncs <= MAX_HASH_FUNCS; |
|||
}; |
|||
|
|||
function toInt(v) { |
|||
return ~~v; |
|||
} |
|||
|
|||
function min(a, b) { |
|||
if (a < b) |
|||
return a; |
|||
return b; |
|||
} |
|||
|
|||
Bloom.prototype.init = function(elements, FPRate) { |
|||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), |
|||
MAX_BLOOM_FILTER_SIZE * 8) / 8; |
|||
this.data[filterSize] = 0; |
|||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), |
|||
MAX_HASH_FUNCS); |
|||
}; |
|||
|
|||
|
|||
module.exports = require('soop')(Bloom); |
|||
|
File diff suppressed because it is too large
@ -1,161 +1,158 @@ |
|||
require('classtool'); |
|||
|
|||
function spec(b) { |
|||
function Opcode(num) { |
|||
this.code = num; |
|||
}; |
|||
|
|||
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, |
|||
|
|||
// 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, |
|||
|
|||
// 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, |
|||
|
|||
// splice ops
|
|||
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, |
|||
|
|||
// 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_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_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, |
|||
|
|||
// 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, |
|||
|
|||
// template matching params
|
|||
OP_PUBKEYHASH : 253, |
|||
OP_PUBKEY : 254, |
|||
OP_INVALIDOPCODE : 255 |
|||
}; |
|||
|
|||
Opcode.reverseMap = []; |
|||
|
|||
for (var k in Opcode.map) { |
|||
if(Opcode.map.hasOwnProperty(k)) { |
|||
Opcode.reverseMap[Opcode.map[k]] = k.substr(3); |
|||
} |
|||
} |
|||
var imports = require('soop').imports(); |
|||
|
|||
function Opcode(num) { |
|||
this.code = num; |
|||
}; |
|||
|
|||
Opcode.prototype.toString = function () { |
|||
return Opcode.reverseMap[this.code]; |
|||
}; |
|||
|
|||
return Opcode; |
|||
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, |
|||
|
|||
// 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, |
|||
|
|||
// 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, |
|||
|
|||
// splice ops
|
|||
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, |
|||
|
|||
// 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_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_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, |
|||
|
|||
// 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, |
|||
|
|||
// template matching params
|
|||
OP_PUBKEYHASH : 253, |
|||
OP_PUBKEY : 254, |
|||
OP_INVALIDOPCODE : 255 |
|||
}; |
|||
module.defineClass(spec); |
|||
|
|||
Opcode.reverseMap = []; |
|||
|
|||
for (var k in Opcode.map) { |
|||
if(Opcode.map.hasOwnProperty(k)) { |
|||
Opcode.reverseMap[Opcode.map[k]] = k.substr(3); |
|||
} |
|||
} |
|||
|
|||
module.exports = require('soop')(Opcode); |
|||
|
@ -1,61 +1,58 @@ |
|||
require('classtool'); |
|||
|
|||
function spec(b) { |
|||
var Net = b.Net || require('net'); |
|||
var Binary = b.Binary || require('binary'); |
|||
var buffertools = b.buffertools || require('buffertools'); |
|||
|
|||
function Peer(host, port, services) { |
|||
if ("string" === typeof host) { |
|||
if (host.indexOf(':') && !port) { |
|||
var parts = host.split(':'); |
|||
host = parts[0]; |
|||
port = parts[1]; |
|||
} |
|||
this.host = host; |
|||
this.port = +port || 8333; |
|||
} else if (host instanceof Peer) { |
|||
this.host = host.host; |
|||
this.port = host.port; |
|||
} else if (Buffer.isBuffer(host)) { |
|||
if (buffertools.compare(Peer.IPV6_IPV4_PADDING, host.slice(0, 12)) != 0) { |
|||
throw new Error('IPV6 not supported yet! Cannot instantiate host.'); |
|||
} |
|||
this.host = Array.prototype.slice.apply(host.slice(12)).join('.'); |
|||
this.port = +port || 8333; |
|||
} else { |
|||
throw new Error('Could not instantiate peer, invalid parameter type: ' + |
|||
typeof host); |
|||
var imports = require('soop').imports(); |
|||
|
|||
var Net = imports.Net || require('net'); |
|||
var Binary = imports.Binary || require('binary'); |
|||
var buffertools = imports.buffertools || require('buffertools'); |
|||
|
|||
function Peer(host, port, services) { |
|||
if ("string" === typeof host) { |
|||
if (host.indexOf(':') && !port) { |
|||
var parts = host.split(':'); |
|||
host = parts[0]; |
|||
port = parts[1]; |
|||
} |
|||
this.host = host; |
|||
this.port = +port || 8333; |
|||
} else if (host instanceof Peer) { |
|||
this.host = host.host; |
|||
this.port = host.port; |
|||
} else if (Buffer.isBuffer(host)) { |
|||
if (buffertools.compare(Peer.IPV6_IPV4_PADDING, host.slice(0, 12)) != 0) { |
|||
throw new Error('IPV6 not supported yet! Cannot instantiate host.'); |
|||
} |
|||
this.host = Array.prototype.slice.apply(host.slice(12)).join('.'); |
|||
this.port = +port || 8333; |
|||
} else { |
|||
throw new Error('Could not instantiate peer, invalid parameter type: ' + |
|||
typeof host); |
|||
} |
|||
|
|||
this.services = (services) ? services : null; |
|||
this.lastSeen = 0; |
|||
}; |
|||
|
|||
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.prototype.createConnection = function () { |
|||
var c = Net.createConnection(this.port, this.host); |
|||
return c; |
|||
}; |
|||
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]); |
|||
|
|||
Peer.prototype.getHostAsBuffer = function () { |
|||
return new Buffer(this.host.split('.')); |
|||
}; |
|||
Peer.prototype.createConnection = function () { |
|||
var c = Net.createConnection(this.port, this.host); |
|||
return c; |
|||
}; |
|||
|
|||
Peer.prototype.toString = function () { |
|||
return this.host + ":" + this.port; |
|||
}; |
|||
Peer.prototype.getHostAsBuffer = function () { |
|||
return new Buffer(this.host.split('.')); |
|||
}; |
|||
|
|||
Peer.prototype.toBuffer = function () { |
|||
var put = Binary.put(); |
|||
put.word32le(this.lastSeen); |
|||
put.word64le(this.services); |
|||
put.put(this.getHostAsBuffer()); |
|||
put.word16be(this.port); |
|||
return put.buffer(); |
|||
}; |
|||
Peer.prototype.toString = function () { |
|||
return this.host + ":" + this.port; |
|||
}; |
|||
|
|||
return Peer; |
|||
Peer.prototype.toBuffer = function () { |
|||
var put = Binary.put(); |
|||
put.word32le(this.lastSeen); |
|||
put.word64le(this.services); |
|||
put.put(this.getHostAsBuffer()); |
|||
put.word16be(this.port); |
|||
return put.buffer(); |
|||
}; |
|||
module.defineClass(spec); |
|||
|
|||
module.exports = require('soop')(Peer); |
|||
|
@ -1,215 +1,212 @@ |
|||
require('classtool'); |
|||
|
|||
function spec(b) { |
|||
var config = b.config || require('./config'); |
|||
var log = b.log || require('./util/log'); |
|||
var network = b.network || require('./networks')[config.network]; |
|||
var Connection = b.Connection || require('./Connection').createClass( |
|||
{config: config, network: network}); |
|||
var Peer = b.Peer || require('./Peer').class(); |
|||
var noop = function() {}; |
|||
|
|||
GetAdjustedTime = b.GetAdjustedTime || function () { |
|||
// TODO: Implement actual adjustment
|
|||
return Math.floor(new Date().getTime() / 1000); |
|||
}; |
|||
|
|||
function PeerManager() { |
|||
this.active = false; |
|||
this.timer = null; |
|||
var imports = require('soop').imports(); |
|||
var config = imports.config || require('./config'); |
|||
var log = imports.log || require('./util/log'); |
|||
var network = imports.network || require('./networks')[config.network]; |
|||
var Connection = imports.Connection || |
|||
require('soop').load('./Connection', {config: config, network: network}); |
|||
|
|||
this.peers = []; |
|||
this.connections = []; |
|||
this.isConnected = false; |
|||
this.peerDiscovery = false; |
|||
var Peer = imports.Peer || require('./Peer'); |
|||
|
|||
// Move these to the Node's settings object
|
|||
this.interval = 5000; |
|||
this.minConnections = 8; |
|||
this.minKnownPeers = 10; |
|||
}; |
|||
PeerManager.superclass = b.superclass || require('events').EventEmitter; |
|||
GetAdjustedTime = imports.GetAdjustedTime || function () { |
|||
// TODO: Implement actual adjustment
|
|||
return Math.floor(new Date().getTime() / 1000); |
|||
}; |
|||
|
|||
PeerManager.Connection = Connection; |
|||
function PeerManager() { |
|||
this.active = false; |
|||
this.timer = null; |
|||
|
|||
PeerManager.prototype.start = function() { |
|||
this.active = true; |
|||
if(!this.timer) { |
|||
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
|||
} |
|||
}; |
|||
this.peers = []; |
|||
this.connections = []; |
|||
this.isConnected = false; |
|||
this.peerDiscovery = false; |
|||
|
|||
PeerManager.prototype.stop = function() { |
|||
this.active = false; |
|||
if(this.timer) { |
|||
clearInterval(this.timer); |
|||
this.timer = null; |
|||
} |
|||
for(var i=0; i<this.connections.length; i++) { |
|||
this.connections[i].socket.end(); |
|||
}; |
|||
}; |
|||
// Move these to the Node's settings object
|
|||
this.interval = 5000; |
|||
this.minConnections = 8; |
|||
this.minKnownPeers = 10; |
|||
}; |
|||
|
|||
PeerManager.prototype.addPeer = function(peer, port) { |
|||
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}); |
|||
throw 'Node.addPeer(): Invalid value provided for peer.'; |
|||
} |
|||
}; |
|||
PeerManager.parent = imports.parent || require('events').EventEmitter; |
|||
PeerManager.Connection = Connection; |
|||
|
|||
PeerManager.prototype.checkStatus = function checkStatus() { |
|||
// Make sure we are connected to all forcePeers
|
|||
if(this.peers.length) { |
|||
var peerIndex = {}; |
|||
this.peers.forEach(function(peer) { |
|||
peerIndex[peer.toString()] = peer; |
|||
}); |
|||
|
|||
// Ignore the ones we're already connected to
|
|||
this.connections.forEach(function(conn) { |
|||
var peerName = conn.peer.toString(); |
|||
if("undefined" !== peerIndex[peerName]) { |
|||
delete peerIndex[peerName]; |
|||
} |
|||
}); |
|||
|
|||
Object.keys(peerIndex).forEach(function(i) { |
|||
this.connectTo(peerIndex[i]); |
|||
}.bind(this)); |
|||
} |
|||
}; |
|||
PeerManager.prototype.start = function() { |
|||
this.active = true; |
|||
if(!this.timer) { |
|||
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
|||
} |
|||
}; |
|||
|
|||
PeerManager.prototype.connectTo = function(peer) { |
|||
log.info('connecting to '+peer); |
|||
try { |
|||
return this.addConnection(peer.createConnection(), peer); |
|||
} catch (e) { |
|||
log.err('creating connection',e); |
|||
return null; |
|||
} |
|||
PeerManager.prototype.stop = function() { |
|||
this.active = false; |
|||
if(this.timer) { |
|||
clearInterval(this.timer); |
|||
this.timer = null; |
|||
} |
|||
for(var i=0; i<this.connections.length; i++) { |
|||
this.connections[i].socket.end(); |
|||
}; |
|||
}; |
|||
|
|||
PeerManager.prototype.addConnection = function(socketConn, peer) { |
|||
var conn = new Connection(socketConn, peer); |
|||
this.connections.push(conn); |
|||
this.emit('connection', conn); |
|||
PeerManager.prototype.addPeer = function(peer, port) { |
|||
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}); |
|||
throw 'Node.addPeer(): Invalid value provided for peer.'; |
|||
} |
|||
}; |
|||
|
|||
conn.addListener('version', this.handleVersion.bind(this)); |
|||
conn.addListener('verack', this.handleReady.bind(this)); |
|||
conn.addListener('addr', this.handleAddr.bind(this)); |
|||
conn.addListener('getaddr', this.handleGetAddr.bind(this)); |
|||
conn.addListener('error', this.handleError.bind(this)); |
|||
conn.addListener('disconnect', this.handleDisconnect.bind(this)); |
|||
PeerManager.prototype.checkStatus = function checkStatus() { |
|||
// Make sure we are connected to all forcePeers
|
|||
if(this.peers.length) { |
|||
var peerIndex = {}; |
|||
this.peers.forEach(function(peer) { |
|||
peerIndex[peer.toString()] = peer; |
|||
}); |
|||
|
|||
return conn; |
|||
}; |
|||
// Ignore the ones we're already connected to
|
|||
this.connections.forEach(function(conn) { |
|||
var peerName = conn.peer.toString(); |
|||
if("undefined" !== peerIndex[peerName]) { |
|||
delete peerIndex[peerName]; |
|||
} |
|||
}); |
|||
|
|||
PeerManager.prototype.handleVersion = function(e) { |
|||
if (!e.conn.inbound) { |
|||
// TODO: Advertise our address (if listening)
|
|||
} |
|||
// Get recent addresses
|
|||
if(this.peerDiscovery && |
|||
(e.message.version >= 31402 || this.peers.length < 1000)) { |
|||
e.conn.sendGetAddr(); |
|||
e.conn.getaddr = true; |
|||
} |
|||
}; |
|||
Object.keys(peerIndex).forEach(function(i) { |
|||
this.connectTo(peerIndex[i]); |
|||
}.bind(this)); |
|||
} |
|||
}; |
|||
|
|||
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, |
|||
socket: e.socket, |
|||
peer: e.peer |
|||
}); |
|||
PeerManager.prototype.connectTo = function(peer) { |
|||
log.info('connecting to '+peer); |
|||
try { |
|||
return this.addConnection(peer.createConnection(), peer); |
|||
} catch (e) { |
|||
log.err('creating connection',e); |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
if(this.isConnected == false) { |
|||
this.emit('netConnected'); |
|||
this.isConnected = true; |
|||
} |
|||
}; |
|||
PeerManager.prototype.addConnection = function(socketConn, peer) { |
|||
var conn = new Connection(socketConn, peer); |
|||
this.connections.push(conn); |
|||
this.emit('connection', conn); |
|||
|
|||
conn.addListener('version', this.handleVersion.bind(this)); |
|||
conn.addListener('verack', this.handleReady.bind(this)); |
|||
conn.addListener('addr', this.handleAddr.bind(this)); |
|||
conn.addListener('getaddr', this.handleGetAddr.bind(this)); |
|||
conn.addListener('error', this.handleError.bind(this)); |
|||
conn.addListener('disconnect', this.handleDisconnect.bind(this)); |
|||
|
|||
return conn; |
|||
}; |
|||
|
|||
PeerManager.prototype.handleVersion = function(e) { |
|||
if (!e.conn.inbound) { |
|||
// TODO: Advertise our address (if listening)
|
|||
} |
|||
// Get recent addresses
|
|||
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); |
|||
this.emit('connect', { |
|||
pm: this, |
|||
conn: e.conn, |
|||
socket: e.socket, |
|||
peer: e.peer |
|||
}); |
|||
|
|||
if(this.isConnected == false) { |
|||
this.emit('netConnected'); |
|||
this.isConnected = true; |
|||
} |
|||
}; |
|||
|
|||
PeerManager.prototype.handleAddr = function (e) { |
|||
if(!this.peerDiscovery) return; |
|||
|
|||
var now = GetAdjustedTime(); |
|||
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)) { |
|||
addr.time = now - 5 * 24 * 60 * 60; |
|||
} |
|||
var peer = new Peer(addr.ip, addr.port, addr.services); |
|||
peer.lastSeen = addr.time; |
|||
|
|||
// TODO: Handle duplicate peers
|
|||
this.peers.push(peer); |
|||
|
|||
// TODO: Handle addr relay
|
|||
} catch(e) { |
|||
log.warn("Invalid addr received: "+e.message); |
|||
PeerManager.prototype.handleAddr = function (e) { |
|||
if(!this.peerDiscovery) return; |
|||
|
|||
var now = GetAdjustedTime(); |
|||
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)) { |
|||
addr.time = now - 5 * 24 * 60 * 60; |
|||
} |
|||
}.bind(this)); |
|||
if (e.message.addrs.length < 1000 ) { |
|||
e.conn.getaddr = false; |
|||
var peer = new Peer(addr.ip, addr.port, addr.services); |
|||
peer.lastSeen = addr.time; |
|||
|
|||
// TODO: Handle duplicate peers
|
|||
this.peers.push(peer); |
|||
|
|||
// TODO: Handle addr relay
|
|||
} catch(e) { |
|||
log.warn("Invalid addr received: "+e.message); |
|||
} |
|||
}; |
|||
}.bind(this)); |
|||
if (e.message.addrs.length < 1000 ) { |
|||
e.conn.getaddr = false; |
|||
} |
|||
}; |
|||
|
|||
PeerManager.prototype.handleGetAddr = function(e) { |
|||
// TODO: Reply with addr message.
|
|||
}; |
|||
PeerManager.prototype.handleGetAddr = function(e) { |
|||
// TODO: Reply with addr message.
|
|||
}; |
|||
|
|||
PeerManager.prototype.handleError = function(e) { |
|||
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err); |
|||
this.handleDisconnect.apply(this, [].slice.call(arguments)); |
|||
}; |
|||
PeerManager.prototype.handleError = function(e) { |
|||
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); |
|||
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(!this.connections.length) { |
|||
this.emit('netDisconnected'); |
|||
this.isConnected = false; |
|||
} |
|||
}; |
|||
if(!this.connections.length) { |
|||
this.emit('netDisconnected'); |
|||
this.isConnected = false; |
|||
} |
|||
}; |
|||
|
|||
PeerManager.prototype.getActiveConnection = function () { |
|||
var activeConnections = this.connections.filter(function (conn) { |
|||
return conn.active; |
|||
}); |
|||
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 candidate = activeConnections[randomIndex]; |
|||
if (candidate.socket.writable) { |
|||
return candidate; |
|||
} else { |
|||
// Socket is not writable, remove it from active connections
|
|||
activeConnections.splice(randomIndex, 1); |
|||
|
|||
// Then try again
|
|||
// TODO: This causes an infinite recursion when all connections are dead,
|
|||
// although it shouldn't.
|
|||
return this.getActiveConnection(); |
|||
} |
|||
if (activeConnections.length) { |
|||
var randomIndex = Math.floor(Math.random()*activeConnections.length); |
|||
var candidate = activeConnections[randomIndex]; |
|||
if (candidate.socket.writable) { |
|||
return candidate; |
|||
} else { |
|||
return null; |
|||
} |
|||
}; |
|||
// Socket is not writable, remove it from active connections
|
|||
activeConnections.splice(randomIndex, 1); |
|||
|
|||
PeerManager.prototype.getActiveConnections = function () { |
|||
return this.connections.slice(0); |
|||
}; |
|||
// Then try again
|
|||
// TODO: This causes an infinite recursion when all connections are dead,
|
|||
// although it shouldn't.
|
|||
return this.getActiveConnection(); |
|||
} |
|||
} else { |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
return PeerManager; |
|||
PeerManager.prototype.getActiveConnections = function () { |
|||
return this.connections.slice(0); |
|||
}; |
|||
module.defineClass(spec); |
|||
|
|||
module.exports = require('soop')(PeerManager); |
|||
|
@ -1,67 +1,64 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
|
|||
function ClassSpec(b) { |
|||
var superclass = b.superclass || require('./util/VersionedData').class(); |
|||
var parent = imports.parent || require('./util/VersionedData'); |
|||
|
|||
//compressed is true if public key is compressed; false otherwise
|
|||
function PrivateKey(version, buf, compressed) { |
|||
PrivateKey.super(this, arguments); |
|||
if (compressed !== undefined) |
|||
this.compressed(compressed); |
|||
}; |
|||
//compressed is true if public key is compressed; false otherwise
|
|||
function PrivateKey(version, buf, compressed) { |
|||
PrivateKey.super(this, arguments); |
|||
if (compressed !== undefined) |
|||
this.compressed(compressed); |
|||
}; |
|||
|
|||
PrivateKey.superclass = superclass; |
|||
superclass.applyEncodingsTo(PrivateKey); |
|||
PrivateKey.parent = parent; |
|||
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) |
|||
throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
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) |
|||
throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
|
|||
// 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);}); |
|||
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) |
|||
return buf.slice(1); |
|||
}; |
|||
// 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);}); |
|||
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) |
|||
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; |
|||
if (compressed) { |
|||
var data=new Buffer(len); |
|||
this.data.copy(data); |
|||
this.data=data; |
|||
this.data[len-1]=1; |
|||
} else { |
|||
this.data=this.data.slice(0,len-1); |
|||
} |
|||
}); |
|||
} |
|||
else { |
|||
// 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; |
|||
var data=this.as('binary'); |
|||
if (data.length==len && data[len-1]==1) |
|||
return true; |
|||
else if (data.length==len-1) |
|||
return false; |
|||
else |
|||
throw new Error('invalid private key'); |
|||
} |
|||
}; |
|||
|
|||
return PrivateKey; |
|||
if (compressed) { |
|||
var data=new Buffer(len); |
|||
this.data.copy(data); |
|||
this.data=data; |
|||
this.data[len-1]=1; |
|||
} else { |
|||
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) |
|||
return true; |
|||
else if (data.length==len-1) |
|||
return false; |
|||
else |
|||
throw new Error('invalid private key'); |
|||
} |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
module.exports = require('soop')(PrivateKey); |
|||
|
@ -1,210 +1,208 @@ |
|||
// RpcClient.js
|
|||
// MIT/X11-like license. See LICENSE.txt.
|
|||
// Copyright 2013 BitPay, Inc.
|
|||
require('classtool'); |
|||
//
|
|||
var imports = require('soop').imports(); |
|||
var http = imports.http || require('http'); |
|||
var https = imports.https || require('https'); |
|||
var log = imports.log || require('./util/log'); |
|||
|
|||
function ClassSpec(b) { |
|||
var http = b.http || require('http'); |
|||
var https = b.https || require('https'); |
|||
var log = b.log || require('./util/log'); |
|||
function RpcClient(opts) { |
|||
opts = opts || {}; |
|||
this.host = opts.host || '127.0.0.1'; |
|||
this.port = opts.port || 8332; |
|||
this.user = opts.user || 'user'; |
|||
this.pass = opts.pass || 'pass'; |
|||
this.protocol = (opts.protocol == 'http') ? http : https; |
|||
this.batchedCalls = null; |
|||
this.disableAgent = opts.disableAgent || false; |
|||
} |
|||
|
|||
RpcClient.prototype.batch = function(batchCallback, resultCallback) { |
|||
this.batchedCalls = []; |
|||
batchCallback(); |
|||
rpc.call(this, this.batchedCalls, resultCallback); |
|||
this.batchedCalls = null; |
|||
} |
|||
|
|||
function RpcClient(opts) { |
|||
opts = opts || {}; |
|||
this.host = opts.host || '127.0.0.1'; |
|||
this.port = opts.port || 8332; |
|||
this.user = opts.user || 'user'; |
|||
this.pass = opts.pass || 'pass'; |
|||
this.protocol = (opts.protocol == 'http') ? http : https; |
|||
this.batchedCalls = null; |
|||
this.disableAgent = opts.disableAgent || false; |
|||
} |
|||
|
|||
RpcClient.prototype.batch = function(batchCallback, resultCallback) { |
|||
this.batchedCalls = []; |
|||
batchCallback(); |
|||
rpc.call(this, this.batchedCalls, resultCallback); |
|||
this.batchedCalls = null; |
|||
} |
|||
|
|||
var callspec = { |
|||
addMultiSigAddress: '', |
|||
addNode: '', |
|||
backupWallet: '', |
|||
createMultiSig: '', |
|||
createRawTransaction: '', |
|||
decodeRawTransaction: '', |
|||
dumpPrivKey: '', |
|||
encryptWallet: '', |
|||
getAccount: '', |
|||
getAccountAddress: 'str', |
|||
getAddedNodeInfo: '', |
|||
getAddressesByAccount: '', |
|||
getBalance: 'str int', |
|||
getBestBlockHash: '', |
|||
getBlock: '', |
|||
getBlockCount: '', |
|||
getBlockHash: 'int', |
|||
getBlockNumber: '', |
|||
getBlockTemplate: '', |
|||
getConnectionCount: '', |
|||
getDifficulty: '', |
|||
getGenerate: '', |
|||
getHashesPerSec: '', |
|||
getInfo: '', |
|||
getMemoryPool: '', |
|||
getMiningInfo: '', |
|||
getNewAddress: '', |
|||
getPeerInfo: '', |
|||
getRawMemPool: '', |
|||
getRawTransaction: 'str int', |
|||
getReceivedByAccount: 'str int', |
|||
getReceivedByAddress: 'str int', |
|||
getTransaction: '', |
|||
getTxOut: 'str int bool', |
|||
getTxOutSetInfo: '', |
|||
getWork: '', |
|||
help: '', |
|||
importAddress: 'str str bool', |
|||
importPrivKey: 'str str bool', |
|||
keyPoolRefill: '', |
|||
listAccounts: 'int', |
|||
listAddressGroupings: '', |
|||
listReceivedByAccount: 'int bool', |
|||
listReceivedByAddress: 'int bool', |
|||
listSinceBlock: 'str int', |
|||
listTransactions: 'str int int', |
|||
listUnspent: 'int int', |
|||
listLockUnspent: 'bool', |
|||
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
|
|||
sendRawTransaction: '', |
|||
sendToAddress: 'str float str str', |
|||
setAccount: '', |
|||
setGenerate: 'bool int', |
|||
setTxFee: 'float', |
|||
signMessage: '', |
|||
signRawTransaction: '', |
|||
stop: '', |
|||
submitBlock: '', |
|||
validateAddress: '', |
|||
verifyMessage: '', |
|||
walletLock: '', |
|||
walletPassPhrase: 'string int', |
|||
walletPassphraseChange: '', |
|||
}; |
|||
var callspec = { |
|||
addMultiSigAddress: '', |
|||
addNode: '', |
|||
backupWallet: '', |
|||
createMultiSig: '', |
|||
createRawTransaction: '', |
|||
decodeRawTransaction: '', |
|||
dumpPrivKey: '', |
|||
encryptWallet: '', |
|||
getAccount: '', |
|||
getAccountAddress: 'str', |
|||
getAddedNodeInfo: '', |
|||
getAddressesByAccount: '', |
|||
getBalance: 'str int', |
|||
getBestBlockHash: '', |
|||
getBlock: '', |
|||
getBlockCount: '', |
|||
getBlockHash: 'int', |
|||
getBlockNumber: '', |
|||
getBlockTemplate: '', |
|||
getConnectionCount: '', |
|||
getDifficulty: '', |
|||
getGenerate: '', |
|||
getHashesPerSec: '', |
|||
getInfo: '', |
|||
getMemoryPool: '', |
|||
getMiningInfo: '', |
|||
getNewAddress: '', |
|||
getPeerInfo: '', |
|||
getRawMemPool: '', |
|||
getRawTransaction: 'str int', |
|||
getReceivedByAccount: 'str int', |
|||
getReceivedByAddress: 'str int', |
|||
getTransaction: '', |
|||
getTxOut: 'str int bool', |
|||
getTxOutSetInfo: '', |
|||
getWork: '', |
|||
help: '', |
|||
importAddress: 'str str bool', |
|||
importPrivKey: 'str str bool', |
|||
keyPoolRefill: '', |
|||
listAccounts: 'int', |
|||
listAddressGroupings: '', |
|||
listReceivedByAccount: 'int bool', |
|||
listReceivedByAddress: 'int bool', |
|||
listSinceBlock: 'str int', |
|||
listTransactions: 'str int int', |
|||
listUnspent: 'int int', |
|||
listLockUnspent: 'bool', |
|||
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
|
|||
sendRawTransaction: '', |
|||
sendToAddress: 'str float str str', |
|||
setAccount: '', |
|||
setGenerate: 'bool int', |
|||
setTxFee: 'float', |
|||
signMessage: '', |
|||
signRawTransaction: '', |
|||
stop: '', |
|||
submitBlock: '', |
|||
validateAddress: '', |
|||
verifyMessage: '', |
|||
walletLock: '', |
|||
walletPassPhrase: 'string int', |
|||
walletPassphraseChange: '', |
|||
}; |
|||
|
|||
var slice = function(arr, start, end) { |
|||
return Array.prototype.slice.call(arr, start, end); |
|||
}; |
|||
var slice = function(arr, start, end) { |
|||
return Array.prototype.slice.call(arr, start, end); |
|||
}; |
|||
|
|||
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) { |
|||
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]); |
|||
} |
|||
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) { |
|||
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]); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
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');}, |
|||
}; |
|||
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');}, |
|||
}; |
|||
|
|||
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]]) { |
|||
spec[i] = types[spec[i]]; |
|||
} else { |
|||
spec[i] = types.string; |
|||
} |
|||
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]]) { |
|||
spec[i] = types[spec[i]]; |
|||
} else { |
|||
spec[i] = types.string; |
|||
} |
|||
var methodName = k.toLowerCase(); |
|||
constructor.prototype[k] = createRPCMethod(methodName, spec); |
|||
constructor.prototype[methodName] = constructor.prototype[k]; |
|||
} |
|||
var methodName = k.toLowerCase(); |
|||
constructor.prototype[k] = createRPCMethod(methodName, spec); |
|||
constructor.prototype[methodName] = constructor.prototype[k]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
function rpc(request, callback) { |
|||
var self = this; |
|||
var request; |
|||
request = JSON.stringify(request); |
|||
var auth = Buffer(self.user + ':' + self.pass).toString('base64'); |
|||
function rpc(request, callback) { |
|||
var self = this; |
|||
var request; |
|||
request = JSON.stringify(request); |
|||
var auth = Buffer(self.user + ':' + self.pass).toString('base64'); |
|||
|
|||
var options = { |
|||
host: self.host, |
|||
path: '/', |
|||
method: 'POST', |
|||
port: self.port, |
|||
agent: self.disableAgent ? false : undefined, |
|||
}; |
|||
if(self.httpOptions) { |
|||
for(var k in self.httpOptions) { |
|||
options[k] = self.httpOptions[k]; |
|||
} |
|||
var options = { |
|||
host: self.host, |
|||
path: '/', |
|||
method: 'POST', |
|||
port: self.port, |
|||
agent: self.disableAgent ? false : undefined, |
|||
}; |
|||
if(self.httpOptions) { |
|||
for(var k in self.httpOptions) { |
|||
options[k] = self.httpOptions[k]; |
|||
} |
|||
var err = null; |
|||
var req = this.protocol.request(options, function(res) { |
|||
} |
|||
var err = null; |
|||
var req = this.protocol.request(options, function(res) { |
|||
|
|||
var buf = ''; |
|||
res.on('data', function(data) { |
|||
buf += data; |
|||
}); |
|||
res.on('end', function() { |
|||
if(res.statusCode == 401) { |
|||
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized')); |
|||
return; |
|||
} |
|||
if(res.statusCode == 403) { |
|||
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden')); |
|||
return; |
|||
} |
|||
|
|||
if(err) { |
|||
callback(err); |
|||
return; |
|||
} |
|||
try { |
|||
var parsedBuf = JSON.parse(buf); |
|||
} catch(e) { |
|||
log.err(e.stack); |
|||
log.err(buf); |
|||
log.err('HTTP Status code:' + res.statusCode); |
|||
callback(e); |
|||
return; |
|||
} |
|||
callback(parsedBuf.error, parsedBuf); |
|||
}); |
|||
var buf = ''; |
|||
res.on('data', function(data) { |
|||
buf += data; |
|||
}); |
|||
req.on('error', function(e) { |
|||
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); |
|||
req.write(request); |
|||
req.end(); |
|||
}; |
|||
res.on('end', function() { |
|||
if(res.statusCode == 401) { |
|||
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized')); |
|||
return; |
|||
} |
|||
if(res.statusCode == 403) { |
|||
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden')); |
|||
return; |
|||
} |
|||
|
|||
generateRPCMethods(RpcClient, callspec, rpc); |
|||
return RpcClient; |
|||
if(err) { |
|||
callback(err); |
|||
return; |
|||
} |
|||
try { |
|||
var parsedBuf = JSON.parse(buf); |
|||
} catch(e) { |
|||
log.err(e.stack); |
|||
log.err(buf); |
|||
log.err('HTTP Status code:' + res.statusCode); |
|||
callback(e); |
|||
return; |
|||
} |
|||
callback(parsedBuf.error, parsedBuf); |
|||
}); |
|||
}); |
|||
req.on('error', function(e) { |
|||
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); |
|||
req.write(request); |
|||
req.end(); |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
generateRPCMethods(RpcClient, callspec, rpc); |
|||
|
|||
module.exports = require('soop')(RpcClient); |
|||
|
|||
|
@ -1,60 +1,55 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
var parent = imports.parent || require('./util/VersionedData'); |
|||
|
|||
function ClassSpec(b) { |
|||
var superclass = b.superclass || require('./util/VersionedData').class(); |
|||
|
|||
|
|||
function SIN(type, payload) { |
|||
if (typeof type != 'number') { |
|||
SIN.super(this, arguments); |
|||
return; |
|||
}; |
|||
this.data = new Buffer(1 + 1 + payload.length); |
|||
this.__proto__ = this.encodings['binary']; |
|||
this.prefix(0x0F); // SIN magic number, in numberspace
|
|||
this.type(type); |
|||
this.payload(payload); |
|||
}; |
|||
SIN.superclass = superclass; |
|||
superclass.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
|
|||
|
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(0); |
|||
function SIN(type, payload) { |
|||
if (typeof type != 'number') { |
|||
SIN.super(this, arguments); |
|||
return; |
|||
}; |
|||
this.data = new Buffer(1 + 1 + payload.length); |
|||
this.__proto__ = this.encodings['binary']; |
|||
this.prefix(0x0F); // SIN magic number, in numberspace
|
|||
this.type(type); |
|||
this.payload(payload); |
|||
}; |
|||
SIN.parent = parent; |
|||
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
|
|||
|
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(0); |
|||
}; |
|||
|
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(1); |
|||
}; |
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(1); |
|||
}; |
|||
|
|||
// 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);}); |
|||
return data; |
|||
} |
|||
return this.as('binary').slice(1); |
|||
}; |
|||
// 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);}); |
|||
return data; |
|||
} |
|||
return this.as('binary').slice(1); |
|||
}; |
|||
|
|||
SIN.prototype.validate = function() { |
|||
this.doAsBinary(function() { |
|||
SIN.super(this, 'validate', arguments); |
|||
if (this.data.length != 22) throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
return SIN; |
|||
SIN.prototype.validate = function() { |
|||
this.doAsBinary(function() { |
|||
SIN.super(this, 'validate', arguments); |
|||
if (this.data.length != 22) throw new Error('invalid data length'); |
|||
}); |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
module.exports = require('soop')(SIN); |
|||
|
@ -1,43 +1,37 @@ |
|||
require('classtool'); |
|||
var coinUtil = require('./util/util'); |
|||
var timeUtil = require('./util/time'); |
|||
var KeyModule = require('./Key'); |
|||
var SIN = require('./SIN'); |
|||
|
|||
function ClassSpec(b) { |
|||
var coinUtil = require('./util/util'); |
|||
var timeUtil = require('./util/time'); |
|||
var KeyModule = require('./Key'); |
|||
var SIN = require('./SIN').class(); |
|||
function SINKey(cfg) { |
|||
if (typeof cfg != 'object') |
|||
cfg = {}; |
|||
|
|||
function SINKey(cfg) { |
|||
if (typeof cfg != 'object') |
|||
cfg = {}; |
|||
|
|||
this.created = cfg.created; |
|||
this.privKey = cfg.privKey; |
|||
}; |
|||
|
|||
SINKey.prototype.generate = function() { |
|||
this.privKey = KeyModule.Key.generateSync(); |
|||
this.created = timeUtil.curtime(); |
|||
}; |
|||
this.created = cfg.created; |
|||
this.privKey = cfg.privKey; |
|||
}; |
|||
|
|||
SINKey.prototype.pubkeyHash = function() { |
|||
return coinUtil.sha256ripe160(this.privKey.public); |
|||
}; |
|||
SINKey.prototype.generate = function() { |
|||
this.privKey = KeyModule.Key.generateSync(); |
|||
this.created = timeUtil.curtime(); |
|||
}; |
|||
|
|||
SINKey.prototype.storeObj = function() { |
|||
var pubKey = this.privKey.public.toString('hex'); |
|||
var pubKeyHash = this.pubkeyHash(); |
|||
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash); |
|||
var obj = { |
|||
created: this.created, |
|||
priv: this.privKey.private.toString('hex'), |
|||
pub: pubKey, |
|||
sin: sin.toString(), |
|||
}; |
|||
SINKey.prototype.pubkeyHash = function() { |
|||
return coinUtil.sha256ripe160(this.privKey.public); |
|||
}; |
|||
|
|||
return obj; |
|||
SINKey.prototype.storeObj = function() { |
|||
var pubKey = this.privKey.public.toString('hex'); |
|||
var pubKeyHash = this.pubkeyHash(); |
|||
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash); |
|||
var obj = { |
|||
created: this.created, |
|||
priv: this.privKey.private.toString('hex'), |
|||
pub: pubKey, |
|||
sin: sin.toString(), |
|||
}; |
|||
|
|||
return SINKey; |
|||
return obj; |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
module.exports = require('soop')(SINKey); |
|||
|
@ -1,523 +1,517 @@ |
|||
require('classtool'); |
|||
|
|||
function spec(b) { |
|||
var config = b.config || require('./config'); |
|||
var log = b.log || require('./util/log'); |
|||
|
|||
var Opcode = b.Opcode || require('./Opcode').class(); |
|||
var buffertools = b.buffertools || require('buffertools'); |
|||
|
|||
// Make opcodes available as pseudo-constants
|
|||
for (var i in Opcode.map) { |
|||
eval(i + " = " + Opcode.map[i] + ";"); |
|||
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'); |
|||
|
|||
// Make opcodes available as pseudo-constants
|
|||
for (var i in Opcode.map) { |
|||
eval(i + ' = ' + Opcode.map[i] + ';'); |
|||
} |
|||
|
|||
var util = imports.util || require('./util/util'); |
|||
var Parser = imports.Parser || require('./util/BinaryParser'); |
|||
var Put = imports.Put || require('bufferput'); |
|||
|
|||
var TX_UNKNOWN = 0; |
|||
var TX_PUBKEY = 1; |
|||
var TX_PUBKEYHASH = 2; |
|||
var TX_MULTISIG = 3; |
|||
var TX_SCRIPTHASH = 4; |
|||
|
|||
var TX_TYPES = [ |
|||
'unknown', |
|||
'pubkey', |
|||
'pubkeyhash', |
|||
'multisig', |
|||
'scripthash' |
|||
]; |
|||
|
|||
function Script(buffer) { |
|||
if(buffer) { |
|||
this.buffer = buffer; |
|||
} else { |
|||
this.buffer = util.EMPTY_BUFFER; |
|||
} |
|||
|
|||
var util = b.util || require('./util/util'); |
|||
var Parser = b.Parser || require('./util/BinaryParser').class(); |
|||
var Put = b.Put || require('bufferput'); |
|||
|
|||
var TX_UNKNOWN = 0; |
|||
var TX_PUBKEY = 1; |
|||
var TX_PUBKEYHASH = 2; |
|||
var TX_MULTISIG = 3; |
|||
var TX_SCRIPTHASH = 4; |
|||
|
|||
var TX_TYPES = [ |
|||
'unknown', |
|||
'pubkey', |
|||
'pubkeyhash', |
|||
'multisig', |
|||
'scripthash' |
|||
]; |
|||
|
|||
function Script(buffer) { |
|||
if(buffer) { |
|||
this.buffer = buffer; |
|||
this.chunks = []; |
|||
this.parse(); |
|||
}; |
|||
this.class = Script; |
|||
|
|||
Script.TX_UNKNOWN=TX_UNKNOWN; |
|||
Script.TX_PUBKEY=TX_PUBKEY; |
|||
Script.TX_PUBKEYHASH=TX_PUBKEYHASH; |
|||
Script.TX_MULTISIG=TX_MULTISIG; |
|||
Script.TX_SCRIPTHASH=TX_SCRIPTHASH; |
|||
|
|||
Script.prototype.parse = function () { |
|||
this.chunks = []; |
|||
|
|||
var parser = new Parser(this.buffer); |
|||
while (!parser.eof()) { |
|||
var opcode = parser.word8(); |
|||
|
|||
var len; |
|||
if (opcode > 0 && opcode < OP_PUSHDATA1) { |
|||
// Read some bytes of data, opcode value is the length of data
|
|||
this.chunks.push(parser.buffer(opcode)); |
|||
} else if (opcode == OP_PUSHDATA1) { |
|||
len = parser.word8(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else if (opcode == OP_PUSHDATA2) { |
|||
len = parser.word16le(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else if (opcode == OP_PUSHDATA4) { |
|||
len = parser.word32le(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else { |
|||
this.buffer = util.EMPTY_BUFFER; |
|||
this.chunks.push(opcode); |
|||
} |
|||
this.chunks = []; |
|||
this.parse(); |
|||
}; |
|||
this.class = Script; |
|||
|
|||
Script.TX_UNKNOWN=TX_UNKNOWN; |
|||
Script.TX_PUBKEY=TX_PUBKEY; |
|||
Script.TX_PUBKEYHASH=TX_PUBKEYHASH; |
|||
Script.TX_MULTISIG=TX_MULTISIG; |
|||
Script.TX_SCRIPTHASH=TX_SCRIPTHASH; |
|||
|
|||
Script.prototype.parse = function () { |
|||
this.chunks = []; |
|||
|
|||
var parser = new Parser(this.buffer); |
|||
while (!parser.eof()) { |
|||
var opcode = parser.word8(); |
|||
|
|||
var len; |
|||
if (opcode > 0 && opcode < OP_PUSHDATA1) { |
|||
// Read some bytes of data, opcode value is the length of data
|
|||
this.chunks.push(parser.buffer(opcode)); |
|||
} else if (opcode == OP_PUSHDATA1) { |
|||
len = parser.word8(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else if (opcode == OP_PUSHDATA2) { |
|||
len = parser.word16le(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else if (opcode == OP_PUSHDATA4) { |
|||
len = parser.word32le(); |
|||
this.chunks.push(parser.buffer(len)); |
|||
} else { |
|||
this.chunks.push(opcode); |
|||
} |
|||
} |
|||
}; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.isPushOnly = function () |
|||
{ |
|||
for (var i = 0; i < this.chunks.length; i++) |
|||
if (!Buffer.isBuffer(this.chunks[i])) |
|||
return false; |
|||
Script.prototype.isPushOnly = function () |
|||
{ |
|||
for (var i = 0; i < this.chunks.length; i++) |
|||
if (!Buffer.isBuffer(this.chunks[i])) |
|||
return false; |
|||
|
|||
return true; |
|||
}; |
|||
return true; |
|||
}; |
|||
|
|||
Script.prototype.isP2SH = function () |
|||
{ |
|||
return (this.chunks.length == 3 && |
|||
this.chunks[0] == OP_HASH160 && |
|||
Buffer.isBuffer(this.chunks[1]) && |
|||
this.chunks[1].length == 20 && |
|||
this.chunks[2] == OP_EQUAL); |
|||
}; |
|||
|
|||
Script.prototype.isPubkey = function () |
|||
{ |
|||
return (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
this.chunks[1] == OP_CHECKSIG); |
|||
}; |
|||
Script.prototype.isP2SH = function () |
|||
{ |
|||
return (this.chunks.length == 3 && |
|||
this.chunks[0] == OP_HASH160 && |
|||
Buffer.isBuffer(this.chunks[1]) && |
|||
this.chunks[1].length == 20 && |
|||
this.chunks[2] == OP_EQUAL); |
|||
}; |
|||
|
|||
Script.prototype.isPubkeyHash = function () |
|||
{ |
|||
return (this.chunks.length == 5 && |
|||
this.chunks[0] == OP_DUP && |
|||
this.chunks[1] == OP_HASH160 && |
|||
Buffer.isBuffer(this.chunks[2]) && |
|||
this.chunks[2].length == 20 && |
|||
this.chunks[3] == OP_EQUALVERIFY && |
|||
this.chunks[4] == OP_CHECKSIG); |
|||
}; |
|||
|
|||
function isSmallIntOp(opcode) |
|||
{ |
|||
return ((opcode == OP_0) || |
|||
((opcode >= OP_1) && (opcode <= OP_16))); |
|||
}; |
|||
Script.prototype.isPubkey = function () |
|||
{ |
|||
return (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
this.chunks[1] == OP_CHECKSIG); |
|||
}; |
|||
|
|||
Script.prototype.isMultiSig = function () |
|||
{ |
|||
return (this.chunks.length > 3 && |
|||
isSmallIntOp(this.chunks[0]) && |
|||
isSmallIntOp(this.chunks[this.chunks.length-2]) && |
|||
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG); |
|||
}; |
|||
Script.prototype.isPubkeyHash = function () |
|||
{ |
|||
return (this.chunks.length == 5 && |
|||
this.chunks[0] == OP_DUP && |
|||
this.chunks[1] == OP_HASH160 && |
|||
Buffer.isBuffer(this.chunks[2]) && |
|||
this.chunks[2].length == 20 && |
|||
this.chunks[3] == OP_EQUALVERIFY && |
|||
this.chunks[4] == OP_CHECKSIG); |
|||
}; |
|||
|
|||
Script.prototype.finishedMultiSig = function() |
|||
{ |
|||
var nsigs = 0; |
|||
for (var i = 0; i < this.chunks.length-1; i++) |
|||
if (this.chunks[i] !== 0) |
|||
nsigs++; |
|||
|
|||
var serializedScript = this.chunks[this.chunks.length-1]; |
|||
var script = new Script(serializedScript); |
|||
var nreq = script.chunks[0] - 80; //see OP_2-OP_16
|
|||
|
|||
if (nsigs == nreq) |
|||
return true; |
|||
else |
|||
return false; |
|||
} |
|||
function isSmallIntOp(opcode) |
|||
{ |
|||
return ((opcode == OP_0) || |
|||
((opcode >= OP_1) && (opcode <= OP_16))); |
|||
}; |
|||
|
|||
Script.prototype.isMultiSig = function () |
|||
{ |
|||
return (this.chunks.length > 3 && |
|||
isSmallIntOp(this.chunks[0]) && |
|||
isSmallIntOp(this.chunks[this.chunks.length-2]) && |
|||
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG); |
|||
}; |
|||
|
|||
Script.prototype.finishedMultiSig = function() |
|||
{ |
|||
var nsigs = 0; |
|||
for (var i = 0; i < this.chunks.length-1; i++) |
|||
if (this.chunks[i] !== 0) |
|||
nsigs++; |
|||
|
|||
Script.prototype.removePlaceHolders = function() |
|||
var serializedScript = this.chunks[this.chunks.length-1]; |
|||
var script = new Script(serializedScript); |
|||
var nreq = script.chunks[0] - 80; //see OP_2-OP_16
|
|||
|
|||
if (nsigs == nreq) |
|||
return true; |
|||
else |
|||
return false; |
|||
} |
|||
|
|||
Script.prototype.removePlaceHolders = function() |
|||
{ |
|||
var chunks = []; |
|||
for (var i in this.chunks) |
|||
{ |
|||
var chunks = []; |
|||
for (var i in this.chunks) |
|||
{ |
|||
if (this.chunks.hasOwnProperty(i)) { |
|||
var chunk = this.chunks[i]; |
|||
if (chunk != 0) |
|||
chunks.push(chunk); |
|||
} |
|||
if (this.chunks.hasOwnProperty(i)) { |
|||
var chunk = this.chunks[i]; |
|||
if (chunk != 0) |
|||
chunks.push(chunk); |
|||
} |
|||
this.chunks = chunks; |
|||
this.updateBuffer(); |
|||
return this; |
|||
} |
|||
|
|||
Script.prototype.prependOp0 = function() |
|||
{ |
|||
var chunks = [0]; |
|||
for (i in this.chunks) { |
|||
if (this.chunks.hasOwnProperty(i)) { |
|||
chunks.push(this.chunks[i]); |
|||
} |
|||
this.chunks = chunks; |
|||
this.updateBuffer(); |
|||
return this; |
|||
} |
|||
|
|||
Script.prototype.prependOp0 = function() |
|||
{ |
|||
var chunks = [0]; |
|||
for (i in this.chunks) { |
|||
if (this.chunks.hasOwnProperty(i)) { |
|||
chunks.push(this.chunks[i]); |
|||
} |
|||
this.chunks = chunks; |
|||
this.updateBuffer(); |
|||
return this; |
|||
} |
|||
this.chunks = chunks; |
|||
this.updateBuffer(); |
|||
return this; |
|||
} |
|||
|
|||
// is this a script form we know?
|
|||
Script.prototype.classify = function () |
|||
{ |
|||
if (this.isPubkeyHash()) |
|||
return TX_PUBKEYHASH; |
|||
if (this.isP2SH()) |
|||
return TX_SCRIPTHASH; |
|||
if (this.isMultiSig()) |
|||
return TX_MULTISIG; |
|||
if (this.isPubkey()) |
|||
return TX_PUBKEY; |
|||
return TX_UNKNOWN; |
|||
}; |
|||
|
|||
// is this a script form we know?
|
|||
Script.prototype.classify = function () |
|||
{ |
|||
if (this.isPubkeyHash()) |
|||
return TX_PUBKEYHASH; |
|||
if (this.isP2SH()) |
|||
return TX_SCRIPTHASH; |
|||
if (this.isMultiSig()) |
|||
return TX_MULTISIG; |
|||
if (this.isPubkey()) |
|||
return TX_PUBKEY; |
|||
return TX_UNKNOWN; |
|||
}; |
|||
|
|||
// extract useful data items from known scripts
|
|||
Script.prototype.capture = function () |
|||
{ |
|||
var txType = this.classify(); |
|||
var res = []; |
|||
// extract useful data items from known scripts
|
|||
Script.prototype.capture = function () |
|||
{ |
|||
var txType = this.classify(); |
|||
var res = []; |
|||
switch (txType) { |
|||
case TX_PUBKEY: |
|||
res.push(this.chunks[0]); |
|||
break; |
|||
case TX_PUBKEYHASH: |
|||
res.push(this.chunks[2]); |
|||
break; |
|||
case TX_MULTISIG: |
|||
for (var i = 1; i < (this.chunks.length - 2); i++) |
|||
res.push(this.chunks[i]); |
|||
break; |
|||
case TX_SCRIPTHASH: |
|||
res.push(this.chunks[1]); |
|||
break; |
|||
|
|||
case TX_UNKNOWN: |
|||
default: |
|||
// do nothing
|
|||
break; |
|||
} |
|||
|
|||
return res; |
|||
}; |
|||
|
|||
// return first extracted data item from script
|
|||
Script.prototype.captureOne = function () |
|||
{ |
|||
var arr = this.capture(); |
|||
return arr[0]; |
|||
}; |
|||
|
|||
Script.prototype.getOutType = function () |
|||
{ |
|||
var txType = this.classify(); |
|||
switch (txType) { |
|||
case TX_PUBKEY: |
|||
res.push(this.chunks[0]); |
|||
break; |
|||
case TX_PUBKEYHASH: |
|||
res.push(this.chunks[2]); |
|||
break; |
|||
case TX_MULTISIG: |
|||
for (var i = 1; i < (this.chunks.length - 2); i++) |
|||
res.push(this.chunks[i]); |
|||
break; |
|||
case TX_SCRIPTHASH: |
|||
res.push(this.chunks[1]); |
|||
break; |
|||
|
|||
case TX_UNKNOWN: |
|||
case TX_PUBKEY: return 'Pubkey'; |
|||
case TX_PUBKEYHASH: return 'Address'; |
|||
default: return 'Strange'; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.getRawOutType = function() { |
|||
return TX_TYPES[this.classify()]; |
|||
}; |
|||
|
|||
Script.prototype.simpleOutHash = function () |
|||
{ |
|||
switch (this.getOutType()) { |
|||
case 'Address': |
|||
return this.chunks[2]; |
|||
case 'Pubkey': |
|||
return util.sha256ripe160(this.chunks[0]); |
|||
default: |
|||
// do nothing
|
|||
break; |
|||
log.debug("Encountered non-standard scriptPubKey"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
return res; |
|||
}; |
|||
Script.prototype.getInType = function () |
|||
{ |
|||
if (this.chunks.length == 1) { |
|||
// Direct IP to IP transactions only have the public key in their scriptSig.
|
|||
return 'Pubkey'; |
|||
} else if (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
Buffer.isBuffer(this.chunks[1])) { |
|||
return 'Address'; |
|||
} else { |
|||
return 'Strange'; |
|||
} |
|||
}; |
|||
|
|||
// return first extracted data item from script
|
|||
Script.prototype.captureOne = function () |
|||
{ |
|||
var arr = this.capture(); |
|||
return arr[0]; |
|||
}; |
|||
Script.prototype.simpleInPubKey = function () |
|||
{ |
|||
switch (this.getInType()) { |
|||
case 'Address': |
|||
return this.chunks[1]; |
|||
case 'Pubkey': |
|||
return null; |
|||
default: |
|||
log.debug("Encountered non-standard scriptSig"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.getOutType = function () |
|||
{ |
|||
var txType = this.classify(); |
|||
switch (txType) { |
|||
case TX_PUBKEY: return 'Pubkey'; |
|||
case TX_PUBKEYHASH: return 'Address'; |
|||
default: return 'Strange'; |
|||
} |
|||
}; |
|||
Script.prototype.getBuffer = function () |
|||
{ |
|||
return this.buffer; |
|||
}; |
|||
|
|||
Script.prototype.getRawOutType = function() { |
|||
return TX_TYPES[this.classify()]; |
|||
}; |
|||
Script.prototype.getStringContent = function (truncate, maxEl) |
|||
{ |
|||
if (truncate === null) { |
|||
truncate = true; |
|||
} |
|||
|
|||
Script.prototype.simpleOutHash = function () |
|||
{ |
|||
switch (this.getOutType()) { |
|||
case 'Address': |
|||
return this.chunks[2]; |
|||
case 'Pubkey': |
|||
return util.sha256ripe160(this.chunks[0]); |
|||
default: |
|||
log.debug("Encountered non-standard scriptPubKey"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
} |
|||
}; |
|||
if ("undefined" === typeof maxEl) { |
|||
maxEl = 15; |
|||
} |
|||
|
|||
Script.prototype.getInType = function () |
|||
{ |
|||
if (this.chunks.length == 1) { |
|||
// Direct IP to IP transactions only have the public key in their scriptSig.
|
|||
return 'Pubkey'; |
|||
} else if (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
Buffer.isBuffer(this.chunks[1])) { |
|||
return 'Address'; |
|||
} else { |
|||
return 'Strange'; |
|||
} |
|||
}; |
|||
var script = ''; |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
var chunk = this.chunks[i]; |
|||
|
|||
Script.prototype.simpleInPubKey = function () |
|||
{ |
|||
switch (this.getInType()) { |
|||
case 'Address': |
|||
return this.chunks[1]; |
|||
case 'Pubkey': |
|||
return null; |
|||
default: |
|||
log.debug("Encountered non-standard scriptSig"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
if (i > 0) { |
|||
script += " "; |
|||
} |
|||
}; |
|||
|
|||
Script.prototype.getBuffer = function () |
|||
{ |
|||
return this.buffer; |
|||
}; |
|||
|
|||
Script.prototype.getStringContent = function (truncate, maxEl) |
|||
{ |
|||
if (truncate === null) { |
|||
truncate = true; |
|||
if (Buffer.isBuffer(chunk)) { |
|||
script += "0x"+util.formatBuffer(chunk, truncate ? null : 0); |
|||
} else { |
|||
script += Opcode.reverseMap[chunk]; |
|||
} |
|||
|
|||
if ("undefined" === typeof maxEl) { |
|||
maxEl = 15; |
|||
if (maxEl && i > maxEl) { |
|||
script += " ..."; |
|||
break; |
|||
} |
|||
} |
|||
return script; |
|||
}; |
|||
|
|||
var script = ''; |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
var chunk = this.chunks[i]; |
|||
Script.prototype.toString = function (truncate, maxEl) |
|||
{ |
|||
var script = "<Script "; |
|||
script += this.getStringContent(truncate, maxEl); |
|||
script += ">"; |
|||
return script; |
|||
}; |
|||
|
|||
if (i > 0) { |
|||
script += " "; |
|||
} |
|||
|
|||
if (Buffer.isBuffer(chunk)) { |
|||
script += "0x"+util.formatBuffer(chunk, truncate ? null : 0); |
|||
} else { |
|||
script += Opcode.reverseMap[chunk]; |
|||
} |
|||
Script.prototype.writeOp = function (opcode) |
|||
{ |
|||
var buf = Buffer(this.buffer.length + 1); |
|||
this.buffer.copy(buf); |
|||
buf.writeUInt8(opcode, this.buffer.length); |
|||
|
|||
if (maxEl && i > maxEl) { |
|||
script += " ..."; |
|||
break; |
|||
} |
|||
} |
|||
return script; |
|||
}; |
|||
this.buffer = buf; |
|||
|
|||
Script.prototype.toString = function (truncate, maxEl) |
|||
{ |
|||
var script = "<Script "; |
|||
script += this.getStringContent(truncate, maxEl); |
|||
script += ">"; |
|||
return script; |
|||
}; |
|||
this.chunks.push(opcode); |
|||
}; |
|||
|
|||
Script.prototype.writeN = function (n) |
|||
{ |
|||
if (n < 0 || n > 16) |
|||
throw new Error("writeN: out of range value " + n); |
|||
|
|||
Script.prototype.writeOp = function (opcode) |
|||
{ |
|||
var buf = Buffer(this.buffer.length + 1); |
|||
this.buffer.copy(buf); |
|||
buf.writeUInt8(opcode, this.buffer.length); |
|||
if (n == 0) |
|||
this.writeOp(OP_0); |
|||
else |
|||
this.writeOp(OP_1 + n - 1); |
|||
}; |
|||
|
|||
this.buffer = buf; |
|||
function prefixSize(data_length) |
|||
{ |
|||
if (data_length < OP_PUSHDATA1) { |
|||
return 1; |
|||
} else if (data_length <= 0xff) { |
|||
return 1 + 1; |
|||
} else if (data_length <= 0xffff) { |
|||
return 1 + 2; |
|||
} else { |
|||
return 1 + 4; |
|||
} |
|||
}; |
|||
|
|||
this.chunks.push(opcode); |
|||
}; |
|||
function encodeLen(data_length) { |
|||
var buf = undefined; |
|||
if (data_length < OP_PUSHDATA1) { |
|||
buf = new Buffer(1); |
|||
buf.writeUInt8(data_length, 0); |
|||
} |
|||
|
|||
else if (data_length <= 0xff) { |
|||
buf = new Buffer(1 + 1); |
|||
buf.writeUInt8(OP_PUSHDATA1, 0); |
|||
buf.writeUInt8(data_length, 1); |
|||
} |
|||
|
|||
else if (data_length <= 0xffff) { |
|||
buf = new Buffer(1 + 2); |
|||
buf.writeUInt8(OP_PUSHDATA2, 0); |
|||
buf.writeUInt16LE(data_length, 1); |
|||
} |
|||
|
|||
else { |
|||
buf = new Buffer(1 + 4); |
|||
buf.writeUInt8(OP_PUSHDATA4, 0); |
|||
buf.writeUInt32LE(data_length, 1); |
|||
} |
|||
|
|||
Script.prototype.writeN = function (n) |
|||
{ |
|||
if (n < 0 || n > 16) |
|||
throw new Error("writeN: out of range value " + n); |
|||
return buf; |
|||
}; |
|||
|
|||
if (n == 0) |
|||
this.writeOp(OP_0); |
|||
else |
|||
this.writeOp(OP_1 + n - 1); |
|||
}; |
|||
Script.prototype.writeBytes = function (data) |
|||
{ |
|||
var newSize = this.buffer.length + prefixSize(data.length) + data.length; |
|||
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]); |
|||
this.chunks.push(data); |
|||
}; |
|||
|
|||
function prefixSize(data_length) |
|||
{ |
|||
if (data_length < OP_PUSHDATA1) { |
|||
return 1; |
|||
} else if (data_length <= 0xff) { |
|||
return 1 + 1; |
|||
} else if (data_length <= 0xffff) { |
|||
return 1 + 2; |
|||
} else { |
|||
return 1 + 4; |
|||
} |
|||
}; |
|||
Script.prototype.updateBuffer = function () |
|||
{ |
|||
this.buffer = Script.chunksToBuffer(this.chunks); |
|||
}; |
|||
|
|||
function encodeLen(data_length) { |
|||
var buf = undefined; |
|||
if (data_length < OP_PUSHDATA1) { |
|||
buf = new Buffer(1); |
|||
buf.writeUInt8(data_length, 0); |
|||
} |
|||
|
|||
else if (data_length <= 0xff) { |
|||
buf = new Buffer(1 + 1); |
|||
buf.writeUInt8(OP_PUSHDATA1, 0); |
|||
buf.writeUInt8(data_length, 1); |
|||
} |
|||
|
|||
else if (data_length <= 0xffff) { |
|||
buf = new Buffer(1 + 2); |
|||
buf.writeUInt8(OP_PUSHDATA2, 0); |
|||
buf.writeUInt16LE(data_length, 1); |
|||
Script.prototype.findAndDelete = function (chunk) |
|||
{ |
|||
var dirty = false; |
|||
if (Buffer.isBuffer(chunk)) { |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
if (Buffer.isBuffer(this.chunks[i]) && |
|||
buffertools.compare(this.chunks[i], chunk) === 0) { |
|||
this.chunks.splice(i, 1); |
|||
dirty = true; |
|||
} |
|||
} |
|||
|
|||
else { |
|||
buf = new Buffer(1 + 4); |
|||
buf.writeUInt8(OP_PUSHDATA4, 0); |
|||
buf.writeUInt32LE(data_length, 1); |
|||
} else if ("number" === typeof chunk) { |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
if (this.chunks[i] === chunk) { |
|||
this.chunks.splice(i, 1); |
|||
dirty = true; |
|||
} |
|||
} |
|||
} else { |
|||
throw new Error("Invalid chunk datatype."); |
|||
} |
|||
if (dirty) { |
|||
this.updateBuffer(); |
|||
} |
|||
}; |
|||
|
|||
return buf; |
|||
}; |
|||
/** |
|||
* Creates a simple OP_CHECKSIG with pubkey output script. |
|||
* |
|||
* These are used for coinbase transactions and at some point were used for |
|||
* IP-based transactions as well. |
|||
*/ |
|||
Script.createPubKeyOut = function (pubkey) { |
|||
var script = new Script(); |
|||
script.writeBytes(pubkey); |
|||
script.writeOp(OP_CHECKSIG); |
|||
return script; |
|||
}; |
|||
|
|||
Script.prototype.writeBytes = function (data) |
|||
{ |
|||
var newSize = this.buffer.length + prefixSize(data.length) + data.length; |
|||
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]); |
|||
this.chunks.push(data); |
|||
}; |
|||
/** |
|||
* Creates a standard txout script. |
|||
*/ |
|||
Script.createPubKeyHashOut = function (pubKeyHash) { |
|||
var script = new Script(); |
|||
script.writeOp(OP_DUP); |
|||
script.writeOp(OP_HASH160); |
|||
script.writeBytes(pubKeyHash); |
|||
script.writeOp(OP_EQUALVERIFY); |
|||
script.writeOp(OP_CHECKSIG); |
|||
return script; |
|||
}; |
|||
|
|||
Script.prototype.updateBuffer = function () |
|||
{ |
|||
this.buffer = Script.chunksToBuffer(this.chunks); |
|||
}; |
|||
Script.createMultisig = function(n_required, keys) { |
|||
var script = new Script(); |
|||
script.writeN(n_required); |
|||
keys.forEach(function(key) { |
|||
script.writeBytes(key); |
|||
}); |
|||
script.writeN(keys.length); |
|||
script.writeOp(OP_CHECKMULTISIG); |
|||
return script; |
|||
}; |
|||
|
|||
Script.prototype.findAndDelete = function (chunk) |
|||
{ |
|||
var dirty = false; |
|||
if (Buffer.isBuffer(chunk)) { |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
if (Buffer.isBuffer(this.chunks[i]) && |
|||
buffertools.compare(this.chunks[i], chunk) === 0) { |
|||
this.chunks.splice(i, 1); |
|||
dirty = true; |
|||
} |
|||
} |
|||
} else if ("number" === typeof chunk) { |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
if (this.chunks[i] === chunk) { |
|||
this.chunks.splice(i, 1); |
|||
dirty = true; |
|||
} |
|||
} |
|||
Script.createP2SH = function(scriptHash) { |
|||
var script = new Script(); |
|||
script.writeOp(OP_HASH160); |
|||
script.writeBytes(scriptHash); |
|||
script.writeOp(OP_EQUAL); |
|||
return script; |
|||
}; |
|||
|
|||
Script.fromTestData = function (testData) { |
|||
testData = testData.map(function (chunk) { |
|||
if ("string" === typeof chunk) { |
|||
return new Buffer(chunk, 'hex'); |
|||
} else { |
|||
throw new Error("Invalid chunk datatype."); |
|||
} |
|||
if (dirty) { |
|||
this.updateBuffer(); |
|||
return chunk; |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* Creates a simple OP_CHECKSIG with pubkey output script. |
|||
* |
|||
* These are used for coinbase transactions and at some point were used for |
|||
* IP-based transactions as well. |
|||
*/ |
|||
Script.createPubKeyOut = function (pubkey) { |
|||
var script = new Script(); |
|||
script.writeBytes(pubkey); |
|||
script.writeOp(OP_CHECKSIG); |
|||
return script; |
|||
}; |
|||
|
|||
/** |
|||
* Creates a standard txout script. |
|||
*/ |
|||
Script.createPubKeyHashOut = function (pubKeyHash) { |
|||
var script = new Script(); |
|||
script.writeOp(OP_DUP); |
|||
script.writeOp(OP_HASH160); |
|||
script.writeBytes(pubKeyHash); |
|||
script.writeOp(OP_EQUALVERIFY); |
|||
script.writeOp(OP_CHECKSIG); |
|||
return script; |
|||
}; |
|||
|
|||
Script.createMultisig = function(n_required, keys) { |
|||
var script = new Script(); |
|||
script.writeN(n_required); |
|||
keys.forEach(function(key) { |
|||
script.writeBytes(key); |
|||
}); |
|||
script.writeN(keys.length); |
|||
script.writeOp(OP_CHECKMULTISIG); |
|||
return script; |
|||
}; |
|||
|
|||
Script.createP2SH = function(scriptHash) { |
|||
var script = new Script(); |
|||
script.writeOp(OP_HASH160); |
|||
script.writeBytes(scriptHash); |
|||
script.writeOp(OP_EQUAL); |
|||
return script; |
|||
}; |
|||
|
|||
Script.fromTestData = function (testData) { |
|||
testData = testData.map(function (chunk) { |
|||
if ("string" === typeof chunk) { |
|||
return new Buffer(chunk, 'hex'); |
|||
} else { |
|||
return chunk; |
|||
} |
|||
}); |
|||
|
|||
var script = new Script(); |
|||
script.chunks = testData; |
|||
script.updateBuffer(); |
|||
return script; |
|||
}; |
|||
|
|||
Script.fromChunks = function (chunks) { |
|||
var script = new Script(); |
|||
script.chunks = chunks; |
|||
script.updateBuffer(); |
|||
return script; |
|||
}; |
|||
|
|||
Script.chunksToBuffer = function (chunks) { |
|||
var buf = new Put(); |
|||
|
|||
for (var i = 0, l = chunks.length; i < l; i++) { |
|||
var data = chunks[i]; |
|||
if (Buffer.isBuffer(data)) { |
|||
if (data.length < OP_PUSHDATA1) { |
|||
buf.word8(data.length); |
|||
} else if (data.length <= 0xff) { |
|||
buf.word8(OP_PUSHDATA1); |
|||
buf.word8(data.length); |
|||
} else if (data.length <= 0xffff) { |
|||
buf.word8(OP_PUSHDATA2); |
|||
buf.word16le(data.length); |
|||
} else { |
|||
buf.word8(OP_PUSHDATA4); |
|||
buf.word32le(data.length); |
|||
} |
|||
buf.put(data); |
|||
} else if ("number" === typeof data) { |
|||
buf.word8(data); |
|||
}); |
|||
|
|||
var script = new Script(); |
|||
script.chunks = testData; |
|||
script.updateBuffer(); |
|||
return script; |
|||
}; |
|||
|
|||
Script.fromChunks = function (chunks) { |
|||
var script = new Script(); |
|||
script.chunks = chunks; |
|||
script.updateBuffer(); |
|||
return script; |
|||
}; |
|||
|
|||
Script.chunksToBuffer = function (chunks) { |
|||
var buf = new Put(); |
|||
|
|||
for (var i = 0, l = chunks.length; i < l; i++) { |
|||
var data = chunks[i]; |
|||
if (Buffer.isBuffer(data)) { |
|||
if (data.length < OP_PUSHDATA1) { |
|||
buf.word8(data.length); |
|||
} else if (data.length <= 0xff) { |
|||
buf.word8(OP_PUSHDATA1); |
|||
buf.word8(data.length); |
|||
} else if (data.length <= 0xffff) { |
|||
buf.word8(OP_PUSHDATA2); |
|||
buf.word16le(data.length); |
|||
} else { |
|||
throw new Error("Script.chunksToBuffer(): Invalid chunk datatype"); |
|||
buf.word8(OP_PUSHDATA4); |
|||
buf.word32le(data.length); |
|||
} |
|||
buf.put(data); |
|||
} else if ("number" === typeof data) { |
|||
buf.word8(data); |
|||
} else { |
|||
throw new Error("Script.chunksToBuffer(): Invalid chunk datatype"); |
|||
} |
|||
return buf.buffer(); |
|||
}; |
|||
|
|||
return Script; |
|||
} |
|||
return buf.buffer(); |
|||
}; |
|||
module.defineClass(spec); |
|||
|
|||
module.exports = require('soop')(Script); |
|||
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -1,142 +1,140 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
|
|||
var hex = function(hex) {return new Buffer(hex, 'hex');}; |
|||
|
|||
function ClassSpec(b) { |
|||
var fs = require('fs'); |
|||
var EncFile = require('./util/EncFile'); |
|||
var Address = require('./Address').class(); |
|||
var networks = require('./networks'); |
|||
var util = b.util || require('./util/util'); |
|||
var ENC_METHOD = 'aes-256-cbc'; |
|||
|
|||
var skeleton = { |
|||
client: 'libcoin', |
|||
client_version: '0.0.1', |
|||
network: 'testnet', |
|||
version: 1, |
|||
best_hash: null, |
|||
best_height: -1, |
|||
keys: [], |
|||
sin: {}, |
|||
scripts: {}, |
|||
}; |
|||
|
|||
function Wallet(cfg) { |
|||
if (typeof cfg !== 'object') |
|||
cfg = {}; |
|||
|
|||
// deep copy (no references)
|
|||
if (cfg.datastore) |
|||
this.datastore = JSON.parse(JSON.stringify(cfg.datastore)); |
|||
else |
|||
this.datastore = JSON.parse(JSON.stringify(skeleton)); |
|||
|
|||
this.network = undefined; |
|||
this.dirty = cfg.dirty || true; |
|||
}; |
|||
|
|||
Wallet.prototype.readSync = function(filename, passphrase) { |
|||
this.datastore = EncFile.readJFileSync(ENC_METHOD, |
|||
passphrase, filename); |
|||
this.dirty = false; |
|||
}; |
|||
|
|||
Wallet.prototype.writeSync = function(filename, passphrase) { |
|||
var tmp_fn = filename + ".tmp"; |
|||
|
|||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn, |
|||
this.datastore); |
|||
fs.renameSync(tmp_fn, filename); |
|||
|
|||
this.dirty = false; |
|||
}; |
|||
|
|||
Wallet.prototype.setNetwork = function(netname) { |
|||
if (!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"); |
|||
} |
|||
|
|||
// store+canonicalize name
|
|||
this.datastore['network'] = this.network.name; |
|||
this.dirty = true; |
|||
}; |
|||
|
|||
Wallet.prototype.addKey = function(wkey) { |
|||
this.datastore.keys.push(wkey); |
|||
this.dirty = true; |
|||
}; |
|||
|
|||
Wallet.prototype.addSIN = function(sinObj) { |
|||
this.datastore.sin[sinObj.sin] = sinObj; |
|||
this.dirty = true; |
|||
}; |
|||
|
|||
Wallet.prototype.findKeyHash = function(pubKeyHash) { |
|||
var pkhStr = pubKeyHash.toString(); |
|||
|
|||
for (var i = 0; i < this.datastore.keys.length; i++) { |
|||
var obj = this.datastore.keys[i]; |
|||
var addrStr = obj.addr; |
|||
var addr = new Address(addrStr); |
|||
if (addr.payload().toString() == pkhStr) |
|||
return obj; |
|||
} |
|||
|
|||
return undefined; |
|||
}; |
|||
|
|||
Wallet.prototype.expandKey = function(key) { |
|||
var addr = new Address(key); |
|||
var isAddr = true; |
|||
|
|||
try { |
|||
addr.validate(); |
|||
var b = addr.payload(); |
|||
var obj = this.findKeyHash(b); |
|||
key = obj.pub; |
|||
} catch(e) { |
|||
// do nothing
|
|||
} |
|||
|
|||
var re = /^[a-fA-F0-9]+$/; |
|||
if (!key.match(re)) |
|||
throw new Error("Unknown key type"); |
|||
return hex(key); |
|||
}; |
|||
|
|||
Wallet.prototype.expandKeys = function(keys) { |
|||
var res = []; |
|||
var us = this; |
|||
keys.forEach(function(key) { |
|||
var expKey = us.expandKey(key); |
|||
res.push(expKey); |
|||
}); |
|||
return res; |
|||
}; |
|||
|
|||
Wallet.prototype.addScript = function(script) { |
|||
var buf = script.getBuffer(); |
|||
var hash = util.sha256ripe160(buf); |
|||
var addr = new Address(this.network.addressScript, hash); |
|||
var addrStr = addr.as('base58'); |
|||
this.datastore.scripts[addrStr] = buf.toString('hex'); |
|||
this.dirty = true; |
|||
|
|||
return addrStr; |
|||
}; |
|||
|
|||
return Wallet; |
|||
var fs = require('fs'); |
|||
var EncFile = require('./util/EncFile'); |
|||
var Address = require('./Address'); |
|||
var networks = require('./networks'); |
|||
var util = imports.util || require('./util/util'); |
|||
var ENC_METHOD = 'aes-256-cbc'; |
|||
|
|||
var skeleton = { |
|||
client: 'libcoin', |
|||
client_version: '0.0.1', |
|||
network: 'testnet', |
|||
version: 1, |
|||
best_hash: null, |
|||
best_height: -1, |
|||
keys: [], |
|||
sin: {}, |
|||
scripts: {}, |
|||
}; |
|||
|
|||
function Wallet(cfg) { |
|||
if (typeof cfg !== 'object') |
|||
cfg = {}; |
|||
|
|||
// deep copy (no references)
|
|||
if (cfg.datastore) |
|||
this.datastore = JSON.parse(JSON.stringify(cfg.datastore)); |
|||
else |
|||
this.datastore = JSON.parse(JSON.stringify(skeleton)); |
|||
|
|||
this.network = undefined; |
|||
this.dirty = cfg.dirty || true; |
|||
}; |
|||
|
|||
Wallet.prototype.readSync = function(filename, passphrase) { |
|||
this.datastore = EncFile.readJFileSync(ENC_METHOD, |
|||
passphrase, filename); |
|||
this.dirty = false; |
|||
}; |
|||
|
|||
Wallet.prototype.writeSync = function(filename, passphrase) { |
|||
var tmp_fn = filename + ".tmp"; |
|||
|
|||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn, |
|||
this.datastore); |
|||
fs.renameSync(tmp_fn, filename); |
|||
|
|||
this.dirty = false; |
|||
}; |
|||
|
|||
Wallet.prototype.setNetwork = function(netname) { |
|||
if (!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"); |
|||
} |
|||
|
|||
// store+canonicalize name
|
|||
this.datastore['network'] = this.network.name; |
|||
this.dirty = true; |
|||
}; |
|||
|
|||
Wallet.prototype.addKey = function(wkey) { |
|||
this.datastore.keys.push(wkey); |
|||
this.dirty = true; |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
Wallet.prototype.addSIN = function(sinObj) { |
|||
this.datastore.sin[sinObj.sin] = sinObj; |
|||
this.dirty = true; |
|||
}; |
|||
|
|||
Wallet.prototype.findKeyHash = function(pubKeyHash) { |
|||
var pkhStr = pubKeyHash.toString(); |
|||
|
|||
for (var i = 0; i < this.datastore.keys.length; i++) { |
|||
var obj = this.datastore.keys[i]; |
|||
var addrStr = obj.addr; |
|||
var addr = new Address(addrStr); |
|||
if (addr.payload().toString() == pkhStr) |
|||
return obj; |
|||
} |
|||
|
|||
return undefined; |
|||
}; |
|||
|
|||
Wallet.prototype.expandKey = function(key) { |
|||
var addr = new Address(key); |
|||
var isAddr = true; |
|||
|
|||
try { |
|||
addr.validate(); |
|||
var b = addr.payload(); |
|||
var obj = this.findKeyHash(b); |
|||
key = obj.pub; |
|||
} catch(e) { |
|||
// do nothing
|
|||
} |
|||
|
|||
var re = /^[a-fA-F0-9]+$/; |
|||
if (!key.match(re)) |
|||
throw new Error("Unknown key type"); |
|||
return hex(key); |
|||
}; |
|||
|
|||
Wallet.prototype.expandKeys = function(keys) { |
|||
var res = []; |
|||
var us = this; |
|||
keys.forEach(function(key) { |
|||
var expKey = us.expandKey(key); |
|||
res.push(expKey); |
|||
}); |
|||
return res; |
|||
}; |
|||
|
|||
Wallet.prototype.addScript = function(script) { |
|||
var buf = script.getBuffer(); |
|||
var hash = util.sha256ripe160(buf); |
|||
var addr = new Address(this.network.addressScript, hash); |
|||
var addrStr = addr.as('base58'); |
|||
this.datastore.scripts[addrStr] = buf.toString('hex'); |
|||
this.dirty = true; |
|||
|
|||
return addrStr; |
|||
}; |
|||
|
|||
module.exports = require('soop')(Wallet); |
|||
|
|||
|
@ -1,55 +1,52 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
|
|||
function ClassSpec(b) { |
|||
var coinUtil = require('./util/util'); |
|||
var timeUtil = require('./util/time'); |
|||
var KeyModule = require('./Key'); |
|||
var PrivateKey = require('./PrivateKey').class(); |
|||
var Address = require('./Address').class(); |
|||
var coinUtil = require('./util/util'); |
|||
var timeUtil = require('./util/time'); |
|||
var KeyModule = require('./Key'); |
|||
var PrivateKey = require('./PrivateKey'); |
|||
var Address = require('./Address'); |
|||
|
|||
function WalletKey(cfg) { |
|||
if (!cfg) cfg = {}; |
|||
if (!cfg.network) throw new Error('network parameter is required'); |
|||
this.network = cfg.network; // required
|
|||
this.created = cfg.created; |
|||
this.privKey = cfg.privKey; |
|||
}; |
|||
|
|||
WalletKey.prototype.generate = function() { |
|||
this.privKey = KeyModule.Key.generateSync(); |
|||
this.created = timeUtil.curtime(); |
|||
}; |
|||
function WalletKey(cfg) { |
|||
if (!cfg) cfg = {}; |
|||
if (!cfg.network) throw new Error('network parameter is required'); |
|||
this.network = cfg.network; // required
|
|||
this.created = cfg.created; |
|||
this.privKey = cfg.privKey; |
|||
}; |
|||
|
|||
WalletKey.prototype.storeObj = function() { |
|||
var pubKey = this.privKey.public.toString('hex'); |
|||
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public); |
|||
var addr = new Address(this.network.addressPubkey, pubKeyHash); |
|||
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed); |
|||
var obj = { |
|||
created: this.created, |
|||
priv: priv.toString(), |
|||
pub: pubKey, |
|||
addr: addr.toString(), |
|||
}; |
|||
WalletKey.prototype.generate = function() { |
|||
this.privKey = KeyModule.Key.generateSync(); |
|||
this.created = timeUtil.curtime(); |
|||
}; |
|||
|
|||
return obj; |
|||
WalletKey.prototype.storeObj = function() { |
|||
var pubKey = this.privKey.public.toString('hex'); |
|||
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public); |
|||
var addr = new Address(this.network.addressPubkey, pubKeyHash); |
|||
var priv = new PrivateKey(this.network.keySecret, this.privKey.private, this.privKey.compressed); |
|||
var obj = { |
|||
created: this.created, |
|||
priv: priv.toString(), |
|||
pub: pubKey, |
|||
addr: addr.toString(), |
|||
}; |
|||
|
|||
WalletKey.prototype.fromObj = function(obj) { |
|||
this.created = obj.created; |
|||
this.privKey = new KeyModule.Key(); |
|||
if (obj.priv.length==64) { |
|||
this.privKey.private = new Buffer(obj.priv,'hex'); |
|||
this.privKey.compressed = true; |
|||
} |
|||
else { |
|||
var priv = new PrivateKey(obj.priv); |
|||
this.privKey.private = new Buffer(priv.payload()); |
|||
this.privKey.compressed = priv.compressed(); |
|||
} |
|||
this.privKey.regenerateSync(); |
|||
}; |
|||
return obj; |
|||
}; |
|||
|
|||
return WalletKey; |
|||
WalletKey.prototype.fromObj = function(obj) { |
|||
this.created = obj.created; |
|||
this.privKey = new KeyModule.Key(); |
|||
if (obj.priv.length==64) { |
|||
this.privKey.private = new Buffer(obj.priv,'hex'); |
|||
this.privKey.compressed = true; |
|||
} |
|||
else { |
|||
var priv = new PrivateKey(obj.priv); |
|||
this.privKey.private = new Buffer(priv.payload()); |
|||
this.privKey.compressed = priv.compressed(); |
|||
} |
|||
this.privKey.regenerateSync(); |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
module.exports = require('soop')(WalletKey); |
|||
|
@ -1,39 +1,37 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
var base58 = imports.base58 || require('base58-native').base58Check; |
|||
var superclass = imports.parent || require('./EncodedData'); |
|||
|
|||
function ClassSpec(b) { |
|||
var superclass = b.superclass || require('./EncodedData').class(); |
|||
|
|||
function VersionedData(version, payload) { |
|||
if(typeof version != 'number') { |
|||
VersionedData.super(this, arguments); |
|||
return; |
|||
}; |
|||
this.data = new Buffer(payload.length + 1); |
|||
this.__proto__ = this.encodings['binary']; |
|||
this.version(version); |
|||
this.payload(payload); |
|||
function VersionedData(version, payload) { |
|||
if(typeof version != 'number') { |
|||
VersionedData.super(this, arguments); |
|||
return; |
|||
}; |
|||
VersionedData.superclass = superclass; |
|||
superclass.applyEncodingsTo(VersionedData); |
|||
this.data = new Buffer(payload.length + 1); |
|||
this.__proto__ = this.encodings['binary']; |
|||
this.version(version); |
|||
this.payload(payload); |
|||
}; |
|||
|
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(0); |
|||
}; |
|||
VersionedData.parent = superclass || require('./Person'); |
|||
superclass.applyEncodingsTo(VersionedData); |
|||
|
|||
// 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);}); |
|||
return data; |
|||
} |
|||
return this.as('binary').slice(1); |
|||
}; |
|||
// 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);}); |
|||
return num; |
|||
} |
|||
return this.as('binary').readUInt8(0); |
|||
}; |
|||
|
|||
return VersionedData; |
|||
// 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);}); |
|||
return data; |
|||
} |
|||
return this.as('binary').slice(1); |
|||
}; |
|||
module.defineClass(ClassSpec); |
|||
|
|||
module.exports = require('soop')(VersionedData); |
|||
|
Loading…
Reference in new issue