Merge remote-tracking branch 'matiu/feature/support-soop-browser'

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.
This commit is contained in:
Ryan X. Charles 2014-03-08 19:30:21 -05:00
commit c19fb7a3ce
55 changed files with 5005 additions and 4932 deletions

View File

@ -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;
superclass.applyEncodingsTo(Address);
Address.prototype.validate = function() {
this.doAsBinary(function() {
Address.super(this, 'validate', arguments);
if(this.data.length !== 21) throw new Error('invalid data length');
});
};
return Address;
} }
module.defineClass(ClassSpec);
Address.parent = parent;
parent.applyEncodingsTo(Address);
Address.prototype.validate = function() {
this.doAsBinary(function() {
Address.super(this, 'validate', arguments);
if(this.data.length !== 21) throw new Error('invalid data length');
});
};
module.exports = require('soop')(Address);

1117
Block.js

File diff suppressed because it is too large Load Diff

221
Bloom.js
View File

@ -1,116 +1,111 @@
require('classtool'); var MAX_BLOOM_FILTER_SIZE = 36000; // bytes
var MAX_HASH_FUNCS = 50;
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
function ClassSpec(b) { function Bloom() {
var MAX_BLOOM_FILTER_SIZE = 36000; // bytes this.data = '';
var MAX_HASH_FUNCS = 50; this.hashFuncs = 0;
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
function Bloom() {
this.data = '';
this.hashFuncs = 0;
};
function ROTL32(x, r) {
return (x << r) | (x >> (32 - r));
};
function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8));
return v;
};
Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var nBlocks = data.length / 4;
// data body
for (var i = -nBlocks; i; i++) {
var k1 = getBlockU32(i);
k1 *= c1;
k1 = ROTLF32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = ROTFL(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (trailing 1-3 bytes)
var tail = data.slice(nBlocks * 4);
var k1 = 0;
switch (data.length & 3) {
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
// finalize
h1 ^= data.length;
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1 % (this.data.length * 8);
};
Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index];
}
};
Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index]))
return false;
}
return true;
};
Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS;
};
function toInt(v) {
return ~~v;
}
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);
};
return Bloom;
}; };
module.defineClass(ClassSpec);
function ROTL32(x, r) {
return (x << r) | (x >> (32 - r));
};
function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8));
return v;
};
Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
var nBlocks = data.length / 4;
// data body
for (var i = -nBlocks; i; i++) {
var k1 = getBlockU32(i);
k1 *= c1;
k1 = ROTLF32(k1, 15);
k1 *= c2;
h1 ^= k1;
h1 = ROTFL(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (trailing 1-3 bytes)
var tail = data.slice(nBlocks * 4);
var k1 = 0;
switch (data.length & 3) {
case 3: k1 ^= tail[2] << 16;
case 2: k1 ^= tail[1] << 8;
case 1: k1 ^= tail[0];
k1 *= c1;
k1 = ROTL32(k1, 15);
k1 *= c2;
h1 ^= k1;
}
// finalize
h1 ^= data.length;
h1 ^= h1 >> 16;
h1 *= 0x85ebca6b;
h1 ^= h1 >> 13;
h1 *= 0xc2b2ae35;
h1 ^= h1 >> 16;
return h1 % (this.data.length * 8);
};
Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index];
}
};
Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index]))
return false;
}
return true;
};
Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS;
};
function toInt(v) {
return ~~v;
}
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 Load Diff

View File

