Browse Source
Conflicts: Script.js ScriptInterpreter.js Transaction.js test/testdata.js ...conflicts resolved by taking Manuel's changes, and then manually including Matias's changes on those same files. The conflicts resulted from differences in indentation, which is because Matias' changes unindendented all the code that had been but is not now inside a function.patch-2
Ryan X. Charles
11 years ago
55 changed files with 4665 additions and 4592 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,214 @@ |
|||
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]; |
|||
|
|||
this.peers = []; |
|||
this.connections = []; |
|||
this.isConnected = false; |
|||
this.peerDiscovery = false; |
|||
var Connection = imports.Connection || |
|||
require('soop').load('Connection', {config: config, network: network}) || |
|||
require ('./Connection'); |
|||
|
|||
// Move these to the Node's settings object
|
|||
this.interval = 5000; |
|||
this.minConnections = 8; |
|||
this.minKnownPeers = 10; |
|||
}; |
|||
PeerManager.superclass = b.superclass || require('events').EventEmitter; |
|||
var Peer = imports.Peer || require('./Peer'); |
|||
|
|||
PeerManager.Connection = Connection; |
|||
GetAdjustedTime = imports.GetAdjustedTime || function () { |
|||
// TODO: Implement actual adjustment
|
|||
return Math.floor(new Date().getTime() / 1000); |
|||
}; |
|||
|
|||
PeerManager.prototype.start = function() { |
|||
this.active = true; |
|||
if(!this.timer) { |
|||
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
|||
} |
|||
}; |
|||
function PeerManager() { |
|||
this.active = false; |
|||
this.timer = 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(); |
|||
}; |
|||
}; |
|||
this.peers = []; |
|||
this.connections = []; |
|||
this.isConnected = false; |
|||
this.peerDiscovery = false; |
|||
|
|||
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.'; |
|||
} |
|||
}; |
|||
// Move these to the Node's settings object
|
|||
this.interval = 5000; |
|||
this.minConnections = 8; |
|||
this.minKnownPeers = 10; |
|||
}; |
|||
|
|||
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.parent = imports.parent || require('events').EventEmitter; |
|||
PeerManager.Connection = Connection; |
|||
|
|||
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.start = function() { |
|||
this.active = true; |
|||
if(!this.timer) { |
|||
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
|||
} |
|||
}; |
|||
|
|||
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,517 +1,512 @@ |
|||
require('classtool'); |
|||
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; |
|||
} |
|||
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); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
function spec(b) { |
|||
var config = b.config || require('./config'); |
|||
var log = b.log || require('./util/log'); |
|||
Script.prototype.isPushOnly = function() { |
|||
for (var i = 0; i < this.chunks.length; i++) |
|||
if (!Buffer.isBuffer(this.chunks[i])) |
|||
return false; |
|||
|
|||
var Opcode = b.Opcode || require('./Opcode').class(); |
|||
var buffertools = b.buffertools || require('buffertools'); |
|||
return true; |
|||
}; |
|||
|
|||
// Make opcodes available as pseudo-constants
|
|||
for (var i in Opcode.map) { |
|||
eval(i + " = " + Opcode.map[i] + ";"); |
|||
} |
|||
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); |
|||
}; |
|||
|
|||
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; |
|||
} else { |
|||
this.buffer = util.EMPTY_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.chunks.push(opcode); |
|||
} |
|||
} |
|||
}; |
|||
Script.prototype.isPubkey = function() { |
|||
return (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
this.chunks[1] == OP_CHECKSIG); |
|||
}; |
|||
|
|||
Script.prototype.isPushOnly = function() { |
|||
for (var i = 0; i < this.chunks.length; i++) |
|||
if (!Buffer.isBuffer(this.chunks[i])) |
|||
return false; |
|||
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.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++; |
|||
|
|||
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; |
|||
}; |
|||
|
|||
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.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.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++; |
|||
|
|||
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; |
|||
else |
|||
return false; |
|||
} |
|||
|
|||
Script.prototype.removePlaceHolders = function() { |
|||
var chunks = []; |
|||
for (var i in this.chunks) { |
|||
if (this.chunks.hasOwnProperty(i)) { |
|||
var chunk = this.chunks[i]; |
|||
if (chunk != 0) |
|||
chunks.push(chunk); |
|||
} |
|||
} |
|||
|
|||
Script.prototype.removePlaceHolders = function() { |
|||
var chunks = []; |
|||
for (var i in this.chunks) { |
|||
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; |
|||
} |
|||
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; |
|||
}; |
|||
|
|||
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; |
|||
// 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; |
|||
} |
|||
|
|||
// 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 = []; |
|||
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 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: |
|||
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: |
|||
log.debug("Encountered non-standard scriptPubKey"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
} |
|||
}; |
|||
// return first extracted data item from script
|
|||
Script.prototype.captureOne = function() { |
|||
var arr = this.capture(); |
|||
return arr[0]; |
|||
}; |
|||
|
|||
Script.prototype.getInType = function() { |
|||
if (this.chunks.length == 1) { |
|||
// Direct IP to IP transactions only have the public key in their scriptSig.
|
|||
Script.prototype.getOutType = function() { |
|||
var txType = this.classify(); |
|||
switch (txType) { |
|||
case TX_PUBKEY: |
|||
return 'Pubkey'; |
|||
} else if (this.chunks.length == 2 && |
|||
Buffer.isBuffer(this.chunks[0]) && |
|||
Buffer.isBuffer(this.chunks[1])) { |
|||
case TX_PUBKEYHASH: |
|||
return 'Address'; |
|||
} else { |
|||
default: |
|||
return 'Strange'; |
|||
} |
|||
}; |
|||
|
|||
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.getBuffer = function() { |
|||
return this.buffer; |
|||
}; |
|||
|
|||
Script.fromStringContent = function(s) { |
|||
var chunks = []; |
|||
var split = s.split(' '); |
|||
for (var i = 0; i < split.length; i++) { |
|||
var word = split[i]; |
|||
if (word.length > 2 && word.substring(0, 2) === '0x') { |
|||
chunks.push(new Buffer(word.substring(2, word.length), 'hex')); |
|||
} |
|||
}; |
|||
|
|||
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: |
|||
log.debug("Encountered non-standard scriptPubKey"); |
|||
log.debug("Strange script was: " + this.toString()); |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
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'; |
|||
} |
|||
}; |
|||
|
|||
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.getBuffer = function() { |
|||
return this.buffer; |
|||
}; |
|||
|
|||
Script.fromStringContent = function(s) { |
|||
var chunks = []; |
|||
var split = s.split(' '); |
|||
for (var i = 0; i < split.length; i++) { |
|||
var word = split[i]; |
|||
if (word.length > 2 && word.substring(0, 2) === '0x') { |
|||
chunks.push(new Buffer(word.substring(2, word.length), 'hex')); |
|||
} else { |
|||
var opcode = Opcode.map['OP_' + word]; |
|||
if (opcode) { |
|||
chunks.push(opcode); |
|||
} else { |
|||
var opcode = Opcode.map['OP_' + word]; |
|||
if (opcode) { |
|||
chunks.push(opcode); |
|||
} else { |
|||
var integer = parseInt(word); |
|||
if (!isNaN(integer)) { |
|||
//console.log(integer+' bits=\t'+integer.toString(2).replace('-','').length);
|
|||
var data = util.intToBuffer(integer); |
|||
chunks.push(data); |
|||
} |
|||
var integer = parseInt(word); |
|||
if (!isNaN(integer)) { |
|||
//console.log(integer+' bits=\t'+integer.toString(2).replace('-','').length);
|
|||
var data = util.intToBuffer(integer); |
|||
chunks.push(data); |
|||
} |
|||
} |
|||
} |
|||
return Script.fromChunks(chunks); |
|||
}; |
|||
} |
|||
return Script.fromChunks(chunks); |
|||
}; |
|||
|
|||
Script.prototype.getStringContent = function(truncate, maxEl) { |
|||
if (truncate === null) { |
|||
truncate = true; |
|||
} |
|||
|
|||
if ('undefined' === typeof maxEl) { |
|||
maxEl = 15; |
|||
} |
|||
|
|||
Script.prototype.getStringContent = function(truncate, maxEl) { |
|||
if (truncate === null) { |
|||
truncate = true; |
|||
var s = ''; |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
var chunk = this.chunks[i]; |
|||
|
|||
if (i > 0) { |
|||
s += ' '; |
|||
} |
|||
|
|||
if ('undefined' === typeof maxEl) { |
|||
maxEl = 15; |
|||
if (Buffer.isBuffer(chunk)) { |
|||
s += '0x' + util.formatBuffer(chunk, truncate ? null : 0); |
|||
} else { |
|||
s += Opcode.reverseMap[chunk]; |
|||
} |
|||
|
|||
var s = ''; |
|||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
|||
var chunk = this.chunks[i]; |
|||
if (maxEl && i > maxEl) { |
|||
s += ' ...'; |
|||
break; |
|||
} |
|||
} |
|||
return s; |
|||
}; |
|||
|
|||
if (i > 0) { |
|||
s += ' '; |
|||
} |
|||
Script.prototype.toString = function(truncate, maxEl) { |
|||
var script = "<Script "; |
|||
script += this.getStringContent(truncate, maxEl); |
|||
script += ">"; |
|||
return script; |
|||
}; |
|||
|
|||
if (Buffer.isBuffer(chunk)) { |
|||
s += '0x' + util.formatBuffer(chunk, truncate ? null : 0); |
|||
} else { |
|||
s += Opcode.reverseMap[chunk]; |
|||
} |
|||
|
|||
if (maxEl && i > maxEl) { |
|||
s += ' ...'; |
|||
break; |
|||
Script.prototype.writeOp = function(opcode) { |
|||
var buf = Buffer(this.buffer.length + 1); |
|||
this.buffer.copy(buf); |
|||
buf.writeUInt8(opcode, this.buffer.length); |
|||
|
|||
this.buffer = buf; |
|||
|
|||
this.chunks.push(opcode); |
|||
}; |
|||
|
|||
Script.prototype.writeN = function(n) { |
|||
if (n < 0 || n > 16) |
|||
throw new Error("writeN: out of range value " + n); |
|||
|
|||
if (n == 0) |
|||
this.writeOp(OP_0); |
|||
else |
|||
this.writeOp(OP_1 + n - 1); |
|||
}; |
|||
|
|||
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; |
|||
} |
|||
}; |
|||
|
|||
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); |
|||
} |
|||
|
|||
return buf; |
|||
}; |
|||
|
|||
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); |
|||
}; |
|||
|
|||
Script.prototype.updateBuffer = function() { |
|||
this.buffer = Script.chunksToBuffer(this.chunks); |
|||
}; |
|||
|
|||
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; |
|||
} |
|||
} |
|||
return s; |
|||
}; |
|||
|
|||
Script.prototype.toString = function(truncate, maxEl) { |
|||
var script = "<Script "; |
|||
script += this.getStringContent(truncate, maxEl); |
|||
script += ">"; |
|||
return script; |
|||
}; |
|||
|
|||
|
|||
Script.prototype.writeOp = function(opcode) { |
|||
var buf = Buffer(this.buffer.length + 1); |
|||
this.buffer.copy(buf); |
|||
buf.writeUInt8(opcode, this.buffer.length); |
|||
|
|||
this.buffer = buf; |
|||
|
|||
this.chunks.push(opcode); |
|||
}; |
|||
|
|||
Script.prototype.writeN = function(n) { |
|||
if (n < 0 || n > 16) |
|||
throw new Error("writeN: out of range value " + n); |
|||
|
|||
if (n == 0) |
|||
this.writeOp(OP_0); |
|||
else |
|||
this.writeOp(OP_1 + n - 1); |
|||
}; |
|||
|
|||
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; |
|||
} |
|||
}; |
|||
|
|||
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); |
|||
} 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."); |
|||
return chunk; |
|||
} |
|||
if (dirty) { |
|||
this.updateBuffer(); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 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); |
|||
|
@ -0,0 +1,6 @@ |
|||
require('bignum').config({ |
|||
EXPONENTIAL_AT: 9999999, |
|||
DECIMAL_PLACES: 0, |
|||
ROUNDING_MODE: 1, |
|||
}); |
|||
|
@ -0,0 +1,88 @@ |
|||
'use strict'; |
|||
|
|||
/* |
|||
* Example for usage of browserify with soop |
|||
* |
|||
* The key parameter 'pack' |
|||
* The supplied 'custom_prelude.js' file is needed for |
|||
* .load function of soop. |
|||
*/ |
|||
|
|||
var fs = require('fs'); |
|||
var browserify = require('browserify'); |
|||
var browserPack = require('browser-pack'); |
|||
var opts = {}; |
|||
|
|||
|
|||
var preludePath = 'node_modules/soop/example/custom_prelude.js'; |
|||
|
|||
var pack = function (params) { |
|||
params.raw = true; |
|||
params.sourceMapPrefix = '//#'; |
|||
params.prelude= fs.readFileSync(preludePath, 'utf8'); |
|||
params.preludePath= preludePath; |
|||
return browserPack(params); |
|||
}; |
|||
|
|||
opts.pack = pack; |
|||
opts.debug = true; |
|||
|
|||
var modules = [ |
|||
'Address', |
|||
'Block', |
|||
'Bloom', |
|||
'Buffers.monkey', |
|||
'Connection', |
|||
'Deserialize', |
|||
'Gruntfile', |
|||
'Number.monkey', |
|||
'Opcode', |
|||
'Peer', |
|||
'PeerManager', |
|||
'PrivateKey', |
|||
'RpcClient', |
|||
'SIN', |
|||
'SINKey', |
|||
'Script', |
|||
'ScriptInterpreter', |
|||
'Sign', |
|||
'Transaction', |
|||
'Wallet', |
|||
'WalletKey', |
|||
'config', |
|||
'const', |
|||
'networks', |
|||
'bitcore', |
|||
]; |
|||
|
|||
var b = browserify(opts); |
|||
b.require('browserify-bignum/bignumber.js', {expose: 'bignum'} ); |
|||
b.require('browserify-buffertools/buffertools.js', {expose:'buffertools'}); |
|||
b.require('buffer', {expose: 'buffer'}); |
|||
b.require('base58-native'); |
|||
b.require('./Key.js', {expose: 'KeyModule'}); |
|||
b.require('./util/log'); |
|||
b.require('./util/util'); |
|||
b.require('./util/EncodedData'); |
|||
b.require('./util/VersionedData'); |
|||
b.add('./browser/bignum_config.js'); |
|||
|
|||
modules.forEach(function(m) { |
|||
b.require('./' + m + '.js' ,{expose:m} ); |
|||
}); |
|||
|
|||
var bopts = { |
|||
// detectGlobals: true,
|
|||
// insertGlobals: 'Buffer',
|
|||
// insertGlobalVars: {
|
|||
// Buffer: function () {
|
|||
// return 'require("buffer").Buffer';
|
|||
// },
|
|||
// },
|
|||
}; |
|||
|
|||
b.bundle(bopts).pipe(process.stdout); |
|||
|
|||
|
|||
|
|||
|
@ -1,39 +1,38 @@ |
|||
require('classtool'); |
|||
var imports = require('soop').imports(); |
|||
var base58 = imports.base58 || require('base58-native').base58Check; |
|||
var parent = 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 = parent; |
|||
parent.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