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) { |
function Address() { |
||||
var superclass = b.superclass || require('./util/VersionedData').class(); |
Address.super(this, arguments); |
||||
|
} |
||||
function Address() { |
|
||||
Address.super(this, arguments); |
|
||||
} |
|
||||
|
|
||||
Address.superclass = superclass; |
Address.parent = parent; |
||||
superclass.applyEncodingsTo(Address); |
parent.applyEncodingsTo(Address); |
||||
|
|
||||
Address.prototype.validate = function() { |
Address.prototype.validate = function() { |
||||
this.doAsBinary(function() { |
this.doAsBinary(function() { |
||||
Address.super(this, 'validate', arguments); |
Address.super(this, 'validate', arguments); |
||||
if(this.data.length !== 21) throw new Error('invalid data length'); |
if(this.data.length !== 21) throw new Error('invalid data length'); |
||||
}); |
}); |
||||
}; |
}; |
||||
|
|
||||
return Address; |
module.exports = require('soop')(Address); |
||||
} |
|
||||
module.defineClass(ClassSpec); |
|
||||
|
File diff suppressed because it is too large
@ -1,116 +1,111 @@ |
|||||
require('classtool'); |
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
||||
|
var MAX_HASH_FUNCS = 50; |
||||
function ClassSpec(b) { |
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; |
||||
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
|
var LN2 = 0.6931471805599453094172321214581765680755001343602552; |
||||
var MAX_HASH_FUNCS = 50; |
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; |
||||
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; |
|
||||
var LN2 = 0.6931471805599453094172321214581765680755001343602552; |
function Bloom() { |
||||
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; |
this.data = ''; |
||||
|
this.hashFuncs = 0; |
||||
function Bloom() { |
}; |
||||
this.data = ''; |
|
||||
this.hashFuncs = 0; |
function ROTL32(x, r) { |
||||
}; |
return (x << r) | (x >> (32 - r)); |
||||
|
}; |
||||
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)) | |
||||
function getBlockU32(blockIdx, data) { |
(data[idx + 1] << (1 * 8)) | |
||||
var idx = blockIdx * 4; |
(data[idx + 2] << (2 * 8)) | |
||||
var v = (data[idx + 0] << (0 * 8)) | |
(data[idx + 3] << (3 * 8)); |
||||
(data[idx + 1] << (1 * 8)) | |
return v; |
||||
(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; |
||||
Bloom.prototype.hash = function(hashNum, data) { |
var c2 = 0x1b873593; |
||||
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); |
var nBlocks = data.length / 4; |
||||
var c1 = 0xcc9e2d51; |
|
||||
var c2 = 0x1b873593; |
// data body
|
||||
var nBlocks = data.length / 4; |
for (var i = -nBlocks; i; i++) { |
||||
|
var k1 = getBlockU32(i); |
||||
// data body
|
|
||||
for (var i = -nBlocks; i; i++) { |
k1 *= c1; |
||||
var k1 = getBlockU32(i); |
k1 = ROTLF32(k1, 15); |
||||
|
k1 *= c2; |
||||
k1 *= c1; |
|
||||
k1 = ROTLF32(k1, 15); |
h1 ^= k1; |
||||
k1 *= c2; |
h1 = ROTFL(h1, 13); |
||||
|
h1 = h1 * 5 + 0xe6546b64; |
||||
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; |
|
||||
} |
} |
||||
|
|
||||
function min(a, b) { |
// tail (trailing 1-3 bytes)
|
||||
if (a < b) |
var tail = data.slice(nBlocks * 4); |
||||
return a; |
|
||||
return b; |
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) { |
// finalize
|
||||
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), |
h1 ^= data.length; |
||||
MAX_BLOOM_FILTER_SIZE * 8) / 8; |
h1 ^= h1 >> 16; |
||||
this.data[filterSize] = 0; |
h1 *= 0x85ebca6b; |
||||
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), |
h1 ^= h1 >> 13; |
||||
MAX_HASH_FUNCS); |
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'); |
var imports = require('soop').imports(); |
||||
|
|
||||
function spec(b) { |
function Opcode(num) { |
||||
function Opcode(num) { |
this.code = num; |
||||
this.code = num; |
}; |
||||
}; |
|
||||
|
Opcode.prototype.toString = function () { |
||||
Opcode.prototype.toString = function () { |
return Opcode.reverseMap[this.code]; |
||||
return Opcode.reverseMap[this.code]; |
}; |
||||
}; |
|
||||
|
|
||||
Opcode.map = { |
|
||||
// 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); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
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'); |
var imports = require('soop').imports(); |
||||
|
|
||||
function spec(b) { |
var Net = imports.Net || require('net'); |
||||
var Net = b.Net || require('net'); |
var Binary = imports.Binary || require('binary'); |
||||
var Binary = b.Binary || require('binary'); |
var buffertools = imports.buffertools || require('buffertools'); |
||||
var buffertools = b.buffertools || require('buffertools'); |
|
||||
|
function Peer(host, port, services) { |
||||
function Peer(host, port, services) { |
if ("string" === typeof host) { |
||||
if ("string" === typeof host) { |
if (host.indexOf(':') && !port) { |
||||
if (host.indexOf(':') && !port) { |
var parts = host.split(':'); |
||||
var parts = host.split(':'); |
host = parts[0]; |
||||
host = parts[0]; |
port = parts[1]; |
||||
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.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; |
Peer.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]); |
||||
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.prototype.getHostAsBuffer = function () { |
Peer.prototype.createConnection = function () { |
||||
return new Buffer(this.host.split('.')); |
var c = Net.createConnection(this.port, this.host); |
||||
}; |
return c; |
||||
|
}; |
||||
|
|
||||
Peer.prototype.toString = function () { |
Peer.prototype.getHostAsBuffer = function () { |
||||
return this.host + ":" + this.port; |
return new Buffer(this.host.split('.')); |
||||
}; |
}; |
||||
|
|
||||
Peer.prototype.toBuffer = function () { |
Peer.prototype.toString = function () { |
||||
var put = Binary.put(); |
return this.host + ":" + this.port; |
||||
put.word32le(this.lastSeen); |
}; |
||||
put.word64le(this.services); |
|
||||
put.put(this.getHostAsBuffer()); |
|
||||
put.word16be(this.port); |
|
||||
return put.buffer(); |
|
||||
}; |
|
||||
|
|
||||
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() { |
var imports = require('soop').imports(); |
||||
this.active = false; |
var config = imports.config || require('./config'); |
||||
this.timer = null; |
var log = imports.log || require('./util/log'); |
||||
|
var network = imports.network || require('./networks')[config.network]; |
||||
|
|
||||
this.peers = []; |
var Connection = imports.Connection || |
||||
this.connections = []; |
require('soop').load('Connection', {config: config, network: network}) || |
||||
this.isConnected = false; |
require ('./Connection'); |
||||
this.peerDiscovery = false; |
|
||||
|
|
||||
// Move these to the Node's settings object
|
var Peer = imports.Peer || require('./Peer'); |
||||
this.interval = 5000; |
|
||||
this.minConnections = 8; |
|
||||
this.minKnownPeers = 10; |
|
||||
}; |
|
||||
PeerManager.superclass = b.superclass || require('events').EventEmitter; |
|
||||
|
|
||||
PeerManager.Connection = Connection; |
GetAdjustedTime = imports.GetAdjustedTime || function () { |
||||
|
// TODO: Implement actual adjustment
|
||||
|
return Math.floor(new Date().getTime() / 1000); |
||||
|
}; |
||||
|
|
||||
PeerManager.prototype.start = function() { |
function PeerManager() { |
||||
this.active = true; |
this.active = false; |
||||
if(!this.timer) { |
this.timer = null; |
||||
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
PeerManager.prototype.stop = function() { |
this.peers = []; |
||||
this.active = false; |
this.connections = []; |
||||
if(this.timer) { |
this.isConnected = false; |
||||
clearInterval(this.timer); |
this.peerDiscovery = false; |
||||
this.timer = null; |
|
||||
} |
|
||||
for(var i=0; i<this.connections.length; i++) { |
|
||||
this.connections[i].socket.end(); |
|
||||
}; |
|
||||
}; |
|
||||
|
|
||||
PeerManager.prototype.addPeer = function(peer, port) { |
// Move these to the Node's settings object
|
||||
if(peer instanceof Peer) { |
this.interval = 5000; |
||||
this.peers.push(peer); |
this.minConnections = 8; |
||||
} else if ("string" == typeof peer) { |
this.minKnownPeers = 10; |
||||
this.addPeer(new Peer(peer, port)); |
}; |
||||
} else { |
|
||||
log.err('Node.addPeer(): Invalid value provided for peer', |
|
||||
{val: peer}); |
|
||||
throw 'Node.addPeer(): Invalid value provided for peer.'; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
PeerManager.prototype.checkStatus = function checkStatus() { |
PeerManager.parent = imports.parent || require('events').EventEmitter; |
||||
// Make sure we are connected to all forcePeers
|
PeerManager.Connection = Connection; |
||||
if(this.peers.length) { |
|
||||
var peerIndex = {}; |
|
||||
this.peers.forEach(function(peer) { |
|
||||
peerIndex[peer.toString()] = peer; |
|
||||
}); |
|
||||
|
|
||||
// Ignore the ones we're already connected to
|
|
||||
this.connections.forEach(function(conn) { |
|
||||
var peerName = conn.peer.toString(); |
|
||||
if("undefined" !== peerIndex[peerName]) { |
|
||||
delete peerIndex[peerName]; |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
Object.keys(peerIndex).forEach(function(i) { |
|
||||
this.connectTo(peerIndex[i]); |
|
||||
}.bind(this)); |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
PeerManager.prototype.connectTo = function(peer) { |
PeerManager.prototype.start = function() { |
||||
log.info('connecting to '+peer); |
this.active = true; |
||||
try { |
if(!this.timer) { |
||||
return this.addConnection(peer.createConnection(), peer); |
this.timer = setInterval(this.checkStatus.bind(this), this.interval); |
||||
} catch (e) { |
} |
||||
log.err('creating connection',e); |
}; |
||||
return null; |
|
||||
} |
PeerManager.prototype.stop = function() { |
||||
|
this.active = false; |
||||
|
if(this.timer) { |
||||
|
clearInterval(this.timer); |
||||
|
this.timer = null; |
||||
|
} |
||||
|
for(var i=0; i<this.connections.length; i++) { |
||||
|
this.connections[i].socket.end(); |
||||
}; |
}; |
||||
|
}; |
||||
|
|
||||
PeerManager.prototype.addConnection = function(socketConn, peer) { |
PeerManager.prototype.addPeer = function(peer, port) { |
||||
var conn = new Connection(socketConn, peer); |
if(peer instanceof Peer) { |
||||
this.connections.push(conn); |
this.peers.push(peer); |
||||
this.emit('connection', conn); |
} 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)); |
PeerManager.prototype.checkStatus = function checkStatus() { |
||||
conn.addListener('verack', this.handleReady.bind(this)); |
// Make sure we are connected to all forcePeers
|
||||
conn.addListener('addr', this.handleAddr.bind(this)); |
if(this.peers.length) { |
||||
conn.addListener('getaddr', this.handleGetAddr.bind(this)); |
var peerIndex = {}; |
||||
conn.addListener('error', this.handleError.bind(this)); |
this.peers.forEach(function(peer) { |
||||
conn.addListener('disconnect', this.handleDisconnect.bind(this)); |
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) { |
Object.keys(peerIndex).forEach(function(i) { |
||||
if (!e.conn.inbound) { |
this.connectTo(peerIndex[i]); |
||||
// TODO: Advertise our address (if listening)
|
}.bind(this)); |
||||
} |
} |
||||
// 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) { |
PeerManager.prototype.connectTo = function(peer) { |
||||
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port); |
log.info('connecting to '+peer); |
||||
this.emit('connect', { |
try { |
||||
pm: this, |
return this.addConnection(peer.createConnection(), peer); |
||||
conn: e.conn, |
} catch (e) { |
||||
socket: e.socket, |
log.err('creating connection',e); |
||||
peer: e.peer |
return null; |
||||
}); |
} |
||||
|
}; |
||||
|
|
||||
if(this.isConnected == false) { |
PeerManager.prototype.addConnection = function(socketConn, peer) { |
||||
this.emit('netConnected'); |
var conn = new Connection(socketConn, peer); |
||||
this.isConnected = true; |
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) { |
PeerManager.prototype.handleAddr = function (e) { |
||||
if(!this.peerDiscovery) return; |
if(!this.peerDiscovery) return; |
||||
|
|
||||
var now = GetAdjustedTime(); |
var now = GetAdjustedTime(); |
||||
e.message.addrs.forEach(function (addr) { |
e.message.addrs.forEach(function (addr) { |
||||
try { |
try { |
||||
// In case of an invalid time, assume "5 days ago"
|
// In case of an invalid time, assume "5 days ago"
|
||||
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) { |
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) { |
||||
addr.time = now - 5 * 24 * 60 * 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); |
|
||||
} |
} |
||||
}.bind(this)); |
var peer = new Peer(addr.ip, addr.port, addr.services); |
||||
if (e.message.addrs.length < 1000 ) { |
peer.lastSeen = addr.time; |
||||
e.conn.getaddr = false; |
|
||||
|
// 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) { |
PeerManager.prototype.handleGetAddr = function(e) { |
||||
// TODO: Reply with addr message.
|
// TODO: Reply with addr message.
|
||||
}; |
}; |
||||
|
|
||||
PeerManager.prototype.handleError = function(e) { |
PeerManager.prototype.handleError = function(e) { |
||||
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err); |
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err); |
||||
this.handleDisconnect.apply(this, [].slice.call(arguments)); |
this.handleDisconnect.apply(this, [].slice.call(arguments)); |
||||
}; |
}; |
||||
|
|
||||
PeerManager.prototype.handleDisconnect = function(e) { |
PeerManager.prototype.handleDisconnect = function(e) { |
||||
log.info('disconnected from peer '+e.peer); |
log.info('disconnected from peer '+e.peer); |
||||
var i = this.connections.indexOf(e.conn); |
var i = this.connections.indexOf(e.conn); |
||||
if(i != -1) this.connections.splice(i, 1); |
if(i != -1) this.connections.splice(i, 1); |
||||
|
|
||||
if(!this.connections.length) { |
if(!this.connections.length) { |
||||
this.emit('netDisconnected'); |
this.emit('netDisconnected'); |
||||
this.isConnected = false; |
this.isConnected = false; |
||||
} |
} |
||||
}; |
}; |
||||
|
|
||||
PeerManager.prototype.getActiveConnection = function () { |
PeerManager.prototype.getActiveConnection = function () { |
||||
var activeConnections = this.connections.filter(function (conn) { |
var activeConnections = this.connections.filter(function (conn) { |
||||
return conn.active; |
return conn.active; |
||||
}); |
}); |
||||
|
|
||||
if (activeConnections.length) { |
if (activeConnections.length) { |
||||
var randomIndex = Math.floor(Math.random()*activeConnections.length); |
var randomIndex = Math.floor(Math.random()*activeConnections.length); |
||||
var candidate = activeConnections[randomIndex]; |
var candidate = activeConnections[randomIndex]; |
||||
if (candidate.socket.writable) { |
if (candidate.socket.writable) { |
||||
return candidate; |
return candidate; |
||||
} 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(); |
|
||||
} |
|
||||
} else { |
} else { |
||||
return null; |
// Socket is not writable, remove it from active connections
|
||||
} |
activeConnections.splice(randomIndex, 1); |
||||
}; |
|
||||
|
|
||||
PeerManager.prototype.getActiveConnections = function () { |
// Then try again
|
||||
return this.connections.slice(0); |
// 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 parent = imports.parent || require('./util/VersionedData'); |
||||
var superclass = b.superclass || require('./util/VersionedData').class(); |
|
||||
|
|
||||
//compressed is true if public key is compressed; false otherwise
|
//compressed is true if public key is compressed; false otherwise
|
||||
function PrivateKey(version, buf, compressed) { |
function PrivateKey(version, buf, compressed) { |
||||
PrivateKey.super(this, arguments); |
PrivateKey.super(this, arguments); |
||||
if (compressed !== undefined) |
if (compressed !== undefined) |
||||
this.compressed(compressed); |
this.compressed(compressed); |
||||
}; |
}; |
||||
|
|
||||
PrivateKey.superclass = superclass; |
PrivateKey.parent = parent; |
||||
superclass.applyEncodingsTo(PrivateKey); |
parent.applyEncodingsTo(PrivateKey); |
||||
|
|
||||
PrivateKey.prototype.validate = function() { |
PrivateKey.prototype.validate = function() { |
||||
this.doAsBinary(function() { |
this.doAsBinary(function() { |
||||
PrivateKey.super(this, 'validate', arguments); |
PrivateKey.super(this, 'validate', arguments); |
||||
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1) |
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1) |
||||
throw new Error('invalid data length'); |
throw new Error('invalid data length'); |
||||
}); |
}); |
||||
}; |
}; |
||||
|
|
||||
// get or set the payload data (as a Buffer object)
|
// get or set the payload data (as a Buffer object)
|
||||
// overloaded from VersionedData
|
// overloaded from VersionedData
|
||||
PrivateKey.prototype.payload = function(data) { |
PrivateKey.prototype.payload = function(data) { |
||||
if(data) { |
if(data) { |
||||
this.doAsBinary(function() {data.copy(this.data,1);}); |
this.doAsBinary(function() {data.copy(this.data,1);}); |
||||
return data; |
return data; |
||||
} |
} |
||||
var buf=this.as('binary'); |
var buf=this.as('binary'); |
||||
if (buf.length==1+32+1) |
if (buf.length==1+32+1) |
||||
return buf.slice(1,1+32); |
return buf.slice(1,1+32); |
||||
else if (buf.length==1+32) |
else if (buf.length==1+32) |
||||
return buf.slice(1); |
return buf.slice(1); |
||||
}; |
}; |
||||
|
|
||||
// get or set whether the corresponding public key is compressed
|
// get or set whether the corresponding public key is compressed
|
||||
PrivateKey.prototype.compressed = function(compressed) { |
PrivateKey.prototype.compressed = function(compressed) { |
||||
if (compressed !== undefined) { |
if (compressed !== undefined) { |
||||
this.doAsBinary(function(){ |
this.doAsBinary(function(){ |
||||
var len=1+32+1; |
|
||||
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 len=1+32+1; |
||||
var data=this.as('binary'); |
if (compressed) { |
||||
if (data.length==len && data[len-1]==1) |
var data=new Buffer(len); |
||||
return true; |
this.data.copy(data); |
||||
else if (data.length==len-1) |
this.data=data; |
||||
return false; |
this.data[len-1]=1; |
||||
else |
} else { |
||||
throw new Error('invalid private key'); |
this.data=this.data.slice(0,len-1); |
||||
} |
} |
||||
}; |
}); |
||||
|
} |
||||
return PrivateKey; |
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
|
// RpcClient.js
|
||||
// MIT/X11-like license. See LICENSE.txt.
|
// MIT/X11-like license. See LICENSE.txt.
|
||||
// Copyright 2013 BitPay, Inc.
|
// 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) { |
function RpcClient(opts) { |
||||
var http = b.http || require('http'); |
opts = opts || {}; |
||||
var https = b.https || require('https'); |
this.host = opts.host || '127.0.0.1'; |
||||
var log = b.log || require('./util/log'); |
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) { |
var callspec = { |
||||
opts = opts || {}; |
addMultiSigAddress: '', |
||||
this.host = opts.host || '127.0.0.1'; |
addNode: '', |
||||
this.port = opts.port || 8332; |
backupWallet: '', |
||||
this.user = opts.user || 'user'; |
createMultiSig: '', |
||||
this.pass = opts.pass || 'pass'; |
createRawTransaction: '', |
||||
this.protocol = (opts.protocol == 'http') ? http : https; |
decodeRawTransaction: '', |
||||
this.batchedCalls = null; |
dumpPrivKey: '', |
||||
this.disableAgent = opts.disableAgent || false; |
encryptWallet: '', |
||||
} |
getAccount: '', |
||||
|
getAccountAddress: 'str', |
||||
RpcClient.prototype.batch = function(batchCallback, resultCallback) { |
getAddedNodeInfo: '', |
||||
this.batchedCalls = []; |
getAddressesByAccount: '', |
||||
batchCallback(); |
getBalance: 'str int', |
||||
rpc.call(this, this.batchedCalls, resultCallback); |
getBestBlockHash: '', |
||||
this.batchedCalls = null; |
getBlock: '', |
||||
} |
getBlockCount: '', |
||||
|
getBlockHash: 'int', |
||||
var callspec = { |
getBlockNumber: '', |
||||
addMultiSigAddress: '', |
getBlockTemplate: '', |
||||
addNode: '', |
getConnectionCount: '', |
||||
backupWallet: '', |
getDifficulty: '', |
||||
createMultiSig: '', |
getGenerate: '', |
||||
createRawTransaction: '', |
getHashesPerSec: '', |
||||
decodeRawTransaction: '', |
getInfo: '', |
||||
dumpPrivKey: '', |
getMemoryPool: '', |
||||
encryptWallet: '', |
getMiningInfo: '', |
||||
getAccount: '', |
getNewAddress: '', |
||||
getAccountAddress: 'str', |
getPeerInfo: '', |
||||
getAddedNodeInfo: '', |
getRawMemPool: '', |
||||
getAddressesByAccount: '', |
getRawTransaction: 'str int', |
||||
getBalance: 'str int', |
getReceivedByAccount: 'str int', |
||||
getBestBlockHash: '', |
getReceivedByAddress: 'str int', |
||||
getBlock: '', |
getTransaction: '', |
||||
getBlockCount: '', |
getTxOut: 'str int bool', |
||||
getBlockHash: 'int', |
getTxOutSetInfo: '', |
||||
getBlockNumber: '', |
getWork: '', |
||||
getBlockTemplate: '', |
help: '', |
||||
getConnectionCount: '', |
importAddress: 'str str bool', |
||||
getDifficulty: '', |
importPrivKey: 'str str bool', |
||||
getGenerate: '', |
keyPoolRefill: '', |
||||
getHashesPerSec: '', |
listAccounts: 'int', |
||||
getInfo: '', |
listAddressGroupings: '', |
||||
getMemoryPool: '', |
listReceivedByAccount: 'int bool', |
||||
getMiningInfo: '', |
listReceivedByAddress: 'int bool', |
||||
getNewAddress: '', |
listSinceBlock: 'str int', |
||||
getPeerInfo: '', |
listTransactions: 'str int int', |
||||
getRawMemPool: '', |
listUnspent: 'int int', |
||||
getRawTransaction: 'str int', |
listLockUnspent: 'bool', |
||||
getReceivedByAccount: 'str int', |
lockUnspent: '', |
||||
getReceivedByAddress: 'str int', |
move: 'str str float int str', |
||||
getTransaction: '', |
sendFrom: 'str str float int str str', |
||||
getTxOut: 'str int bool', |
sendMany: 'str str int str', //not sure this is will work
|
||||
getTxOutSetInfo: '', |
sendRawTransaction: '', |
||||
getWork: '', |
sendToAddress: 'str float str str', |
||||
help: '', |
setAccount: '', |
||||
importAddress: 'str str bool', |
setGenerate: 'bool int', |
||||
importPrivKey: 'str str bool', |
setTxFee: 'float', |
||||
keyPoolRefill: '', |
signMessage: '', |
||||
listAccounts: 'int', |
signRawTransaction: '', |
||||
listAddressGroupings: '', |
stop: '', |
||||
listReceivedByAccount: 'int bool', |
submitBlock: '', |
||||
listReceivedByAddress: 'int bool', |
validateAddress: '', |
||||
listSinceBlock: 'str int', |
verifyMessage: '', |
||||
listTransactions: 'str int int', |
walletLock: '', |
||||
listUnspent: 'int int', |
walletPassPhrase: 'string int', |
||||
listLockUnspent: 'bool', |
walletPassphraseChange: '', |
||||
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) { |
var slice = function(arr, start, end) { |
||||
return Array.prototype.slice.call(arr, start, end); |
return Array.prototype.slice.call(arr, start, end); |
||||
}; |
}; |
||||
|
|
||||
function generateRPCMethods(constructor, apiCalls, rpc) { |
function generateRPCMethods(constructor, apiCalls, rpc) { |
||||
function createRPCMethod(methodName, argMap) { |
function createRPCMethod(methodName, argMap) { |
||||
return function() { |
return function() { |
||||
var limit = arguments.length - 1; |
var limit = arguments.length - 1; |
||||
if(this.batchedCalls) var limit = arguments.length; |
if(this.batchedCalls) var limit = arguments.length; |
||||
for (var i=0; i<limit; i++) { |
for (var i=0; i<limit; i++) { |
||||
if(argMap[i]) arguments[i] = argMap[i](arguments[i]); |
if(argMap[i]) arguments[i] = argMap[i](arguments[i]); |
||||
}; |
|
||||
if(this.batchedCalls) { |
|
||||
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]); |
|
||||
} |
|
||||
}; |
}; |
||||
|
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 = { |
var types = { |
||||
str: function(arg) {return arg.toString();}, |
str: function(arg) {return arg.toString();}, |
||||
int: function(arg) {return parseFloat(arg);}, |
int: function(arg) {return parseFloat(arg);}, |
||||
float: 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');}, |
bool: function(arg) {return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');}, |
||||
}; |
}; |
||||
|
|
||||
for(var k in apiCalls) { |
for(var k in apiCalls) { |
||||
if (apiCalls.hasOwnProperty(k)) { |
if (apiCalls.hasOwnProperty(k)) { |
||||
var spec = apiCalls[k].split(' '); |
var spec = apiCalls[k].split(' '); |
||||
for (var i = 0; i < spec.length; i++) { |
for (var i = 0; i < spec.length; i++) { |
||||
if(types[spec[i]]) { |
if(types[spec[i]]) { |
||||
spec[i] = types[spec[i]]; |
spec[i] = types[spec[i]]; |
||||
} else { |
} else { |
||||
spec[i] = types.string; |
spec[i] = types.string; |
||||
} |
|
||||
} |
} |
||||
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) { |
function rpc(request, callback) { |
||||
var self = this; |
var self = this; |
||||
var request; |
var request; |
||||
request = JSON.stringify(request); |
request = JSON.stringify(request); |
||||
var auth = Buffer(self.user + ':' + self.pass).toString('base64'); |
var auth = Buffer(self.user + ':' + self.pass).toString('base64'); |
||||
|
|
||||
var options = { |
var options = { |
||||
host: self.host, |
host: self.host, |
||||
path: '/', |
path: '/', |
||||
method: 'POST', |
method: 'POST', |
||||
port: self.port, |
port: self.port, |
||||
agent: self.disableAgent ? false : undefined, |
agent: self.disableAgent ? false : undefined, |
||||
}; |
}; |
||||
if(self.httpOptions) { |
if(self.httpOptions) { |
||||
for(var k in self.httpOptions) { |
for(var k in self.httpOptions) { |
||||
options[k] = self.httpOptions[k]; |
options[k] = self.httpOptions[k]; |
||||
} |
|
||||
} |
} |
||||
var err = null; |
} |
||||
var req = this.protocol.request(options, function(res) { |
var err = null; |
||||
|
var req = this.protocol.request(options, function(res) { |
||||
|
|
||||
var buf = ''; |
var buf = ''; |
||||
res.on('data', function(data) { |
res.on('data', function(data) { |
||||
buf += 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); |
|
||||
}); |
|
||||
}); |
}); |
||||
req.on('error', function(e) { |
res.on('end', function() { |
||||
var err = new Error('Could not connect to bitcoin via RPC: '+e.message); |
if(res.statusCode == 401) { |
||||
log.err(err); |
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized')); |
||||
callback(err); |
return; |
||||
}); |
} |
||||
|
if(res.statusCode == 403) { |
||||
req.setHeader('Content-Length', request.length); |
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden')); |
||||
req.setHeader('Content-Type', 'application/json'); |
return; |
||||
req.setHeader('Authorization', 'Basic ' + auth); |
} |
||||
req.write(request); |
|
||||
req.end(); |
|
||||
}; |
|
||||
|
|
||||
generateRPCMethods(RpcClient, callspec, rpc); |
if(err) { |
||||
return RpcClient; |
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) { |
function SIN(type, payload) { |
||||
var superclass = b.superclass || require('./util/VersionedData').class(); |
if (typeof type != 'number') { |
||||
|
SIN.super(this, arguments); |
||||
|
return; |
||||
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); |
|
||||
}; |
}; |
||||
|
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)
|
// get or set the SIN-type data (the second byte of the address)
|
||||
SIN.prototype.type = function(num) { |
SIN.prototype.type = function(num) { |
||||
if(num || (num === 0)) { |
if(num || (num === 0)) { |
||||
this.doAsBinary(function() {this.data.writeUInt8(num, 1);}); |
this.doAsBinary(function() {this.data.writeUInt8(num, 1);}); |
||||
return num; |
return num; |
||||
} |
} |
||||
return this.as('binary').readUInt8(1); |
return this.as('binary').readUInt8(1); |
||||
}; |
}; |
||||
|
|
||||
// get or set the payload data (as a Buffer object)
|
// get or set the payload data (as a Buffer object)
|
||||
SIN.prototype.payload = function(data) { |
SIN.prototype.payload = function(data) { |
||||
if(data) { |
if(data) { |
||||
this.doAsBinary(function() {data.copy(this.data, 2);}); |
this.doAsBinary(function() {data.copy(this.data, 2);}); |
||||
return data; |
return data; |
||||
} |
} |
||||
return this.as('binary').slice(1); |
return this.as('binary').slice(1); |
||||
}; |
}; |
||||
|
|
||||
SIN.prototype.validate = function() { |
SIN.prototype.validate = function() { |
||||
this.doAsBinary(function() { |
this.doAsBinary(function() { |
||||
SIN.super(this, 'validate', arguments); |
SIN.super(this, 'validate', arguments); |
||||
if (this.data.length != 22) throw new Error('invalid data length'); |
if (this.data.length != 22) throw new Error('invalid data length'); |
||||
}); |
}); |
||||
}; |
|
||||
return SIN; |
|
||||
}; |
}; |
||||
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) { |
function SINKey(cfg) { |
||||
var coinUtil = require('./util/util'); |
if (typeof cfg != 'object') |
||||
var timeUtil = require('./util/time'); |
cfg = {}; |
||||
var KeyModule = require('./Key'); |
|
||||
var SIN = require('./SIN').class(); |
|
||||
|
|
||||
function SINKey(cfg) { |
this.created = cfg.created; |
||||
if (typeof cfg != 'object') |
this.privKey = cfg.privKey; |
||||
cfg = {}; |
}; |
||||
|
|
||||
this.created = cfg.created; |
|
||||
this.privKey = cfg.privKey; |
|
||||
}; |
|
||||
|
|
||||
SINKey.prototype.generate = function() { |
|
||||
this.privKey = KeyModule.Key.generateSync(); |
|
||||
this.created = timeUtil.curtime(); |
|
||||
}; |
|
||||
|
|
||||
SINKey.prototype.pubkeyHash = function() { |
SINKey.prototype.generate = function() { |
||||
return coinUtil.sha256ripe160(this.privKey.public); |
this.privKey = KeyModule.Key.generateSync(); |
||||
}; |
this.created = timeUtil.curtime(); |
||||
|
}; |
||||
|
|
||||
SINKey.prototype.storeObj = function() { |
SINKey.prototype.pubkeyHash = function() { |
||||
var pubKey = this.privKey.public.toString('hex'); |
return coinUtil.sha256ripe160(this.privKey.public); |
||||
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 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) { |
Script.prototype.isPushOnly = function() { |
||||
var config = b.config || require('./config'); |
for (var i = 0; i < this.chunks.length; i++) |
||||
var log = b.log || require('./util/log'); |
if (!Buffer.isBuffer(this.chunks[i])) |
||||
|
return false; |
||||
|
|
||||
var Opcode = b.Opcode || require('./Opcode').class(); |
return true; |
||||
var buffertools = b.buffertools || require('buffertools'); |
}; |
||||
|
|
||||
// Make opcodes available as pseudo-constants
|
Script.prototype.isP2SH = function() { |
||||
for (var i in Opcode.map) { |
return (this.chunks.length == 3 && |
||||
eval(i + " = " + Opcode.map[i] + ";"); |
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'); |
Script.prototype.isPubkey = function() { |
||||
var Parser = b.Parser || require('./util/BinaryParser').class(); |
return (this.chunks.length == 2 && |
||||
var Put = b.Put || require('bufferput'); |
Buffer.isBuffer(this.chunks[0]) && |
||||
|
this.chunks[1] == OP_CHECKSIG); |
||||
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.isPushOnly = function() { |
Script.prototype.isPubkeyHash = function() { |
||||
for (var i = 0; i < this.chunks.length; i++) |
return (this.chunks.length == 5 && |
||||
if (!Buffer.isBuffer(this.chunks[i])) |
this.chunks[0] == OP_DUP && |
||||
return false; |
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; |
return true; |
||||
}; |
else |
||||
|
return false; |
||||
Script.prototype.isP2SH = function() { |
} |
||||
return (this.chunks.length == 3 && |
|
||||
this.chunks[0] == OP_HASH160 && |
Script.prototype.removePlaceHolders = function() { |
||||
Buffer.isBuffer(this.chunks[1]) && |
var chunks = []; |
||||
this.chunks[1].length == 20 && |
for (var i in this.chunks) { |
||||
this.chunks[2] == OP_EQUAL); |
if (this.chunks.hasOwnProperty(i)) { |
||||
}; |
var chunk = this.chunks[i]; |
||||
|
if (chunk != 0) |
||||
Script.prototype.isPubkey = function() { |
chunks.push(chunk); |
||||
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; |
|
||||
} |
} |
||||
|
this.chunks = chunks; |
||||
Script.prototype.removePlaceHolders = function() { |
this.updateBuffer(); |
||||
var chunks = []; |
return this; |
||||
for (var i in this.chunks) { |
} |
||||
if (this.chunks.hasOwnProperty(i)) { |
|
||||
var chunk = this.chunks[i]; |
Script.prototype.prependOp0 = function() { |
||||
if (chunk != 0) |
var chunks = [0]; |
||||
chunks.push(chunk); |
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() { |
// extract useful data items from known scripts
|
||||
var chunks = [0]; |
Script.prototype.capture = function() { |
||||
for (i in this.chunks) { |
var txType = this.classify(); |
||||
if (this.chunks.hasOwnProperty(i)) { |
var res = []; |
||||
chunks.push(this.chunks[i]); |
switch (txType) { |
||||
} |
case TX_PUBKEY: |
||||
} |
res.push(this.chunks[0]); |
||||
this.chunks = chunks; |
break; |
||||
this.updateBuffer(); |
case TX_PUBKEYHASH: |
||||
return this; |
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?
|
return res; |
||||
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 first extracted data item from script
|
||||
}; |
Script.prototype.captureOne = function() { |
||||
|
var arr = this.capture(); |
||||
// return first extracted data item from script
|
return arr[0]; |
||||
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; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
Script.prototype.getInType = function() { |
Script.prototype.getOutType = function() { |
||||
if (this.chunks.length == 1) { |
var txType = this.classify(); |
||||
// Direct IP to IP transactions only have the public key in their scriptSig.
|
switch (txType) { |
||||
|
case TX_PUBKEY: |
||||
return 'Pubkey'; |
return 'Pubkey'; |
||||
} else if (this.chunks.length == 2 && |
case TX_PUBKEYHASH: |
||||
Buffer.isBuffer(this.chunks[0]) && |
|
||||
Buffer.isBuffer(this.chunks[1])) { |
|
||||
return 'Address'; |
return 'Address'; |
||||
} else { |
default: |
||||
return 'Strange'; |
return 'Strange'; |
||||
} |
} |
||||
}; |
}; |
||||
|
|
||||
Script.prototype.simpleInPubKey = function() { |
Script.prototype.getRawOutType = function() { |
||||
switch (this.getInType()) { |
return TX_TYPES[this.classify()]; |
||||
case 'Address': |
}; |
||||
return this.chunks[1]; |
|
||||
case 'Pubkey': |
Script.prototype.simpleOutHash = function() { |
||||
return null; |
switch (this.getOutType()) { |
||||
default: |
case 'Address': |
||||
log.debug("Encountered non-standard scriptSig"); |
return this.chunks[2]; |
||||
log.debug("Strange script was: " + this.toString()); |
case 'Pubkey': |
||||
return null; |
return util.sha256ripe160(this.chunks[0]); |
||||
} |
default: |
||||
}; |
log.debug("Encountered non-standard scriptPubKey"); |
||||
|
log.debug("Strange script was: " + this.toString()); |
||||
Script.prototype.getBuffer = function() { |
return null; |
||||
return this.buffer; |
} |
||||
}; |
}; |
||||
|
|
||||
Script.fromStringContent = function(s) { |
Script.prototype.getInType = function() { |
||||
var chunks = []; |
if (this.chunks.length == 1) { |
||||
var split = s.split(' '); |
// Direct IP to IP transactions only have the public key in their scriptSig.
|
||||
for (var i = 0; i < split.length; i++) { |
return 'Pubkey'; |
||||
var word = split[i]; |
} else if (this.chunks.length == 2 && |
||||
if (word.length > 2 && word.substring(0, 2) === '0x') { |
Buffer.isBuffer(this.chunks[0]) && |
||||
chunks.push(new Buffer(word.substring(2, word.length), 'hex')); |
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 { |
} else { |
||||
var opcode = Opcode.map['OP_' + word]; |
var integer = parseInt(word); |
||||
if (opcode) { |
if (!isNaN(integer)) { |
||||
chunks.push(opcode); |
//console.log(integer+' bits=\t'+integer.toString(2).replace('-','').length);
|
||||
} else { |
var data = util.intToBuffer(integer); |
||||
var integer = parseInt(word); |
chunks.push(data); |
||||
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) { |
var s = ''; |
||||
if (truncate === null) { |
for (var i = 0, l = this.chunks.length; i < l; i++) { |
||||
truncate = true; |
var chunk = this.chunks[i]; |
||||
|
|
||||
|
if (i > 0) { |
||||
|
s += ' '; |
||||
} |
} |
||||
|
|
||||
if ('undefined' === typeof maxEl) { |
if (Buffer.isBuffer(chunk)) { |
||||
maxEl = 15; |
s += '0x' + util.formatBuffer(chunk, truncate ? null : 0); |
||||
|
} else { |
||||
|
s += Opcode.reverseMap[chunk]; |
||||
} |
} |
||||
|
|
||||
var s = ''; |
if (maxEl && i > maxEl) { |
||||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
s += ' ...'; |
||||
var chunk = this.chunks[i]; |
break; |
||||
|
} |
||||
|
} |
||||
|
return s; |
||||
|
}; |
||||
|
|
||||
if (i > 0) { |
Script.prototype.toString = function(truncate, maxEl) { |
||||
s += ' '; |
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) { |
Script.prototype.writeOp = function(opcode) { |
||||
s += ' ...'; |
var buf = Buffer(this.buffer.length + 1); |
||||
break; |
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; |
} else if ("number" === typeof chunk) { |
||||
}; |
for (var i = 0, l = this.chunks.length; i < l; i++) { |
||||
|
if (this.chunks[i] === chunk) { |
||||
Script.prototype.toString = function(truncate, maxEl) { |
this.chunks.splice(i, 1); |
||||
var script = "<Script "; |
dirty = true; |
||||
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 { |
||||
|
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; |
* Creates a standard txout script. |
||||
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]); |
*/ |
||||
this.chunks.push(data); |
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() { |
Script.createMultisig = function(n_required, keys) { |
||||
this.buffer = Script.chunksToBuffer(this.chunks); |
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) { |
Script.createP2SH = function(scriptHash) { |
||||
var dirty = false; |
var script = new Script(); |
||||
if (Buffer.isBuffer(chunk)) { |
script.writeOp(OP_HASH160); |
||||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
script.writeBytes(scriptHash); |
||||
if (Buffer.isBuffer(this.chunks[i]) && |
script.writeOp(OP_EQUAL); |
||||
buffertools.compare(this.chunks[i], chunk) === 0) { |
return script; |
||||
this.chunks.splice(i, 1); |
}; |
||||
dirty = true; |
|
||||
} |
Script.fromTestData = function(testData) { |
||||
} |
testData = testData.map(function(chunk) { |
||||
} else if ("number" === typeof chunk) { |
if ("string" === typeof chunk) { |
||||
for (var i = 0, l = this.chunks.length; i < l; i++) { |
return new Buffer(chunk, 'hex'); |
||||
if (this.chunks[i] === chunk) { |
|
||||
this.chunks.splice(i, 1); |
|
||||
dirty = true; |
|
||||
} |
|
||||
} |
|
||||
} else { |
} else { |
||||
throw new Error("Invalid chunk datatype."); |
return chunk; |
||||
} |
} |
||||
if (dirty) { |
}); |
||||
this.updateBuffer(); |
|
||||
} |
var script = new Script(); |
||||
}; |
script.chunks = testData; |
||||
|
script.updateBuffer(); |
||||
/** |
return script; |
||||
* Creates a simple OP_CHECKSIG with pubkey output script. |
}; |
||||
* |
|
||||
* These are used for coinbase transactions and at some point were used for |
Script.fromChunks = function(chunks) { |
||||
* IP-based transactions as well. |
var script = new Script(); |
||||
*/ |
script.chunks = chunks; |
||||
Script.createPubKeyOut = function(pubkey) { |
script.updateBuffer(); |
||||
var script = new Script(); |
return script; |
||||
script.writeBytes(pubkey); |
}; |
||||
script.writeOp(OP_CHECKSIG); |
|
||||
return script; |
Script.chunksToBuffer = function(chunks) { |
||||
}; |
var buf = new Put(); |
||||
|
|
||||
/** |
for (var i = 0, l = chunks.length; i < l; i++) { |
||||
* Creates a standard txout script. |
var data = chunks[i]; |
||||
*/ |
if (Buffer.isBuffer(data)) { |
||||
Script.createPubKeyHashOut = function(pubKeyHash) { |
if (data.length < OP_PUSHDATA1) { |
||||
var script = new Script(); |
buf.word8(data.length); |
||||
script.writeOp(OP_DUP); |
} else if (data.length <= 0xff) { |
||||
script.writeOp(OP_HASH160); |
buf.word8(OP_PUSHDATA1); |
||||
script.writeBytes(pubKeyHash); |
buf.word8(data.length); |
||||
script.writeOp(OP_EQUALVERIFY); |
} else if (data.length <= 0xffff) { |
||||
script.writeOp(OP_CHECKSIG); |
buf.word8(OP_PUSHDATA2); |
||||
return script; |
buf.word16le(data.length); |
||||
}; |
|
||||
|
|
||||
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); |
|
||||
} else { |
} 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 buf.buffer(); |
||||
|
|
||||
return Script; |
|
||||
}; |
}; |
||||
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');}; |
var hex = function(hex) {return new Buffer(hex, 'hex');}; |
||||
|
|
||||
function ClassSpec(b) { |
var fs = require('fs'); |
||||
var fs = require('fs'); |
var EncFile = require('./util/EncFile'); |
||||
var EncFile = require('./util/EncFile'); |
var Address = require('./Address'); |
||||
var Address = require('./Address').class(); |
var networks = require('./networks'); |
||||
var networks = require('./networks'); |
var util = imports.util || require('./util/util'); |
||||
var util = b.util || require('./util/util'); |
var ENC_METHOD = 'aes-256-cbc'; |
||||
var ENC_METHOD = 'aes-256-cbc'; |
|
||||
|
var skeleton = { |
||||
var skeleton = { |
client: 'libcoin', |
||||
client: 'libcoin', |
client_version: '0.0.1', |
||||
client_version: '0.0.1', |
network: 'testnet', |
||||
network: 'testnet', |
version: 1, |
||||
version: 1, |
best_hash: null, |
||||
best_hash: null, |
best_height: -1, |
||||
best_height: -1, |
keys: [], |
||||
keys: [], |
sin: {}, |
||||
sin: {}, |
scripts: {}, |
||||
scripts: {}, |
}; |
||||
}; |
|
||||
|
function Wallet(cfg) { |
||||
function Wallet(cfg) { |
if (typeof cfg !== 'object') |
||||
if (typeof cfg !== 'object') |
cfg = {}; |
||||
cfg = {}; |
|
||||
|
// deep copy (no references)
|
||||
// deep copy (no references)
|
if (cfg.datastore) |
||||
if (cfg.datastore) |
this.datastore = JSON.parse(JSON.stringify(cfg.datastore)); |
||||
this.datastore = JSON.parse(JSON.stringify(cfg.datastore)); |
else |
||||
else |
this.datastore = JSON.parse(JSON.stringify(skeleton)); |
||||
this.datastore = JSON.parse(JSON.stringify(skeleton)); |
|
||||
|
this.network = undefined; |
||||
this.network = undefined; |
this.dirty = cfg.dirty || true; |
||||
this.dirty = cfg.dirty || true; |
}; |
||||
}; |
|
||||
|
Wallet.prototype.readSync = function(filename, passphrase) { |
||||
Wallet.prototype.readSync = function(filename, passphrase) { |
this.datastore = EncFile.readJFileSync(ENC_METHOD, |
||||
this.datastore = EncFile.readJFileSync(ENC_METHOD, |
passphrase, filename); |
||||
passphrase, filename); |
this.dirty = false; |
||||
this.dirty = false; |
}; |
||||
}; |
|
||||
|
Wallet.prototype.writeSync = function(filename, passphrase) { |
||||
Wallet.prototype.writeSync = function(filename, passphrase) { |
var tmp_fn = filename + ".tmp"; |
||||
var tmp_fn = filename + ".tmp"; |
|
||||
|
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn, |
||||
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn, |
this.datastore); |
||||
this.datastore); |
fs.renameSync(tmp_fn, filename); |
||||
fs.renameSync(tmp_fn, filename); |
|
||||
|
this.dirty = false; |
||||
this.dirty = false; |
}; |
||||
}; |
|
||||
|
Wallet.prototype.setNetwork = function(netname) { |
||||
Wallet.prototype.setNetwork = function(netname) { |
if (!netname) |
||||
if (!netname) |
netname = this.datastore.network; |
||||
netname = this.datastore.network; |
|
||||
|
switch (netname) { |
||||
switch (netname) { |
case "mainnet": |
||||
case "mainnet": |
case "livenet": |
||||
case "livenet": |
this.network = networks.livenet; |
||||
this.network = networks.livenet; |
break; |
||||
break; |
case "testnet": |
||||
case "testnet": |
this.network = networks.testnet; |
||||
this.network = networks.testnet; |
break; |
||||
break; |
default: |
||||
default: |
throw new Error("Unsupported network"); |
||||
throw new Error("Unsupported network"); |
} |
||||
} |
|
||||
|
// store+canonicalize name
|
||||
// store+canonicalize name
|
this.datastore['network'] = this.network.name; |
||||
this.datastore['network'] = this.network.name; |
this.dirty = true; |
||||
this.dirty = true; |
}; |
||||
}; |
|
||||
|
Wallet.prototype.addKey = function(wkey) { |
||||
Wallet.prototype.addKey = function(wkey) { |
this.datastore.keys.push(wkey); |
||||
this.datastore.keys.push(wkey); |
this.dirty = true; |
||||
this.dirty = true; |
|
||||
}; |
|
||||
|
|
||||
Wallet.prototype.addSIN = function(sinObj) { |
|
||||
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; |
|
||||
}; |
}; |
||||
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 coinUtil = require('./util/util'); |
var timeUtil = require('./util/time'); |
||||
var timeUtil = require('./util/time'); |
var KeyModule = require('./Key'); |
||||
var KeyModule = require('./Key'); |
var PrivateKey = require('./PrivateKey'); |
||||
var PrivateKey = require('./PrivateKey').class(); |
var Address = require('./Address'); |
||||
var Address = require('./Address').class(); |
|
||||
|
|
||||
function WalletKey(cfg) { |
function WalletKey(cfg) { |
||||
if (!cfg) cfg = {}; |
if (!cfg) cfg = {}; |
||||
if (!cfg.network) throw new Error('network parameter is required'); |
if (!cfg.network) throw new Error('network parameter is required'); |
||||
this.network = cfg.network; // required
|
this.network = cfg.network; // required
|
||||
this.created = cfg.created; |
this.created = cfg.created; |
||||
this.privKey = cfg.privKey; |
this.privKey = cfg.privKey; |
||||
}; |
}; |
||||
|
|
||||
WalletKey.prototype.generate = function() { |
|
||||
this.privKey = KeyModule.Key.generateSync(); |
|
||||
this.created = timeUtil.curtime(); |
|
||||
}; |
|
||||
|
|
||||
WalletKey.prototype.storeObj = function() { |
WalletKey.prototype.generate = function() { |
||||
var pubKey = this.privKey.public.toString('hex'); |
this.privKey = KeyModule.Key.generateSync(); |
||||
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public); |
this.created = timeUtil.curtime(); |
||||
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(), |
|
||||
}; |
|
||||
|
|
||||
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) { |
return 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 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) { |
function VersionedData(version, payload) { |
||||
if(typeof version != 'number') { |
if(typeof version != 'number') { |
||||
VersionedData.super(this, arguments); |
VersionedData.super(this, arguments); |
||||
return; |
return; |
||||
}; |
|
||||
this.data = new Buffer(payload.length + 1); |
|
||||
this.__proto__ = this.encodings['binary']; |
|
||||
this.version(version); |
|
||||
this.payload(payload); |
|
||||
}; |
}; |
||||
VersionedData.superclass = superclass; |
this.data = new Buffer(payload.length + 1); |
||||
superclass.applyEncodingsTo(VersionedData); |
this.__proto__ = this.encodings['binary']; |
||||
|
this.version(version); |
||||
|
this.payload(payload); |
||||
|
}; |
||||
|
|
||||
// get or set the version data (the first byte of the address)
|
VersionedData.parent = parent; |
||||
VersionedData.prototype.version = function(num) { |
parent.applyEncodingsTo(VersionedData); |
||||
if(num || (num === 0)) { |
|
||||
this.doAsBinary(function() {this.data.writeUInt8(num, 0);}); |
|
||||
return num; |
|
||||
} |
|
||||
return this.as('binary').readUInt8(0); |
|
||||
}; |
|
||||
|
|
||||
// get or set the payload data (as a Buffer object)
|
// get or set the version data (the first byte of the address)
|
||||
VersionedData.prototype.payload = function(data) { |
VersionedData.prototype.version = function(num) { |
||||
if(data) { |
if(num || (num === 0)) { |
||||
this.doAsBinary(function() {data.copy(this.data,1);}); |
this.doAsBinary(function() {this.data.writeUInt8(num, 0);}); |
||||
return data; |
return num; |
||||
} |
} |
||||
return this.as('binary').slice(1); |
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