@ -3,26 +3,28 @@
module.exports = function(grunt) { module.exports = function(grunt) {
//Load NPM tasks //Load NPM tasks
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-mocha-test'); grunt.loadNpmTasks('grunt-mocha-test');
grunt.loadNpmTasks('grunt-markdown'); grunt.loadNpmTasks('grunt-markdown');
grunt.loadNpmTasks('grunt-shell');
// Project Configuration // Project Configuration
grunt.initConfig({ grunt.initConfig({
browserify: { shell: {
client: { browserify: {
src: ['bitcore.js'],
dest: 'browser/bundle.js',
options: { options: {
debug: true, stdout: true
alias: [ },
'browserify-bignum/bignumber.js:bignum', command: 'node ./browserify.js > browser/bundle.js',
'browserify-buffertools/buffertools.js:buffertools'
],
standalone: 'bitcore',
}
}, },
browserifyData: {
options: {
stdout: true
},
command: 'browserify -t brfs test/testdata.js > browser/testdata.js'
},
},
browserify: {
test_data: { test_data: {
src: ['test/testdata.js'], src: ['test/testdata.js'],
dest: 'browser/testdata.js', dest: 'browser/testdata.js',
@ -40,7 +42,7 @@ module.exports = function(grunt) {
}, },
scripts: { scripts: {
files: ['**/*.js', '**/*.html', '!**/node_modules/**', '!browser/bundle.js', '!browser/testdata.js'], files: ['**/*.js', '**/*.html', '!**/node_modules/**', '!browser/bundle.js', '!browser/testdata.js'],
tasks: ['browserify' /*, 'mochaTest'*/ ], tasks: ['shell' /*, 'mochaTest'*/ ],
}, },
}, },
mochaTest: { mochaTest: {

315
Opcode.js
View File

@ -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 () {
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;
}; };
module.defineClass(spec);
Opcode.prototype.toString = function () {
return Opcode.reverseMap[this.code];
};
Opcode.map = {
// push value
OP_FALSE : 0,
OP_0 : 0,
OP_PUSHDATA1 : 76,
OP_PUSHDATA2 : 77,
OP_PUSHDATA4 : 78,
OP_1NEGATE : 79,
OP_RESERVED : 80,
OP_TRUE : 81,
OP_1 : 81,
OP_2 : 82,
OP_3 : 83,
OP_4 : 84,
OP_5 : 85,
OP_6 : 86,
OP_7 : 87,
OP_8 : 88,
OP_9 : 89,
OP_10 : 90,
OP_11 : 91,
OP_12 : 92,
OP_13 : 93,
OP_14 : 94,
OP_15 : 95,
OP_16 : 96,
// control
OP_NOP : 97,
OP_VER : 98,
OP_IF : 99,
OP_NOTIF : 100,
OP_VERIF : 101,
OP_VERNOTIF : 102,
OP_ELSE : 103,
OP_ENDIF : 104,
OP_VERIFY : 105,
OP_RETURN : 106,
// stack ops
OP_TOALTSTACK : 107,
OP_FROMALTSTACK : 108,
OP_2DROP : 109,
OP_2DUP : 110,
OP_3DUP : 111,
OP_2OVER : 112,
OP_2ROT : 113,
OP_2SWAP : 114,
OP_IFDUP : 115,
OP_DEPTH : 116,
OP_DROP : 117,
OP_DUP : 118,
OP_NIP : 119,
OP_OVER : 120,
OP_PICK : 121,
OP_ROLL : 122,
OP_ROT : 123,
OP_SWAP : 124,
OP_TUCK : 125,
// splice ops
OP_CAT : 126,
OP_SUBSTR : 127,
OP_LEFT : 128,
OP_RIGHT : 129,
OP_SIZE : 130,
// bit logic
OP_INVERT : 131,
OP_AND : 132,
OP_OR : 133,
OP_XOR : 134,
OP_EQUAL : 135,
OP_EQUALVERIFY : 136,
OP_RESERVED1 : 137,
OP_RESERVED2 : 138,
// numeric
OP_1ADD : 139,
OP_1SUB : 140,
OP_2MUL : 141,
OP_2DIV : 142,
OP_NEGATE : 143,
OP_ABS : 144,
OP_NOT : 145,
OP_0NOTEQUAL : 146,
OP_ADD : 147,
OP_SUB : 148,
OP_MUL : 149,
OP_DIV : 150,
OP_MOD : 151,
OP_LSHIFT : 152,
OP_RSHIFT : 153,
OP_BOOLAND : 154,
OP_BOOLOR : 155,
OP_NUMEQUAL : 156,
OP_NUMEQUALVERIFY : 157,
OP_NUMNOTEQUAL : 158,
OP_LESSTHAN : 159,
OP_GREATERTHAN : 160,
OP_LESSTHANOREQUAL : 161,
OP_GREATERTHANOREQUAL : 162,
OP_MIN : 163,
OP_MAX : 164,
OP_WITHIN : 165,
// crypto
OP_RIPEMD160 : 166,
OP_SHA1 : 167,
OP_SHA256 : 168,
OP_HASH160 : 169,
OP_HASH256 : 170,
OP_CODESEPARATOR : 171,
OP_CHECKSIG : 172,
OP_CHECKSIGVERIFY : 173,
OP_CHECKMULTISIG : 174,
OP_CHECKMULTISIGVERIFY : 175,
// expansion
OP_NOP1 : 176,
OP_NOP2 : 177,
OP_NOP3 : 178,
OP_NOP4 : 179,
OP_NOP5 : 180,
OP_NOP6 : 181,
OP_NOP7 : 182,
OP_NOP8 : 183,
OP_NOP9 : 184,
OP_NOP10 : 185,
// template matching params
OP_PUBKEYHASH : 253,
OP_PUBKEY : 254,
OP_INVALIDOPCODE : 255
};
Opcode.reverseMap = [];
for (var k in Opcode.map) {
if(Opcode.map.hasOwnProperty(k)) {
Opcode.reverseMap[Opcode.map[k]] = k.substr(3);
}
}
module.exports = require('soop')(Opcode);

109
Peer.js
View File

@ -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.services = (services) ? services : null;
this.lastSeen = 0; 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 () {
return new Buffer(this.host.split('.'));
};
Peer.prototype.toString = function () {
return this.host + ":" + this.port;
};
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();
};
return Peer;
}; };
module.defineClass(spec);
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 () {
return new Buffer(this.host.split('.'));
};
Peer.prototype.toString = function () {
return this.host + ":" + this.port;
};
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.exports = require('soop')(Peer);

View File

@ -1,215 +1,214 @@
require('classtool');
function spec(b) { var imports = require('soop').imports();
var config = b.config || require('./config'); var config = imports.config || require('./config');
var log = b.log || require('./util/log'); var log = imports.log || require('./util/log');
var network = b.network || require('./networks')[config.network]; var network = imports.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 () { var Connection = imports.Connection ||
// TODO: Implement actual adjustment require('soop').load('Connection', {config: config, network: network}) ||
return Math.floor(new Date().getTime() / 1000); require ('./Connection');
};
function PeerManager() { var Peer = imports.Peer || require('./Peer');
this.active = false;
this.timer = null;
this.peers = []; GetAdjustedTime = imports.GetAdjustedTime || function () {
this.connections = []; // TODO: Implement actual adjustment
this.isConnected = false; return Math.floor(new Date().getTime() / 1000);
this.peerDiscovery = false;
// Move these to the Node's settings object
this.interval = 5000;
this.minConnections = 8;
this.minKnownPeers = 10;
};
PeerManager.superclass = b.superclass || require('events').EventEmitter;
PeerManager.Connection = Connection;
PeerManager.prototype.start = function() {
this.active = true;
if(!this.timer) {
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
}
};
PeerManager.prototype.stop = function() {
this.active = false;
if(this.timer) {
clearInterval(this.timer);
this.timer = null;
}
for(var i=0; i<this.connections.length; i++) {
this.connections[i].socket.end();
};
};
PeerManager.prototype.addPeer = function(peer, port) {
if(peer instanceof Peer) {
this.peers.push(peer);
} else if ("string" == typeof peer) {
this.addPeer(new Peer(peer, port));
} else {
log.err('Node.addPeer(): Invalid value provided for peer',
{val: peer});
throw 'Node.addPeer(): Invalid value provided for peer.';
}
};
PeerManager.prototype.checkStatus = function checkStatus() {
// Make sure we are connected to all forcePeers
if(this.peers.length) {
var peerIndex = {};
this.peers.forEach(function(peer) {
peerIndex[peer.toString()] = peer;
});
// Ignore the ones we're already connected to
this.connections.forEach(function(conn) {
var peerName = conn.peer.toString();
if("undefined" !== peerIndex[peerName]) {
delete peerIndex[peerName];
}
});
Object.keys(peerIndex).forEach(function(i) {
this.connectTo(peerIndex[i]);
}.bind(this));
}
};
PeerManager.prototype.connectTo = function(peer) {
log.info('connecting to '+peer);
try {
return this.addConnection(peer.createConnection(), peer);
} catch (e) {
log.err('creating connection',e);
return null;
}
};
PeerManager.prototype.addConnection = function(socketConn, peer) {
var conn = new Connection(socketConn, peer);
this.connections.push(conn);
this.emit('connection', conn);
conn.addListener('version', this.handleVersion.bind(this));
conn.addListener('verack', this.handleReady.bind(this));
conn.addListener('addr', this.handleAddr.bind(this));
conn.addListener('getaddr', this.handleGetAddr.bind(this));
conn.addListener('error', this.handleError.bind(this));
conn.addListener('disconnect', this.handleDisconnect.bind(this));
return conn;
};
PeerManager.prototype.handleVersion = function(e) {
if (!e.conn.inbound) {
// TODO: Advertise our address (if listening)
}
// Get recent addresses
if(this.peerDiscovery &&
(e.message.version >= 31402 || this.peers.length < 1000)) {
e.conn.sendGetAddr();
e.conn.getaddr = true;
}
};
PeerManager.prototype.handleReady = function (e) {
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port);
this.emit('connect', {
pm: this,
conn: e.conn,
socket: e.socket,
peer: e.peer
});
if(this.isConnected == false) {
this.emit('netConnected');
this.isConnected = true;
}
};
PeerManager.prototype.handleAddr = function (e) {
if(!this.peerDiscovery) return;
var now = GetAdjustedTime();
e.message.addrs.forEach(function (addr) {
try {
// In case of an invalid time, assume "5 days ago"
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) {
addr.time = now - 5 * 24 * 60 * 60;
}
var peer = new Peer(addr.ip, addr.port, addr.services);
peer.lastSeen = addr.time;
// TODO: Handle duplicate peers
this.peers.push(peer);
// TODO: Handle addr relay
} catch(e) {
log.warn("Invalid addr received: "+e.message);
}
}.bind(this));
if (e.message.addrs.length < 1000 ) {
e.conn.getaddr = false;
}
};
PeerManager.prototype.handleGetAddr = function(e) {
// TODO: Reply with addr message.
};
PeerManager.prototype.handleError = function(e) {
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
this.handleDisconnect.apply(this, [].slice.call(arguments));
};
PeerManager.prototype.handleDisconnect = function(e) {
log.info('disconnected from peer '+e.peer);
var i = this.connections.indexOf(e.conn);
if(i != -1) this.connections.splice(i, 1);
if(!this.connections.length) {
this.emit('netDisconnected');
this.isConnected = false;
}
};
PeerManager.prototype.getActiveConnection = function () {
var activeConnections = this.connections.filter(function (conn) {
return conn.active;
});
if (activeConnections.length) {
var randomIndex = Math.floor(Math.random()*activeConnections.length);
var candidate = activeConnections[randomIndex];
if (candidate.socket.writable) {
return candidate;
} else {
// Socket is not writable, remove it from active connections
activeConnections.splice(randomIndex, 1);
// Then try again
// TODO: This causes an infinite recursion when all connections are dead,
// although it shouldn't.
return this.getActiveConnection();
}
} else {
return null;
}
};
PeerManager.prototype.getActiveConnections = function () {
return this.connections.slice(0);
};
return PeerManager;
}; };
module.defineClass(spec);
function PeerManager() {
this.active = false;
this.timer = null;
this.peers = [];
this.connections = [];
this.isConnected = false;
this.peerDiscovery = false;
// Move these to the Node's settings object
this.interval = 5000;
this.minConnections = 8;
this.minKnownPeers = 10;
};
PeerManager.parent = imports.parent || require('events').EventEmitter;
PeerManager.Connection = Connection;
PeerManager.prototype.start = function() {
this.active = true;
if(!this.timer) {
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
}
};
PeerManager.prototype.stop = function() {
this.active = false;
if(this.timer) {
clearInterval(this.timer);
this.timer = null;
}
for(var i=0; i<this.connections.length; i++) {
this.connections[i].socket.end();
};
};
PeerManager.prototype.addPeer = function(peer, port) {
if(peer instanceof Peer) {
this.peers.push(peer);
} else if ("string" == typeof peer) {
this.addPeer(new Peer(peer, port));
} else {
log.err('Node.addPeer(): Invalid value provided for peer',
{val: peer});
throw 'Node.addPeer(): Invalid value provided for peer.';
}
};
PeerManager.prototype.checkStatus = function checkStatus() {
// Make sure we are connected to all forcePeers
if(this.peers.length) {
var peerIndex = {};
this.peers.forEach(function(peer) {
peerIndex[peer.toString()] = peer;
});
// Ignore the ones we're already connected to
this.connections.forEach(function(conn) {
var peerName = conn.peer.toString();
if("undefined" !== peerIndex[peerName]) {
delete peerIndex[peerName];
}
});
Object.keys(peerIndex).forEach(function(i) {
this.connectTo(peerIndex[i]);
}.bind(this));
}
};
PeerManager.prototype.connectTo = function(peer) {
log.info('connecting to '+peer);
try {
return this.addConnection(peer.createConnection(), peer);
} catch (e) {
log.err('creating connection',e);
return null;
}
};
PeerManager.prototype.addConnection = function(socketConn, peer) {
var conn = new Connection(socketConn, peer);
this.connections.push(conn);
this.emit('connection', conn);
conn.addListener('version', this.handleVersion.bind(this));
conn.addListener('verack', this.handleReady.bind(this));
conn.addListener('addr', this.handleAddr.bind(this));
conn.addListener('getaddr', this.handleGetAddr.bind(this));
conn.addListener('error', this.handleError.bind(this));
conn.addListener('disconnect', this.handleDisconnect.bind(this));
return conn;
};
PeerManager.prototype.handleVersion = function(e) {
if (!e.conn.inbound) {
// TODO: Advertise our address (if listening)
}
// Get recent addresses
if(this.peerDiscovery &&
(e.message.version >= 31402 || this.peers.length < 1000)) {
e.conn.sendGetAddr();
e.conn.getaddr = true;
}
};
PeerManager.prototype.handleReady = function (e) {
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port);
this.emit('connect', {
pm: this,
conn: e.conn,
socket: e.socket,
peer: e.peer
});
if(this.isConnected == false) {
this.emit('netConnected');
this.isConnected = true;
}
};
PeerManager.prototype.handleAddr = function (e) {
if(!this.peerDiscovery) return;
var now = GetAdjustedTime();
e.message.addrs.forEach(function (addr) {
try {
// In case of an invalid time, assume "5 days ago"
if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) {
addr.time = now - 5 * 24 * 60 * 60;
}
var peer = new Peer(addr.ip, addr.port, addr.services);
peer.lastSeen = addr.time;
// TODO: Handle duplicate peers
this.peers.push(peer);
// TODO: Handle addr relay
} catch(e) {
log.warn("Invalid addr received: "+e.message);
}
}.bind(this));
if (e.message.addrs.length < 1000 ) {
e.conn.getaddr = false;
}
};
PeerManager.prototype.handleGetAddr = function(e) {
// TODO: Reply with addr message.
};
PeerManager.prototype.handleError = function(e) {
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
this.handleDisconnect.apply(this, [].slice.call(arguments));
};
PeerManager.prototype.handleDisconnect = function(e) {
log.info('disconnected from peer '+e.peer);
var i = this.connections.indexOf(e.conn);
if(i != -1) this.connections.splice(i, 1);
if(!this.connections.length) {
this.emit('netDisconnected');
this.isConnected = false;
}
};
PeerManager.prototype.getActiveConnection = function () {
var activeConnections = this.connections.filter(function (conn) {
return conn.active;
});
if (activeConnections.length) {
var randomIndex = Math.floor(Math.random()*activeConnections.length);
var candidate = activeConnections[randomIndex];
if (candidate.socket.writable) {
return candidate;
} else {
// Socket is not writable, remove it from active connections
activeConnections.splice(randomIndex, 1);
// Then try again
// TODO: This causes an infinite recursion when all connections are dead,
// although it shouldn't.
return this.getActiveConnection();
}
} else {
return null;
}
};
PeerManager.prototype.getActiveConnections = function () {
return this.connections.slice(0);
};
module.exports = require('soop')(PeerManager);

View File

@ -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;
superclass.applyEncodingsTo(PrivateKey);
PrivateKey.prototype.validate = function() {
this.doAsBinary(function() {
PrivateKey.super(this, 'validate', arguments);
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
throw new Error('invalid data length');
});
};
// get or set the payload data (as a Buffer object)
// overloaded from VersionedData
PrivateKey.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data,1);});
return data;
}
var buf=this.as('binary');
if (buf.length==1+32+1)
return buf.slice(1,1+32);
else if (buf.length==1+32)
return buf.slice(1);
};
// get or set whether the corresponding public key is compressed
PrivateKey.prototype.compressed = function(compressed) {
if (compressed !== undefined) {
this.doAsBinary(function(){
var len=1+32+1;
if (compressed) {
var data=new Buffer(len);
this.data.copy(data);
this.data=data;
this.data[len-1]=1;
} else {
this.data=this.data.slice(0,len-1);
}
});
}
else {
var len=1+32+1;
var data=this.as('binary');
if (data.length==len && data[len-1]==1)
return true;
else if (data.length==len-1)
return false;
else
throw new Error('invalid private key');
}
};
return PrivateKey;
}; };
module.defineClass(ClassSpec);
PrivateKey.parent = parent;
parent.applyEncodingsTo(PrivateKey);
PrivateKey.prototype.validate = function() {
this.doAsBinary(function() {
PrivateKey.super(this, 'validate', arguments);
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
throw new Error('invalid data length');
});
};
// get or set the payload data (as a Buffer object)
// overloaded from VersionedData
PrivateKey.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data,1);});
return data;
}
var buf=this.as('binary');
if (buf.length==1+32+1)
return buf.slice(1,1+32);
else if (buf.length==1+32)
return buf.slice(1);
};
// get or set whether the corresponding public key is compressed
PrivateKey.prototype.compressed = function(compressed) {
if (compressed !== undefined) {
this.doAsBinary(function(){
var len=1+32+1;
if (compressed) {
var data=new Buffer(len);
this.data.copy(data);
this.data=data;
this.data[len-1]=1;
} else {
this.data=this.data.slice(0,len-1);
}
});
}
else {
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.exports = require('soop')(PrivateKey);

View File

@ -17,9 +17,9 @@ Bitcore runs on [node](http://nodejs.org/), and can be installed via [npm](https
npm install bitcore npm install bitcore
``` ```
It is a collection of objects useful to bitcoin applications; class-like idioms are enabled via [Classtool](https://github.com/gasteve/classtool). In most cases, a developer will require the object's class directly: It is a collection of objects useful to bitcoin applications; class-like idioms are enabled via [Soop](https://github.com/gasteve/soop). In most cases, a developer will require the object's class directly:
``` ```
var Address = require('bitcore/Address').class(); var Address = require('bitcore/Address');
``` ```
#Examples #Examples
@ -29,7 +29,7 @@ Some examples are provided at the [examples](/examples) path. Here are some snip
## Validating an address ## Validating an address
Validating a Bitcoin address: Validating a Bitcoin address:
```js ```js
var Address = require('bitcore/Address').class(); var Address = require('bitcore/Address');
var addrStrings = [ var addrStrings = [
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
@ -57,10 +57,9 @@ For this example you need a running bitcoind instance with RPC enabled.
```js ```js
var util = require('util'); var util = require('util');
var networks = require('bitcore/networks'); var networks = require('bitcore/networks');
var Peer = require('bitcore/Peer').class(); var Peer = require('bitcore/Peer');
var PeerManager = require('bitcore/PeerManager').createClass({ var PeerManager = require('soop').load('bitcore/PeerManager',
network: networks.testnet {network: networks.testnet});
});
var handleBlock = function(info) { var handleBlock = function(info) {
@ -109,14 +108,13 @@ PeerManager will emit the following events: 'version', 'verack', 'addr', 'getadd
For this example you need a running bitcoind instance with RPC enabled. For this example you need a running bitcoind instance with RPC enabled.
```js ```js
var networks = require('bitcore/networks'); var networks = require('bitcore/networks');
var Peer = require('bitcore/Peer').class(); var Peer = require('bitcore/Peer');
var Transaction = require('bitcore/Transaction').class(); var Transaction = require('bitcore/Transaction');
var Address = require('bitcore/Address').class(); var Address = require('bitcore/Address');
var Script = require('bitcore/Script').class(); var Script = require('bitcore/Script');
var coinUtil = require('bitcore/util/util'); var coinUtil = require('bitcore/util/util');
var PeerManager = require('bitcore/PeerManager').createClass({ var PeerManager = require('soop').load('bitcore/PeerManager',
network: networks.testnet {network: networks.testnet});
});
var createTx = function() { var createTx = function() {
@ -185,7 +183,7 @@ peerman.start();
For this example you need a running bitcoind instance with RPC enabled. For this example you need a running bitcoind instance with RPC enabled.
```js ```js
var util = require('util'); var util = require('util');
var RpcClient = require('bitcore/RpcClient').class(); var RpcClient = require('bitcore/RpcClient');
var hash = process.argv[2] || '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4'; var hash = process.argv[2] || '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4';
var config = { var config = {
@ -217,7 +215,7 @@ Check the list of all supported RPC call at [RpcClient.js](RpcClient.js)
Gets an address strings from a ScriptPubKey Buffer Gets an address strings from a ScriptPubKey Buffer
``` ```
var Address = require('bitcore/Address').class(); var Address = require('bitcore/Address');
var coinUtil= require('bitcore/util/util'); var coinUtil= require('bitcore/util/util');
var getAddrStr = function(s) { var getAddrStr = function(s) {

View File

@ -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) {
return Array.prototype.slice.call(arr, start, end);
};
function generateRPCMethods(constructor, apiCalls, rpc) {
function createRPCMethod(methodName, argMap) {
return function() {
var limit = arguments.length - 1;
if(this.batchedCalls) var limit = arguments.length;
for (var i=0; i<limit; i++) {
if(argMap[i]) arguments[i] = argMap[i](arguments[i]);
};
if(this.batchedCalls) {
this.batchedCalls.push({jsonrpc: '2.0', method: methodName, params: slice(arguments)});
} else {
rpc.call(this, {method: methodName, params: slice(arguments, 0, arguments.length - 1)}, arguments[arguments.length - 1]);
}
};
};
var types = {
str: function(arg) {return arg.toString();},
int: function(arg) {return parseFloat(arg);},
float: function(arg) {return parseFloat(arg);},
bool: function(arg) {return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');},
};
for(var k in apiCalls) {
if (apiCalls.hasOwnProperty(k)) {
var spec = apiCalls[k].split(' ');
for (var i = 0; i < spec.length; i++) {
if(types[spec[i]]) {
spec[i] = types[spec[i]];
} else {
spec[i] = types.string;
}
}
var methodName = k.toLowerCase();
constructor.prototype[k] = createRPCMethod(methodName, spec);
constructor.prototype[methodName] = constructor.prototype[k];
}
}
}
function rpc(request, callback) {
var self = this;
var request;
request = JSON.stringify(request);
var auth = Buffer(self.user + ':' + self.pass).toString('base64');
var options = {
host: self.host,
path: '/',
method: 'POST',
port: self.port,
agent: self.disableAgent ? false : undefined,
};
if(self.httpOptions) {
for(var k in self.httpOptions) {
options[k] = self.httpOptions[k];
}
}
var err = null;
var req = this.protocol.request(options, function(res) {
var buf = '';
res.on('data', function(data) {
buf += data;
});
res.on('end', function() {
if(res.statusCode == 401) {
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized'));
return;
}
if(res.statusCode == 403) {
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden'));
return;
}
if(err) {
callback(err);
return;
}
try {
var parsedBuf = JSON.parse(buf);
} catch(e) {
log.err(e.stack);
log.err(buf);
log.err('HTTP Status code:' + res.statusCode);
callback(e);
return;
}
callback(parsedBuf.error, parsedBuf);
});
});
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();
};
generateRPCMethods(RpcClient, callspec, rpc);
return RpcClient;
}; };
module.defineClass(ClassSpec);
var slice = function(arr, start, end) {
return Array.prototype.slice.call(arr, start, end);
};
function generateRPCMethods(constructor, apiCalls, rpc) {
function createRPCMethod(methodName, argMap) {
return function() {
var limit = arguments.length - 1;
if(this.batchedCalls) var limit = arguments.length;
for (var i=0; i<limit; i++) {
if(argMap[i]) arguments[i] = argMap[i](arguments[i]);
};
if(this.batchedCalls) {
this.batchedCalls.push({jsonrpc: '2.0', method: methodName, params: slice(arguments)});
} else {
rpc.call(this, {method: methodName, params: slice(arguments, 0, arguments.length - 1)}, arguments[arguments.length - 1]);
}
};
};
var types = {
str: function(arg) {return arg.toString();},
int: function(arg) {return parseFloat(arg);},
float: function(arg) {return parseFloat(arg);},
bool: function(arg) {return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true');},
};
for(var k in apiCalls) {
if (apiCalls.hasOwnProperty(k)) {
var spec = apiCalls[k].split(' ');
for (var i = 0; i < spec.length; i++) {
if(types[spec[i]]) {
spec[i] = types[spec[i]];
} else {
spec[i] = types.string;
}
}
var methodName = k.toLowerCase();
constructor.prototype[k] = createRPCMethod(methodName, spec);
constructor.prototype[methodName] = constructor.prototype[k];
}
}
}
function rpc(request, callback) {
var self = this;
var request;
request = JSON.stringify(request);
var auth = Buffer(self.user + ':' + self.pass).toString('base64');
var options = {
host: self.host,
path: '/',
method: 'POST',
port: self.port,
agent: self.disableAgent ? false : undefined,
};
if(self.httpOptions) {
for(var k in self.httpOptions) {
options[k] = self.httpOptions[k];
}
}
var err = null;
var req = this.protocol.request(options, function(res) {
var buf = '';
res.on('data', function(data) {
buf += data;
});
res.on('end', function() {
if(res.statusCode == 401) {
callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized'));
return;
}
if(res.statusCode == 403) {
callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden'));
return;
}
if(err) {
callback(err);
return;
}
try {
var parsedBuf = JSON.parse(buf);
} catch(e) {
log.err(e.stack);
log.err(buf);
log.err('HTTP Status code:' + res.statusCode);
callback(e);
return;
}
callback(parsedBuf.error, parsedBuf);
});
});
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();
};
generateRPCMethods(RpcClient, callspec, rpc);
module.exports = require('soop')(RpcClient);

109
SIN.js
View File

@ -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; this.data = new Buffer(1 + 1 + payload.length);
superclass.applyEncodingsTo(SIN); this.__proto__ = this.encodings['binary'];
this.prefix(0x0F); // SIN magic number, in numberspace
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX this.type(type);
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX this.payload(payload);
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
// get or set the prefix data (the first byte of the address)
SIN.prototype.prefix = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
// get or set the SIN-type data (the second byte of the address)
SIN.prototype.type = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 1);});
return num;
}
return this.as('binary').readUInt8(1);
};
// get or set the payload data (as a Buffer object)
SIN.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data, 2);});
return data;
}
return this.as('binary').slice(1);
};
SIN.prototype.validate = function() {
this.doAsBinary(function() {
SIN.super(this, 'validate', arguments);
if (this.data.length != 22) throw new Error('invalid data length');
});
};
return SIN;
}; };
module.defineClass(ClassSpec); SIN.parent = parent;
parent.applyEncodingsTo(SIN);
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
// get or set the prefix data (the first byte of the address)
SIN.prototype.prefix = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
// get or set the SIN-type data (the second byte of the address)
SIN.prototype.type = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 1);});
return num;
}
return this.as('binary').readUInt8(1);
};
// get or set the payload data (as a Buffer object)
SIN.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data, 2);});
return data;
}
return this.as('binary').slice(1);
};
SIN.prototype.validate = function() {
this.doAsBinary(function() {
SIN.super(this, 'validate', arguments);
if (this.data.length != 22) throw new Error('invalid data length');
});
};
module.exports = require('soop')(SIN);

View File

@ -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() {
return coinUtil.sha256ripe160(this.privKey.public);
};
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 obj;
};
return SINKey;
}; };
module.defineClass(ClassSpec);
SINKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
SINKey.prototype.pubkeyHash = function() {
return coinUtil.sha256ripe160(this.privKey.public);
};
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 obj;
};
module.exports = require('soop')(SINKey);

1019
Script.js

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

272
Wallet.js
View File

@ -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) {
if (typeof cfg !== 'object')
cfg = {};
// deep copy (no references)
if (cfg.datastore)
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
else
this.datastore = JSON.parse(JSON.stringify(skeleton));
this.network = undefined;
this.dirty = cfg.dirty || true;
};
Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename);
this.dirty = false;
};
Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp";
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
this.datastore);
fs.renameSync(tmp_fn, filename);
this.dirty = false;
};
Wallet.prototype.setNetwork = function(netname) {
if (!netname)
netname = this.datastore.network;
switch (netname) {
case "mainnet":
case "livenet":
this.network = networks.livenet;
break;
case "testnet":
this.network = networks.testnet;
break;
default:
throw new Error("Unsupported network");
}
// store+canonicalize name
this.datastore['network'] = this.network.name;
this.dirty = true;
};
Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey);
this.dirty = true;
};
Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true;
};
Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString();
for (var i = 0; i < this.datastore.keys.length; i++) {
var obj = this.datastore.keys[i];
var addrStr = obj.addr;
var addr = new Address(addrStr);
if (addr.payload().toString() == pkhStr)
return obj;
}
return undefined;
};
Wallet.prototype.expandKey = function(key) {
var addr = new Address(key);
var isAddr = true;
try {
addr.validate();
var b = addr.payload();
var obj = this.findKeyHash(b);
key = obj.pub;
} catch(e) {
// do nothing
}
var re = /^[a-fA-F0-9]+$/;
if (!key.match(re))
throw new Error("Unknown key type");
return hex(key);
};
Wallet.prototype.expandKeys = function(keys) {
var res = [];
var us = this;
keys.forEach(function(key) {
var expKey = us.expandKey(key);
res.push(expKey);
});
return res;
};
Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer();
var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash);
var addrStr = addr.as('base58');
this.datastore.scripts[addrStr] = buf.toString('hex');
this.dirty = true;
return addrStr;
};
return Wallet;
}; };
module.defineClass(ClassSpec);
function Wallet(cfg) {
if (typeof cfg !== 'object')
cfg = {};
// deep copy (no references)
if (cfg.datastore)
this.datastore = JSON.parse(JSON.stringify(cfg.datastore));
else
this.datastore = JSON.parse(JSON.stringify(skeleton));
this.network = undefined;
this.dirty = cfg.dirty || true;
};
Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename);
this.dirty = false;
};
Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp";
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
this.datastore);
fs.renameSync(tmp_fn, filename);
this.dirty = false;
};
Wallet.prototype.setNetwork = function(netname) {
if (!netname)
netname = this.datastore.network;
switch (netname) {
case "mainnet":
case "livenet":
this.network = networks.livenet;
break;
case "testnet":
this.network = networks.testnet;
break;
default:
throw new Error("Unsupported network");
}
// store+canonicalize name
this.datastore['network'] = this.network.name;
this.dirty = true;
};
Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey);
this.dirty = true;
};
Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true;
};
Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString();
for (var i = 0; i < this.datastore.keys.length; i++) {
var obj = this.datastore.keys[i];
var addrStr = obj.addr;
var addr = new Address(addrStr);
if (addr.payload().toString() == pkhStr)
return obj;
}
return undefined;
};
Wallet.prototype.expandKey = function(key) {
var addr = new Address(key);
var isAddr = true;
try {
addr.validate();
var b = addr.payload();
var obj = this.findKeyHash(b);
key = obj.pub;
} catch(e) {
// do nothing
}
var re = /^[a-fA-F0-9]+$/;
if (!key.match(re))
throw new Error("Unknown key type");
return hex(key);
};
Wallet.prototype.expandKeys = function(keys) {
var res = [];
var us = this;
keys.forEach(function(key) {
var expKey = us.expandKey(key);
res.push(expKey);
});
return res;
};
Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer();
var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash);
var addrStr = addr.as('base58');
this.datastore.scripts[addrStr] = buf.toString('hex');
this.dirty = true;
return addrStr;
};
module.exports = require('soop')(Wallet);

View File

@ -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() {
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(),
};
return obj;
};
WalletKey.prototype.fromObj = function(obj) {
this.created = obj.created;
this.privKey = new KeyModule.Key();
if (obj.priv.length==64) {
this.privKey.private = new Buffer(obj.priv,'hex');
this.privKey.compressed = true;
}
else {
var priv = new PrivateKey(obj.priv);
this.privKey.private = new Buffer(priv.payload());
this.privKey.compressed = priv.compressed();
}
this.privKey.regenerateSync();
};
return WalletKey;
}; };
module.defineClass(ClassSpec);
WalletKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
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(),
};
return obj;
};
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.exports = require('soop')(WalletKey);

View File

@ -3,25 +3,27 @@
*/ */
module.exports.bignum = require('bignum'); module.exports.bignum = require('bignum');
module.exports.base58 = require('base58-native'); module.exports.base58 = require('base58-native');
module.exports.buffertools = require('buffertools'); module.exports.buffertools = require('buffertools');
module.exports.config = require('./config'); module.exports.config = require('./config');
module.exports.const = require('./const'); module.exports.const = require('./const');
module.exports.Deserialize = require('./Deserialize'); module.exports.Deserialize = require('./Deserialize');
module.exports.log = require('./util/log'); module.exports.log = require('./util/log');
module.exports.networks = require('./networks'); module.exports.networks = require('./networks');
module.exports.util = require('./util/util'); module.exports.util = require('./util/util');
module.exports.EncodedData = require('./util/EncodedData'); module.exports.EncodedData = require('./util/EncodedData');
module.exports.VersionedData = require('./util/VersionedData'); module.exports.VersionedData = require('./util/VersionedData');
module.exports.Address = require('./Address'); module.exports.Address = require('./Address');
module.exports.Opcode = require('./Opcode'); module.exports.Opcode = require('./Opcode');
module.exports.Script = require('./Script'); module.exports.Script = require('./Script');
module.exports.Transaction = require('./Transaction'); module.exports.Transaction = require('./Transaction');
module.exports.Peer = require('./Peer');
module.exports.PeerManager = require('./PeerManager');
module.exports.Block = require('./Block');
module.exports.Connection = require('./Connection'); module.exports.Connection = require('./Connection');
module.exports.Peer = require('./Peer');
module.exports.Block = require('./Block');
module.exports.ScriptInterpreter = require('./ScriptInterpreter'); module.exports.ScriptInterpreter = require('./ScriptInterpreter');
module.exports.Bloom = require('./Bloom'); module.exports.Bloom = require('./Bloom');
module.exports.KeyModule = require('./Key'); module.exports.KeyModule = require('./Key');
@ -34,6 +36,14 @@ module.exports.WalletKey = require('./WalletKey');
module.exports.Buffer = Buffer; module.exports.Buffer = Buffer;
if (typeof process.versions === 'undefined') { if (typeof process.versions === 'undefined') {
// Browser specific
module.exports.bignum.config({EXPONENTIAL_AT: 9999999, DECIMAL_PLACES: 0, ROUNDING_MODE: 1}); module.exports.bignum.config({EXPONENTIAL_AT: 9999999, DECIMAL_PLACES: 0, ROUNDING_MODE: 1});
// module.exports.PeerManager = function () {
// throw new Error('PeerManager not availabe in browser Bitcore, under .bitcore. Use it with: require(\'PeerManager\');');
// };
}
else {
// Nodejs specific
module.exports.PeerManager = require('./PeerManager');
} }

6
browser/bignum_config.js Normal file
View File

@ -0,0 +1,6 @@
require('bignum').config({
EXPONENTIAL_AT: 9999999,
DECIMAL_PLACES: 0,
ROUNDING_MODE: 1,
});

88
browserify.js Normal file
View File

@ -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);

View File

@ -2,7 +2,7 @@
// Replace '..' with 'bitcore' if you plan on using this code elsewhere. // Replace '..' with 'bitcore' if you plan on using this code elsewhere.
var Address = require('../Address').class(); var Address = require('../Address');
var addrStrings = [ var addrStrings = [
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",

View File

@ -4,10 +4,9 @@
var util = require('util'); var util = require('util');
var networks = require('../networks'); var networks = require('../networks');
var Peer = require('../Peer').class(); var Peer = require('../Peer');
var PeerManager = require('../PeerManager').createClass({ var PeerManager = require('soop').load('../PeerManager',
network: networks.testnet {network: networks.testnet});
});
var handleBlock = function(info) { var handleBlock = function(info) {

View File

@ -3,7 +3,7 @@
// Replace '..' with 'bitcore' if you plan on using this code elsewhere. // Replace '..' with 'bitcore' if you plan on using this code elsewhere.
var util = require('util'); var util = require('util');
var RpcClient = require('../RpcClient').class(); var RpcClient = require('../RpcClient');
var hash = process.argv[2] || '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4'; var hash = process.argv[2] || '0000000000b6288775bbd326bedf324ca8717a15191da58391535408205aada4';
var config = { var config = {

View File

@ -2,14 +2,13 @@
// Replace '..' with 'bitcore' if you plan on using this code elsewhere. // Replace '..' with 'bitcore' if you plan on using this code elsewhere.
var networks = require('../networks'); var networks = require('../networks');
var Peer = require('../Peer').class(); var Peer = require('../Peer');
var Transaction = require('../Transaction').class(); var Transaction = require('../Transaction');
var Address = require('../Address').class(); var Address = require('../Address');
var Script = require('../Script').class(); var Script = require('../Script');
var coinUtil = require('../util/util'); var coinUtil = require('../util/util');
var PeerManager = require('../PeerManager').createClass({ var PeerManager = require('soop').load('../PeerManager',
network: networks.testnet {network: networks.testnet});
});
var createTx = function() { var createTx = function() {

View File

@ -6,18 +6,19 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head> </head>
<body> <body>
<div id='content'></div> <pre>
<div id='content'></div>
</pre>
<script src="../browser/bundle.js"></script> <script src="../browser/bundle.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var Address = require('Address');
print = function(s){ print = function(s){
var div = document.getElementById('content'); var div = document.getElementById('content');
div.innerHTML += s + '<br />'; div.innerHTML += s + '<br />';
}; };
var Address = bitcore.Address.class();
var addrStrings = [ var addrStrings = [
"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa", "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
"1A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx", "1A1zP1eP5QGefi2DMPTfTL5SLmv7Dixxxx",
@ -37,15 +38,33 @@
} }
}); });
print('<hr>');
var Key = require('KeyModule').Key;
var Key = bitcore.KeyModule.Key; var buffertools = require('buffertools');
var k = Key.generateSync(); var k = Key.generateSync();
print ('Generated Key Pair:'); print ('Generate Key Pair:');
print ('Private:' + bitcore.buffertools.toHex(k.private)); print ('Private:' + buffertools.toHex(k.private));
print ('Public:' + bitcore.buffertools.toHex(k.public)); print ('Public:' + buffertools.toHex(k.public));
print('<hr>');
/*
Using bitcore root module
*/
var bitcore = require('bitcore');
var k = bitcore.KeyModule.Key.generateSync();
print ('Generate Key Pair:');
print ('Private:' + buffertools.toHex(k.private));
print ('Public:' + buffertools.toHex(k.public));
print('<hr>');
console.log('[example.html.65:PeerManager:]'); //TODO
var pm = require('PeerManager');
</script> </script>
</body> </body>

View File

@ -44,7 +44,7 @@
"test": "mocha test -R spec" "test": "mocha test -R spec"
}, },
"dependencies": { "dependencies": {
"classtool": "git://github.com/bitpay/classtool.git", "soop": "git://github.com/matiu/node-soop.git#feature/browser-support",
"base58-native": "=0.1.3", "base58-native": "=0.1.3",
"bindings": "=1.1.1", "bindings": "=1.1.1",
"bufferput": "git://github.com/bitpay/node-bufferput.git", "bufferput": "git://github.com/bitpay/node-bufferput.git",
@ -57,7 +57,8 @@
"devDependencies": { "devDependencies": {
"grunt-contrib-watch": "~0.5.3", "grunt-contrib-watch": "~0.5.3",
"grunt-mocha-test": "~0.8.2", "grunt-mocha-test": "~0.8.2",
"grunt-browserify": "~1.3.0", "grunt-shell": "~0.6.4",
"browser-pack": "*",
"grunt-markdown": "~0.5.0", "grunt-markdown": "~0.5.0",
"mocha": ">=1.15.1", "mocha": ">=1.15.1",
"browserify-bignum": "git://github.com/maraoz/browserify-bignum.git", "browserify-bignum": "git://github.com/maraoz/browserify-bignum.git",

View File

@ -13,7 +13,14 @@
<script>mocha.setup('bdd')</script> <script>mocha.setup('bdd')</script>
<script src="../browser/bundle.js"></script> <script src="../browser/bundle.js"></script>
<script src="../browser/testdata.js"></script> <script src="../browser/testdata.js"></script>
<script src="adapter.js"></script>
<script>
var bitcore = require('bitcore');
this.Buffer = require('buffer').Buffer;
</script>
<!-- <script src="adapter.js"></script> -->
<script src="test.Address.js"></script> <script src="test.Address.js"></script>
<script src="test.basic.js"></script> <script src="test.basic.js"></script>

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('Address', function() {
should.exist(AddressModule); should.exist(AddressModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Address = AddressModule.class(); Address = AddressModule;
should.exist(Address); should.exist(Address);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
var BlockModule = bitcore.Block; var BlockModule = bitcore.Block;
@ -12,7 +12,7 @@ describe('Block', function() {
should.exist(BlockModule); should.exist(BlockModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Block = BlockModule.class(); Block = BlockModule;
should.exist(Block); should.exist(Block);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('Bloom', function() {
should.exist(BloomModule); should.exist(BloomModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Bloom = BloomModule.class(); Bloom = BloomModule;
should.exist(Bloom); should.exist(Bloom);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -14,7 +14,7 @@ describe('Connection', function() {
should.exist(ConnectionModule); should.exist(ConnectionModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Connection = ConnectionModule.class(); Connection = ConnectionModule;
should.exist(Connection); should.exist(Connection);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('EncodedData', function() {
should.exist(EncodedDataModule); should.exist(EncodedDataModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
EncodedData = EncodedDataModule.class(); EncodedData = EncodedDataModule;
should.exist(EncodedData); should.exist(EncodedData);
}); });
it('should be able to create an instance', function() { it('should be able to create an instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var buffertools = require('buffertools'); var buffertools = require('buffertools');

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('Opcode', function() {
should.exist(OpcodeModule); should.exist(OpcodeModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Opcode = OpcodeModule.class(); Opcode = OpcodeModule;
should.exist(Opcode); should.exist(Opcode);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('Peer', function() {
should.exist(PeerModule); should.exist(PeerModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Peer = PeerModule.class(); Peer = PeerModule;
should.exist(Peer); should.exist(Peer);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,11 +1,12 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
var PeerManagerModule = bitcore.PeerManager; var PeerManagerModule = bitcore.PeerManager || require('PeerManager');
var PeerManager; var PeerManager;
describe('PeerManager', function() { describe('PeerManager', function() {
@ -13,7 +14,7 @@ describe('PeerManager', function() {
should.exist(PeerManagerModule); should.exist(PeerManagerModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
PeerManager = PeerManagerModule.class(); PeerManager = PeerManagerModule;
should.exist(PeerManager); should.exist(PeerManager);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -15,7 +15,7 @@ describe('PrivateKey', function() {
should.exist(PrivateKeyModule); should.exist(PrivateKeyModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
PrivateKey = PrivateKeyModule.class(); PrivateKey = PrivateKeyModule;
should.exist(PrivateKey); should.exist(PrivateKey);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,13 +1,13 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
var RpcClientModule = bitcore.RpcClient; var RpcClientModule = bitcore.RpcClient;
var RpcClient; var RpcClient;
RpcClient = RpcClientModule.class(); RpcClient = RpcClientModule;
describe('RpcClient', function() { describe('RpcClient', function() {
it('should initialze the main object', function() { it('should initialze the main object', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('SIN', function() {
should.exist(SINModule); should.exist(SINModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
SIN = SINModule.class(); SIN = SINModule;
should.exist(SIN); should.exist(SIN);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,10 +1,7 @@
'use strict'; 'use strict';
var chai = chai || require('chai');
var bitcore = bitcore || require('../bitcore');
var chai = require('chai');
var bitcore = require('../bitcore');
var should = chai.should(); var should = chai.should();
var SINKeyModule = bitcore.SINKey; var SINKeyModule = bitcore.SINKey;
@ -16,7 +13,7 @@ describe('SINKey', function() {
should.exist(SINKeyModule); should.exist(SINKeyModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
SINKey = SINKeyModule.class(); SINKey = SINKeyModule;
should.exist(SINKey); should.exist(SINKey);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,12 +1,12 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
var ScriptModule = bitcore.Script; var ScriptModule = bitcore.Script;
var Address = bitcore.Address.class(); var Address = bitcore.Address;
var networks = bitcore.networks; var networks = bitcore.networks;
var Script; var Script;
var test_data = require('./testdata'); var test_data = require('./testdata');
@ -16,7 +16,7 @@ describe('Script', function() {
should.exist(ScriptModule); should.exist(ScriptModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Script = ScriptModule.class(); Script = ScriptModule;
should.exist(Script); should.exist(Script);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('ScriptInterpreter', function() {
should.exist(ScriptInterpreterModule); should.exist(ScriptInterpreterModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
ScriptInterpreter = ScriptInterpreterModule.class(); ScriptInterpreter = ScriptInterpreterModule;
should.exist(ScriptInterpreter); should.exist(ScriptInterpreter);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -9,7 +9,7 @@ var TransactionModule = bitcore.Transaction;
var Transaction; var Transaction;
var In; var In;
var Out; var Out;
var Script = bitcore.Script.class(); var Script = bitcore.Script;
var buffertools = require('buffertools'); var buffertools = require('buffertools');
var test_data = require('./testdata'); var test_data = require('./testdata');
@ -18,7 +18,7 @@ describe('Transaction', function() {
should.exist(TransactionModule); should.exist(TransactionModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Transaction = TransactionModule.class(); Transaction = TransactionModule;
should.exist(Transaction); should.exist(Transaction);
In = Transaction.In; In = Transaction.In;
Out = Transaction.Out; Out = Transaction.Out;

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('VersionedData', function() {
should.exist(VersionedDataModule); should.exist(VersionedDataModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
VersionedData = VersionedDataModule.class(); VersionedData = VersionedDataModule;
should.exist(VersionedData); should.exist(VersionedData);
}); });
it('should be able to create an instance', function() { it('should be able to create an instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -13,7 +13,7 @@ describe('Wallet', function() {
should.exist(WalletModule); should.exist(WalletModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
Wallet = WalletModule.class(); Wallet = WalletModule;
should.exist(Wallet); should.exist(Wallet);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();
@ -14,7 +14,7 @@ describe('WalletKey', function() {
should.exist(WalletKeyModule); should.exist(WalletKeyModule);
}); });
it('should be able to create class', function() { it('should be able to create class', function() {
WalletKey = WalletKeyModule.class(); WalletKey = WalletKeyModule;
should.exist(WalletKey); should.exist(WalletKey);
}); });
it('should be able to create instance', function() { it('should be able to create instance', function() {

View File

@ -1,15 +1,27 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var test_data;
if (typeof dataValid !== 'undefined' ) {
test_data = {
dataValid: dataValid,
dataInvalid: dataInvalid,
};
}
else {
test_data = require('./testdata');
}
var should = chai.should(); var should = chai.should();
var Address = bitcore.Address.class(); var Address = bitcore.Address;
var PrivateKey = bitcore.PrivateKey.class(); var PrivateKey = bitcore.PrivateKey;
var networks = bitcore.networks; var networks = bitcore.networks;
var KeyModule = bitcore.KeyModule; var KeyModule = bitcore.KeyModule;
var test_data = require('./testdata');
function test_encode_priv(b58, payload, isTestnet, isCompressed) { function test_encode_priv(b58, payload, isTestnet, isCompressed) {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var expect = chai.expect; var expect = chai.expect;
var should = chai.should(); var should = chai.should();

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
var chai = require('chai'); var chai = chai || require('chai');
var bitcore = require('../bitcore'); var bitcore = bitcore || require('../bitcore');
var should = chai.should(); var should = chai.should();

View File

@ -1,5 +1,6 @@
var chai = require('chai');
var bitcore = require('../bitcore'); var chai = chai || require('chai');
var bitcore = bitcore || require('../bitcore');
var coinUtil = bitcore.util; var coinUtil = bitcore.util;
var should = chai.should(); var should = chai.should();
var buffertools = require('buffertools'); var buffertools = require('buffertools');

View File

@ -1,5 +1,3 @@
var fs = require('fs'); var fs = require('fs');
var dataValid = JSON.parse(fs.readFileSync('test/data/base58_keys_valid.json')); var dataValid = JSON.parse(fs.readFileSync('test/data/base58_keys_valid.json'));

View File

@ -2,147 +2,145 @@
* Simple synchronous parser based on node-binary. * Simple synchronous parser based on node-binary.
*/ */
function spec(b) { var imports = require('soop').imports();
function Parser(buffer) function Parser(buffer)
{ {
this.subject = buffer; this.subject = buffer;
this.pos = 0; this.pos = 0;
};
Parser.prototype.buffer = function buffer(len) {
var buf = this.subject.slice(this.pos, this.pos+len);
this.pos += len;
return buf;
};
Parser.prototype.search = function search(needle) {
var len;
if ("string" === typeof needle || Buffer.isBuffer(needle)) {
// TODO: Slicing is probably too slow
len = this.subject.slice(this.pos).indexOf(needle);
if (len !== -1) {
this.pos += len + needle.length;
}
return len;
}
if ("number" === typeof needle) {
needle = needle & 0xff;
// Search for single byte
for (var i = this.pos, l = this.subject.length; i < l; i++) {
if (this.subject[i] == needle) {
len = i - this.pos;
this.pos = i+1;
return len;
}
}
return -1;
}
};
/**
* Like search(), but returns the skipped bytes
*/
Parser.prototype.scan = function scan(needle) {
var startPos = this.pos;
var len = this.search(needle);
if (len !== -1) {
return this.subject.slice(startPos, startPos+len);
} else {
throw new Error('No match');
}
};
Parser.prototype.eof = function eof() {
return this.pos >= this.subject.length;
};
// convert byte strings to unsigned little endian numbers
function decodeLEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256,i) * bytes[i];
}
return acc;
}
// convert byte strings to unsigned big endian numbers
function decodeBEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
}
return acc;
}
// convert byte strings to signed big endian numbers
function decodeBEs (bytes) {
var val = decodeBEu(bytes);
if ((bytes[0] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
// convert byte strings to signed little endian numbers
function decodeLEs (bytes) {
var val = decodeLEu(bytes);
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
function getDecoder(len, fn) {
return function () {
var buf = this.buffer(len);
return fn(buf);
};
};
[ 1, 2, 4, 8 ].forEach(function (bytes) {
var bits = bytes * 8;
Parser.prototype['word' + bits + 'le']
= Parser.prototype['word' + bits + 'lu']
= getDecoder(bytes, decodeLEu);
Parser.prototype['word' + bits + 'ls']
= getDecoder(bytes, decodeLEs);
Parser.prototype['word' + bits + 'be']
= Parser.prototype['word' + bits + 'bu']
= getDecoder(bytes, decodeBEu);
Parser.prototype['word' + bits + 'bs']
= getDecoder(bytes, decodeBEs);
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
Parser.prototype.word8s = Parser.prototype.word8bs;
});
Parser.prototype.varInt = function ()
{
var firstByte = this.word8();
switch (firstByte) {
case 0xFD:
return this.word16le();
case 0xFE:
return this.word32le();
case 0xFF:
return this.word64le();
default:
return firstByte;
}
};
Parser.prototype.varStr = function () {
var len = this.varInt();
return this.buffer(len);
};
return Parser;
}; };
module.defineClass(spec);
Parser.prototype.buffer = function buffer(len) {
var buf = this.subject.slice(this.pos, this.pos+len);
this.pos += len;
return buf;
};
Parser.prototype.search = function search(needle) {
var len;
if ("string" === typeof needle || Buffer.isBuffer(needle)) {
// TODO: Slicing is probably too slow
len = this.subject.slice(this.pos).indexOf(needle);
if (len !== -1) {
this.pos += len + needle.length;
}
return len;
}
if ("number" === typeof needle) {
needle = needle & 0xff;
// Search for single byte
for (var i = this.pos, l = this.subject.length; i < l; i++) {
if (this.subject[i] == needle) {
len = i - this.pos;
this.pos = i+1;
return len;
}
}
return -1;
}
};
/**
* Like search(), but returns the skipped bytes
*/
Parser.prototype.scan = function scan(needle) {
var startPos = this.pos;
var len = this.search(needle);
if (len !== -1) {
return this.subject.slice(startPos, startPos+len);
} else {
throw new Error('No match');
}
};
Parser.prototype.eof = function eof() {
return this.pos >= this.subject.length;
};
// convert byte strings to unsigned little endian numbers
function decodeLEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256,i) * bytes[i];
}
return acc;
}
// convert byte strings to unsigned big endian numbers
function decodeBEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
}
return acc;
}
// convert byte strings to signed big endian numbers
function decodeBEs (bytes) {
var val = decodeBEu(bytes);
if ((bytes[0] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
// convert byte strings to signed little endian numbers
function decodeLEs (bytes) {
var val = decodeLEu(bytes);
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
function getDecoder(len, fn) {
return function () {
var buf = this.buffer(len);
return fn(buf);
};
};
[ 1, 2, 4, 8 ].forEach(function (bytes) {
var bits = bytes * 8;
Parser.prototype['word' + bits + 'le']
= Parser.prototype['word' + bits + 'lu']
= getDecoder(bytes, decodeLEu);
Parser.prototype['word' + bits + 'ls']
= getDecoder(bytes, decodeLEs);
Parser.prototype['word' + bits + 'be']
= Parser.prototype['word' + bits + 'bu']
= getDecoder(bytes, decodeBEu);
Parser.prototype['word' + bits + 'bs']
= getDecoder(bytes, decodeBEs);
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
Parser.prototype.word8s = Parser.prototype.word8bs;
});
Parser.prototype.varInt = function ()
{
var firstByte = this.word8();
switch (firstByte) {
case 0xFD:
return this.word16le();
case 0xFE:
return this.word32le();
case 0xFF:
return this.word64le();
default:
return firstByte;
}
};
Parser.prototype.varStr = function () {
var len = this.varInt();
return this.buffer(len);
};
module.exports = require('soop')(Parser);

View File

@ -1,159 +1,158 @@
require('classtool'); var imports = require('soop').imports();
var base58 = imports.base58 || require('base58-native').base58Check;
function ClassSpec(b) {
var base58 = b.base58 || require('base58-native').base58Check;
// Constructor. Takes the following forms: // Constructor. Takes the following forms:
// new EncodedData(<base58_address_string>) // new EncodedData(<base58_address_string>)
// new EncodedData(<binary_buffer>) // new EncodedData(<binary_buffer>)
// new EncodedData(<data>, <encoding>) // new EncodedData(<data>, <encoding>)
// new EncodedData(<version>, <20-byte-hash>) // new EncodedData(<version>, <20-byte-hash>)
function EncodedData(data, encoding) { function EncodedData(data, encoding) {
this.data = data; this.data = data;
if(!encoding && (typeof data == 'string')) { if(!encoding && (typeof data == 'string')) {
this.__proto__ = this.encodings['base58']; this.__proto__ = this.encodings['base58'];
} else { } else {
this.__proto__ = this.encodings[encoding || 'binary']; this.__proto__ = this.encodings[encoding || 'binary'];
}
};
// get or set the encoding used (transforms data)
EncodedData.prototype.encoding = function(encoding) {
if(encoding && (encoding != this._encoding)) {
this.data = this.as(encoding);
this.__proto__ = this.encodings[encoding];
}
return this._encoding;
};
// answer a new instance having the given encoding
EncodedData.prototype.withEncoding = function(encoding) {
return new EncodedData(this.as(encoding), encoding);
};
// answer the data in the given encoding
EncodedData.prototype.as = function(encoding) {
if(!encodings[encoding]) throw new Error('invalid encoding');
return this.converters[encoding].call(this);
};
// validate that we can convert to binary
EncodedData.prototype._validate = function() {
this.withEncoding('binary');
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
// subclasses can override to do more stuff
EncodedData.prototype.validate = function() {
this._validate();
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
// convert to a string (in base58 form)
EncodedData.prototype.toString = function() {
return this.as('base58');
};
// utility
EncodedData.prototype.doAsBinary = function(callback) {
var oldEncoding = this.encoding();
this.encoding('binary');
callback.apply(this);
this.encoding(oldEncoding);
};
// Setup support for various address encodings. The object for
// each encoding inherits from the EncodedData prototype. This
// allows any encoding to override any method...changing the encoding
// for an instance will change the encoding it inherits from. Note,
// this will present some problems for anyone wanting to inherit from
// EncodedData (we'll deal with that when needed).
var encodings = {
'binary': {
converters: {
'binary': function() {
var answer = new Buffer(this.data.length);
this.data.copy(answer);
return answer;
},
'base58': function() {
return base58.encode(this.data);
},
'hex': function() {
return this.data.toString('hex');
},
},
_validate: function() {
//nothing to do here...we make no assumptions about the data
},
},
'base58': {
converters: {
'binary': function() {
return base58.decode(this.data);
},
'hex': function() {
return this.withEncoding('binary').as('hex');
},
},
},
'hex': {
converters: {
'binary': function() {
return new Buffer(this.data, 'hex');
},
'base58': function() {
return this.withEncoding('binary').as('base58');
},
},
},
};
var no_conversion = function() {return this.data;};
for(var k in encodings) {
if(encodings.hasOwnProperty(k)){
if(!encodings[k].converters[k])
encodings[k].converters[k] = no_conversion;
encodings[k]._encoding = k;
}
} }
};
EncodedData.applyEncodingsTo = function(aClass) { // get or set the encoding used (transforms data)
var tmp = {}; EncodedData.prototype.encoding = function(encoding) {
for(var k in encodings) { if(encoding && (encoding != this._encoding)) {
var enc = encodings[k]; this.data = this.as(encoding);
var obj = {}; this.__proto__ = this.encodings[encoding];
for(var j in enc) { }
obj[j] = enc[j]; return this._encoding;
} };
obj.__proto__ = aClass.prototype;
tmp[k] = obj;
}
aClass.prototype.encodings = tmp;
};
EncodedData.applyEncodingsTo(EncodedData); // answer a new instance having the given encoding
return EncodedData; EncodedData.prototype.withEncoding = function(encoding) {
return new EncodedData(this.as(encoding), encoding);
};
// answer the data in the given encoding
EncodedData.prototype.as = function(encoding) {
if(!encodings[encoding]) throw new Error('invalid encoding');
return this.converters[encoding].call(this);
};
// validate that we can convert to binary
EncodedData.prototype._validate = function() {
this.withEncoding('binary');
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
// subclasses can override to do more stuff
EncodedData.prototype.validate = function() {
this._validate();
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
// convert to a string (in base58 form)
EncodedData.prototype.toString = function() {
return this.as('base58');
};
// utility
EncodedData.prototype.doAsBinary = function(callback) {
var oldEncoding = this.encoding();
this.encoding('binary');
callback.apply(this);
this.encoding(oldEncoding);
};
// Setup support for various address encodings. The object for
// each encoding inherits from the EncodedData prototype. This
// allows any encoding to override any method...changing the encoding
// for an instance will change the encoding it inherits from. Note,
// this will present some problems for anyone wanting to inherit from
// EncodedData (we'll deal with that when needed).
var encodings = {
'binary': {
converters: {
'binary': function() {
var answer = new Buffer(this.data.length);
this.data.copy(answer);
return answer;
},
'base58': function() {
return base58.encode(this.data);
},
'hex': function() {
return this.data.toString('hex');
},
},
_validate: function() {
//nothing to do here...we make no assumptions about the data
},
},
'base58': {
converters: {
'binary': function() {
return base58.decode(this.data);
},
'hex': function() {
return this.withEncoding('binary').as('hex');
},
},
},
'hex': {
converters: {
'binary': function() {
return new Buffer(this.data, 'hex');
},
'base58': function() {
return this.withEncoding('binary').as('base58');
},
},
},
};
var no_conversion = function() {return this.data;};
for(var k in encodings) {
if(encodings.hasOwnProperty(k)){
if(!encodings[k].converters[k])
encodings[k].converters[k] = no_conversion;
encodings[k]._encoding = k;
}
} }
module.defineClass(ClassSpec);
EncodedData.applyEncodingsTo = function(aClass) {
var tmp = {};
for(var k in encodings) {
var enc = encodings[k];
var obj = {};
for(var j in enc) {
obj[j] = enc[j];
}
obj.__proto__ = aClass.prototype;
tmp[k] = obj;
}
aClass.prototype.encodings = tmp;
};
EncodedData.applyEncodingsTo(EncodedData);
module.exports = require('soop')(EncodedData);

View File

@ -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);
// get or set the version data (the first byte of the address) this.payload(payload);
VersionedData.prototype.version = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
// 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);
};
return VersionedData;
}; };
module.defineClass(ClassSpec);
VersionedData.parent = parent;
parent.applyEncodingsTo(VersionedData);
// get or set the version data (the first byte of the address)
VersionedData.prototype.version = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
// 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.exports = require('soop')(VersionedData);