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

193
Block.js
View File

@ -1,25 +1,24 @@
require('classtool'); var imports = require('soop').imports();
function spec(b) { var util = imports.util || require('./util/util');
var util = b.util || require('./util/util'); var Debug1 = imports.Debug1 || function() {};
var Debug1 = b.Debug1 || function() {}; var Script = imports.Script || require('./Script');
var Script = b.Script || require('./Script').class(); var Bignum = imports.Bignum || require('bignum');
var Bignum = b.Bignum || require('bignum'); var Binary = imports.Binary || require('binary');
var Binary = b.Binary || require('binary'); var Step = imports.Step || require('step');
var Step = b.Step || require('step'); var buffertools = imports.buffertools || require('buffertools');
var buffertools = b.buffertools || require('buffertools'); var Transaction = imports.Transaction || require('./Transaction');
var Transaction = b.Transaction || require('./Transaction').class(); var TransactionIn = Transaction.In;
var TransactionIn = Transaction.In; var TransactionOut = Transaction.Out;
var TransactionOut = Transaction.Out; var COINBASE_OP = Transaction.COINBASE_OP;
var COINBASE_OP = Transaction.COINBASE_OP; var VerificationError = imports.VerificationError || require('./util/error').VerificationError;
var VerificationError = b.VerificationError || require('./util/error').VerificationError; var BlockRules = {
var BlockRules = {
maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future
largestHash: Bignum(2).pow(256) largestHash: Bignum(2).pow(256)
}; };
function Block(data) function Block(data)
{ {
if ("object" !== typeof data) { if ("object" !== typeof data) {
data = {}; data = {};
} }
@ -35,9 +34,9 @@ function spec(b) {
this.active = data.active || false; this.active = data.active || false;
this.chainWork = data.chainWork || util.EMPTY_BUFFER; this.chainWork = data.chainWork || util.EMPTY_BUFFER;
this.txs = data.txs || []; this.txs = data.txs || [];
} }
Block.prototype.getHeader = function getHeader() { Block.prototype.getHeader = function getHeader() {
var buf = new Buffer(80); var buf = new Buffer(80);
var ofs = 0; var ofs = 0;
buf.writeUInt32LE(this.version, ofs); ofs += 4; buf.writeUInt32LE(this.version, ofs); ofs += 4;
@ -47,9 +46,9 @@ function spec(b) {
buf.writeUInt32LE(this.bits, ofs); ofs += 4; buf.writeUInt32LE(this.bits, ofs); ofs += 4;
buf.writeUInt32LE(this.nonce, ofs); ofs += 4; buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
return buf; return buf;
}; };
Block.prototype.parse = function parse(parser, headerOnly) { Block.prototype.parse = function parse(parser, headerOnly) {
this.version = parser.word32le(); this.version = parser.word32le();
this.prev_hash = parser.buffer(32); this.prev_hash = parser.buffer(32);
this.merkle_root = parser.buffer(32); this.merkle_root = parser.buffer(32);
@ -70,26 +69,26 @@ function spec(b) {
tx.parse(parser); tx.parse(parser);
this.txs.push(tx); this.txs.push(tx);
} }
}; };
Block.prototype.calcHash = function calcHash() { Block.prototype.calcHash = function calcHash() {
var header = this.getHeader(); var header = this.getHeader();
return util.twoSha256(header); return util.twoSha256(header);
}; };
Block.prototype.checkHash = function checkHash() { Block.prototype.checkHash = function checkHash() {
if (!this.hash || !this.hash.length) return false; if (!this.hash || !this.hash.length) return false;
return buffertools.compare(this.calcHash(), this.hash) == 0; return buffertools.compare(this.calcHash(), this.hash) == 0;
}; };
Block.prototype.getHash = function getHash() { Block.prototype.getHash = function getHash() {
if (!this.hash || !this.hash.length) this.hash = this.calcHash(); if (!this.hash || !this.hash.length) this.hash = this.calcHash();
return this.hash; return this.hash;
}; };
Block.prototype.checkProofOfWork = function checkProofOfWork() { Block.prototype.checkProofOfWork = function checkProofOfWork() {
var target = util.decodeDiffBits(this.bits); var target = util.decodeDiffBits(this.bits);
// TODO: Create a compare method in node-buffertools that uses the correct // TODO: Create a compare method in node-buffertools that uses the correct
@ -104,30 +103,30 @@ function spec(b) {
buffertools.reverse(this.hash); buffertools.reverse(this.hash);
return true; return true;
}; };
/** /**
* Returns the amount of work that went into this block. * Returns the amount of work that went into this block.
* *
* Work is defined as the average number of tries required to meet this * Work is defined as the average number of tries required to meet this
* block's difficulty target. For example a target that is greater than 5% * block's difficulty target. For example a target that is greater than 5%
* of all possible hashes would mean that 20 "work" is required to meet it. * of all possible hashes would mean that 20 "work" is required to meet it.
*/ */
Block.prototype.getWork = function getWork() { Block.prototype.getWork = function getWork() {
var target = util.decodeDiffBits(this.bits, true); var target = util.decodeDiffBits(this.bits, true);
return BlockRules.largestHash.div(target.add(1)); return BlockRules.largestHash.div(target.add(1));
}; };
Block.prototype.checkTimestamp = function checkTimestamp() { Block.prototype.checkTimestamp = function checkTimestamp() {
var currentTime = new Date().getTime() / 1000; var currentTime = new Date().getTime() / 1000;
if (this.timestamp > currentTime + BlockRules.maxTimeOffset) { if (this.timestamp > currentTime + BlockRules.maxTimeOffset) {
throw new VerificationError('Timestamp too far into the future'); throw new VerificationError('Timestamp too far into the future');
} }
return true; return true;
}; };
Block.prototype.checkTransactions = function checkTransactions(txs) { Block.prototype.checkTransactions = function checkTransactions(txs) {
if (!Array.isArray(txs) || txs.length <= 0) { if (!Array.isArray(txs) || txs.length <= 0) {
throw new VerificationError('No transactions'); throw new VerificationError('No transactions');
} }
@ -141,15 +140,15 @@ function spec(b) {
} }
return true; return true;
}; };
/** /**
* Build merkle tree. * Build merkle tree.
* *
* Ported from Java. Original code: BitcoinJ by Mike Hearn * Ported from Java. Original code: BitcoinJ by Mike Hearn
* Copyright (c) 2011 Google Inc. * Copyright (c) 2011 Google Inc.
*/ */
Block.prototype.getMerkleTree = function getMerkleTree(txs) { Block.prototype.getMerkleTree = function getMerkleTree(txs) {
// The merkle hash is based on a tree of hashes calculated from the transactions: // The merkle hash is based on a tree of hashes calculated from the transactions:
// //
// merkleHash // merkleHash
@ -188,14 +187,14 @@ function spec(b) {
} }
return tree; return tree;
}; };
Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) { Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) {
var tree = this.getMerkleTree(txs); var tree = this.getMerkleTree(txs);
return tree[tree.length - 1]; return tree[tree.length - 1];
}; };
Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) { Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) {
if (!this.merkle_root || !this.merkle_root.length) { if (!this.merkle_root || !this.merkle_root.length) {
throw new VerificationError('No merkle root'); throw new VerificationError('No merkle root');
} }
@ -205,9 +204,9 @@ function spec(b) {
} }
return true; return true;
}; };
Block.prototype.checkBlock = function checkBlock(txs) { Block.prototype.checkBlock = function checkBlock(txs) {
if (!this.checkHash()) { if (!this.checkHash()) {
throw new VerificationError("Block hash invalid"); throw new VerificationError("Block hash invalid");
} }
@ -221,31 +220,31 @@ function spec(b) {
} }
} }
return true; return true;
}; };
Block.getBlockValue = function getBlockValue(height) { Block.getBlockValue = function getBlockValue(height) {
var subsidy = Bignum(50).mul(util.COIN); var subsidy = Bignum(50).mul(util.COIN);
subsidy = subsidy.div(Bignum(2).pow(Math.floor(height / 210000))); subsidy = subsidy.div(Bignum(2).pow(Math.floor(height / 210000)));
return subsidy; return subsidy;
}; };
Block.prototype.getBlockValue = function getBlockValue() { Block.prototype.getBlockValue = function getBlockValue() {
return Block.getBlockValue(this.height); return Block.getBlockValue(this.height);
}; };
Block.prototype.toString = function toString() { Block.prototype.toString = function toString() {
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">"; return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
}; };
/** /**
* Initializes some properties based on information from the parent block. * Initializes some properties based on information from the parent block.
*/ */
Block.prototype.attachTo = function attachTo(parent) { Block.prototype.attachTo = function attachTo(parent) {
this.height = parent.height + 1; this.height = parent.height + 1;
this.setChainWork(parent.getChainWork().add(this.getWork())); this.setChainWork(parent.getChainWork().add(this.getWork()));
}; };
Block.prototype.setChainWork = function setChainWork(chainWork) { Block.prototype.setChainWork = function setChainWork(chainWork) {
if (Buffer.isBuffer(chainWork)) { if (Buffer.isBuffer(chainWork)) {
// Nothing to do // Nothing to do
} else if ("function" === typeof chainWork.toBuffer) { // duck-typing bignum } else if ("function" === typeof chainWork.toBuffer) { // duck-typing bignum
@ -255,24 +254,24 @@ function spec(b) {
} }
this.chainWork = chainWork; this.chainWork = chainWork;
}; };
Block.prototype.getChainWork = function getChainWork() { Block.prototype.getChainWork = function getChainWork() {
return Bignum.fromBuffer(this.chainWork); return Bignum.fromBuffer(this.chainWork);
}; };
/** /**
* Compares the chainWork of two blocks. * Compares the chainWork of two blocks.
*/ */
Block.prototype.moreWorkThan = function moreWorkThan(otherBlock) { Block.prototype.moreWorkThan = function moreWorkThan(otherBlock) {
return this.getChainWork().cmp(otherBlock.getChainWork()) > 0; return this.getChainWork().cmp(otherBlock.getChainWork()) > 0;
}; };
/** /**
* Returns the difficulty target for the next block after this one. * Returns the difficulty target for the next block after this one.
*/ */
Block.prototype.getNextWork = Block.prototype.getNextWork =
function getNextWork(blockChain, nextBlock, callback) { function getNextWork(blockChain, nextBlock, callback) {
var self = this; var self = this;
var powLimit = blockChain.getMinDiff(); var powLimit = blockChain.getMinDiff();
@ -371,13 +370,13 @@ function spec(b) {
} }
); );
} }
}; };
var medianTimeSpan = 11; var medianTimeSpan = 11;
Block.prototype.getMedianTimePast = Block.prototype.getMedianTimePast =
function getMedianTimePast(blockChain, callback) function getMedianTimePast(blockChain, callback)
{ {
var self = this; var self = this;
Step( Step(
@ -407,11 +406,11 @@ function spec(b) {
}, },
callback callback
); );
}; };
Block.prototype.verifyChild = Block.prototype.verifyChild =
function verifyChild(blockChain, child, callback) function verifyChild(blockChain, child, callback)
{ {
var self = this; var self = this;
Step( Step(
@ -444,11 +443,11 @@ function spec(b) {
}, },
callback callback
); );
}; };
Block.prototype.createCoinbaseTx = Block.prototype.createCoinbaseTx =
function createCoinbaseTx(beneficiary) function createCoinbaseTx(beneficiary)
{ {
var tx = new Transaction(); var tx = new Transaction();
tx.ins.push(new TransactionIn({ tx.ins.push(new TransactionIn({
s: util.EMPTY_BUFFER, s: util.EMPTY_BUFFER,
@ -460,11 +459,11 @@ function spec(b) {
s: Script.createPubKeyOut(beneficiary).getBuffer() s: Script.createPubKeyOut(beneficiary).getBuffer()
})); }));
return tx; return tx;
}; };
Block.prototype.prepareNextBlock = Block.prototype.prepareNextBlock =
function prepareNextBlock(blockChain, beneficiary, time, callback) function prepareNextBlock(blockChain, beneficiary, time, callback)
{ {
var self = this; var self = this;
var newBlock = new Block(); var newBlock = new Block();
@ -512,11 +511,11 @@ function spec(b) {
}, },
callback callback
); );
}; };
Block.prototype.mineNextBlock = Block.prototype.mineNextBlock =
function mineNextBlock(blockChain, beneficiary, time, miner, callback) function mineNextBlock(blockChain, beneficiary, time, miner, callback)
{ {
this.prepareNextBlock(blockChain, beneficiary, time, function (err, data) { this.prepareNextBlock(blockChain, beneficiary, time, function (err, data) {
try { try {
if (err) throw err; if (err) throw err;
@ -539,20 +538,20 @@ function spec(b) {
callback(e); callback(e);
} }
}); });
}; };
Block.prototype.solve = function solve(miner, callback) { Block.prototype.solve = function solve(miner, callback) {
var header = this.getHeader(); var header = this.getHeader();
var target = util.decodeDiffBits(this.bits); var target = util.decodeDiffBits(this.bits);
miner.solve(header, target, callback); miner.solve(header, target, callback);
}; };
/** /**
* Returns an object with the same field names as jgarzik's getblock patch. * Returns an object with the same field names as jgarzik's getblock patch.
*/ */
Block.prototype.getStandardizedObject = Block.prototype.getStandardizedObject =
function getStandardizedObject(txs) function getStandardizedObject(txs)
{ {
var block = { var block = {
hash: util.formatHashFull(this.getHash()), hash: util.formatHashFull(this.getHash()),
version: this.version, version: this.version,
@ -587,8 +586,6 @@ function spec(b) {
block.size = this.size; block.size = this.size;
} }
return block; return block;
};
return Block;
}; };
module.defineClass(spec);
module.exports = require('soop')(Block);

View File

@ -1,31 +1,28 @@
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
var MAX_HASH_FUNCS = 50;
var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455;
var LN2 = 0.6931471805599453094172321214581765680755001343602552;
var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80];
function Bloom() {
this.data = ''; this.data = '';
this.hashFuncs = 0; this.hashFuncs = 0;
}; };
function ROTL32(x, r) { function ROTL32(x, r) {
return (x << r) | (x >> (32 - r)); return (x << r) | (x >> (32 - r));
}; };
function getBlockU32(blockIdx, data) { function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4; var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) | var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) | (data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) | (data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8)); (data[idx + 3] << (3 * 8));
return v; return v;
}; };
Bloom.prototype.hash = function(hashNum, data) { Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51; var c1 = 0xcc9e2d51;
var c2 = 0x1b873593; var c2 = 0x1b873593;
@ -68,16 +65,16 @@ function ClassSpec(b) {
h1 ^= h1 >> 16; h1 ^= h1 >> 16;
return h1 % (this.data.length * 8); return h1 % (this.data.length * 8);
}; };
Bloom.prototype.insert = function(data) { Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) { for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data); var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index]; this.data[index >> 3] |= bit_mask[7 & index];
} }
}; };
Bloom.prototype.contains = function(data) { Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) { for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data); var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index])) if (!(this.data[index >> 3] & bit_mask[7 & index]))
@ -85,32 +82,30 @@ function ClassSpec(b) {
} }
return true; return true;
}; };
Bloom.prototype.sizeOk = function() { Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE && return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS; this.hashFuncs <= MAX_HASH_FUNCS;
}; };
function toInt(v) { function toInt(v) {
return ~~v; return ~~v;
} }
function min(a, b) { function min(a, b) {
if (a < b) if (a < b)
return a; return a;
return b; return b;
} }
Bloom.prototype.init = function(elements, FPRate) { Bloom.prototype.init = function(elements, FPRate) {
var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)),
MAX_BLOOM_FILTER_SIZE * 8) / 8; MAX_BLOOM_FILTER_SIZE * 8) / 8;
this.data[filterSize] = 0; this.data[filterSize] = 0;
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
MAX_HASH_FUNCS); MAX_HASH_FUNCS);
};
return Bloom;
}; };
module.defineClass(ClassSpec);
module.exports = require('soop')(Bloom);

View File

@ -1,29 +1,28 @@
require('classtool'); var imports = require('soop').imports();
function spec(b) { var config = imports.config || require('./config');
var config = b.config || require('./config'); var log = imports.log || require('./util/log');
var log = b.log || require('./util/log'); var network = imports.network || require('./networks')[config.network];
var network = b.network || require('./networks')[config.network];
var MAX_RECEIVE_BUFFER = 10000000; var MAX_RECEIVE_BUFFER = 10000000;
var PROTOCOL_VERSION = 70000; var PROTOCOL_VERSION = 70000;
var Binary = b.Binary || require('binary'); var Binary = imports.Binary || require('binary');
var Put = b.Put || require('bufferput'); var Put = imports.Put || require('bufferput');
var Buffers = b.Buffers || require('buffers'); var Buffers = imports.Buffers || require('buffers');
require('./Buffers.monkey').patch(Buffers); require('./Buffers.monkey').patch(Buffers);
var noop = function() {};
var Block = require('./Block').class();
var Transaction = require('./Transaction').class();
var util = b.util || require('./util/util');
var Parser = b.Parser || require('./util/BinaryParser').class();
var buffertools = b.buffertools || require('buffertools');
var doubleSha256 = b.doubleSha256 || util.twoSha256;
var nonce = util.generateNonce();
var BIP0031_VERSION = 60000; var Block = require('./Block');
var Transaction = require('./Transaction');
var util = imports.util || require('./util/util');
var Parser = imports.Parser || require('./util/BinaryParser');
var buffertools = imports.buffertools || require('buffertools');
var doubleSha256 = imports.doubleSha256 || util.twoSha256;
var nonce = util.generateNonce();
function Connection(socket, peer) { var BIP0031_VERSION = 60000;
function Connection(socket, peer) {
Connection.super(this, arguments); Connection.super(this, arguments);
this.socket = socket; this.socket = socket;
this.peer = peer; this.peer = peer;
@ -52,10 +51,10 @@ function spec(b) {
} }
this.setupHandlers(); this.setupHandlers();
} }
Connection.superclass = b.superclass || require('events').EventEmitter; Connection.parent = imports.parent || require('events').EventEmitter;
Connection.prototype.setupHandlers = function () { Connection.prototype.setupHandlers = function () {
this.socket.addListener('connect', this.handleConnect.bind(this)); this.socket.addListener('connect', this.handleConnect.bind(this));
this.socket.addListener('error', this.handleError.bind(this)); this.socket.addListener('error', this.handleError.bind(this));
this.socket.addListener('end', this.handleDisconnect.bind(this)); this.socket.addListener('end', this.handleDisconnect.bind(this));
@ -68,9 +67,9 @@ function spec(b) {
(data.length > dumpLen ? '...' : '')); (data.length > dumpLen ? '...' : ''));
}).bind(this)); }).bind(this));
this.socket.addListener('data', this.handleData.bind(this)); this.socket.addListener('data', this.handleData.bind(this));
}; };
Connection.prototype.handleConnect = function () { Connection.prototype.handleConnect = function () {
if (!this.inbound) { if (!this.inbound) {
this.sendVersion(); this.sendVersion();
} }
@ -79,9 +78,9 @@ function spec(b) {
socket: this.socket, socket: this.socket,
peer: this.peer peer: this.peer
}); });
}; };
Connection.prototype.handleError = function(err) { Connection.prototype.handleError = function(err) {
if (err.errno == 110 || err.errno == 'ETIMEDOUT') { if (err.errno == 110 || err.errno == 'ETIMEDOUT') {
log.info('connection timed out for '+this.peer); log.info('connection timed out for '+this.peer);
} else if (err.errno == 111 || err.errno == 'ECONNREFUSED') { } else if (err.errno == 111 || err.errno == 'ECONNREFUSED') {
@ -95,17 +94,17 @@ function spec(b) {
peer: this.peer, peer: this.peer,
err: err err: err
}); });
}; };
Connection.prototype.handleDisconnect = function () { Connection.prototype.handleDisconnect = function () {
this.emit('disconnect', { this.emit('disconnect', {
conn: this, conn: this,
socket: this.socket, socket: this.socket,
peer: this.peer peer: this.peer
}); });
}; };
Connection.prototype.handleMessage = function(message) { Connection.prototype.handleMessage = function(message) {
if (!message) { if (!message) {
// Parser was unable to make sense of the message, drop it // Parser was unable to make sense of the message, drop it
return; return;
@ -163,13 +162,13 @@ function spec(b) {
peer: this.peer, peer: this.peer,
message: message message: message
}); });
}; };
Connection.prototype.sendPong = function (nonce) { Connection.prototype.sendPong = function (nonce) {
this.sendMessage('pong', nonce); this.sendMessage('pong', nonce);
}; };
Connection.prototype.sendVersion = function () { Connection.prototype.sendVersion = function () {
var subversion = '/BitcoinX:0.1/'; var subversion = '/BitcoinX:0.1/';
var put = new Put(); var put = new Put();
@ -184,9 +183,9 @@ function spec(b) {
put.word32le(0); put.word32le(0);
this.sendMessage('version', put.buffer()); this.sendMessage('version', put.buffer());
}; };
Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) { Connection.prototype.sendGetBlocks = function (starts, stop, wantHeaders) {
var put = new Put(); var put = new Put();
put.word32le(this.sendVer); put.word32le(this.sendVer);
@ -210,13 +209,13 @@ function spec(b) {
if (wantHeaders) if (wantHeaders)
command = 'getheaders'; command = 'getheaders';
this.sendMessage(command, put.buffer()); this.sendMessage(command, put.buffer());
}; };
Connection.prototype.sendGetHeaders = function(starts, stop) { Connection.prototype.sendGetHeaders = function(starts, stop) {
this.sendGetBlocks(starts, stop, true); this.sendGetBlocks(starts, stop, true);
}; };
Connection.prototype.sendGetData = function (invs) { Connection.prototype.sendGetData = function (invs) {
var put = new Put(); var put = new Put();
put.varint(invs.length); put.varint(invs.length);
for (var i = 0; i < invs.length; i++) { for (var i = 0; i < invs.length; i++) {
@ -224,14 +223,14 @@ function spec(b) {
put.put(invs[i].hash); put.put(invs[i].hash);
} }
this.sendMessage('getdata', put.buffer()); this.sendMessage('getdata', put.buffer());
}; };
Connection.prototype.sendGetAddr = function (invs) { Connection.prototype.sendGetAddr = function (invs) {
var put = new Put(); var put = new Put();
this.sendMessage('getaddr', put.buffer()); this.sendMessage('getaddr', put.buffer());
}; };
Connection.prototype.sendInv = function(data) { Connection.prototype.sendInv = function(data) {
if(!Array.isArray(data)) data = [data]; if(!Array.isArray(data)) data = [data];
var put = new Put(); var put = new Put();
put.varint(data.length); put.varint(data.length);
@ -246,9 +245,9 @@ function spec(b) {
put.put(value.getHash()); put.put(value.getHash());
}); });
this.sendMessage('inv', put.buffer()); this.sendMessage('inv', put.buffer());
}; };
Connection.prototype.sendHeaders = function (headers) { Connection.prototype.sendHeaders = function (headers) {
var put = new Put(); var put = new Put();
put.varint(headers.length); put.varint(headers.length);
headers.forEach(function (header) { headers.forEach(function (header) {
@ -258,13 +257,13 @@ function spec(b) {
put.word8(0); put.word8(0);
}); });
this.sendMessage('headers', put.buffer()); this.sendMessage('headers', put.buffer());
}; };
Connection.prototype.sendTx = function (tx) { Connection.prototype.sendTx = function (tx) {
this.sendMessage('tx', tx.serialize()); this.sendMessage('tx', tx.serialize());
}; };
Connection.prototype.sendBlock = function (block, txs) { Connection.prototype.sendBlock = function (block, txs) {
var put = new Put(); var put = new Put();
// Block header // Block header
@ -277,9 +276,9 @@ function spec(b) {
}); });
this.sendMessage('block', put.buffer()); this.sendMessage('block', put.buffer());
}; };
Connection.prototype.sendMessage = function (command, payload) { Connection.prototype.sendMessage = function (command, payload) {
try { try {
var magic = network.magic; var magic = network.magic;
var commandBuf = new Buffer(command, 'ascii'); var commandBuf = new Buffer(command, 'ascii');
@ -313,9 +312,9 @@ function spec(b) {
log.err("Error while sending message to peer "+this.peer+": "+ log.err("Error while sending message to peer "+this.peer+": "+
(err.stack ? err.stack : err.toString())); (err.stack ? err.stack : err.toString()));
} }
}; };
Connection.prototype.handleData = function (data) { Connection.prototype.handleData = function (data) {
this.buffers.push(data); this.buffers.push(data);
if (this.buffers.length > MAX_RECEIVE_BUFFER) { if (this.buffers.length > MAX_RECEIVE_BUFFER) {
@ -326,9 +325,9 @@ function spec(b) {
} }
this.processData(); this.processData();
}; };
Connection.prototype.processData = function () { Connection.prototype.processData = function () {
// If there are less than 20 bytes there can't be a message yet. // If there are less than 20 bytes there can't be a message yet.
if (this.buffers.length < 20) return; if (this.buffers.length < 20) return;
@ -402,9 +401,9 @@ function spec(b) {
this.buffers.skip(endPos); this.buffers.skip(endPos);
this.processData(); this.processData();
}; };
Connection.prototype.parseMessage = function (command, payload) { Connection.prototype.parseMessage = function (command, payload) {
var parser = new Parser(payload); var parser = new Parser(payload);
var data = { var data = {
@ -444,8 +443,8 @@ function spec(b) {
data.headers = []; data.headers = [];
for (i = 0; i < data.count; i++) { for (i = 0; i < data.count; i++) {
var header = new Block(); var header = new Block();
header.parse(parser); header.parse(parser);
data.headers.push(header); data.headers.push(header);
} }
break; break;
@ -540,8 +539,6 @@ function spec(b) {
} }
return data; return data;
};
return Connection;
}; };
module.defineClass(spec);
module.exports = require('soop')(Connection);

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({
shell: {
browserify: { browserify: {
client: {
src: ['bitcore.js'],
dest: 'browser/bundle.js',
options: { options: {
debug: true, stdout: true
alias: [
'browserify-bignum/bignumber.js:bignum',
'browserify-buffertools/buffertools.js:buffertools'
],
standalone: 'bitcore',
}
}, },
command: 'node ./browserify.js > browser/bundle.js',
},
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: {

View File

@ -1,15 +1,14 @@
require('classtool'); var imports = require('soop').imports();
function spec(b) { function Opcode(num) {
function Opcode(num) {
this.code = num; this.code = num;
}; };
Opcode.prototype.toString = function () { Opcode.prototype.toString = function () {
return Opcode.reverseMap[this.code]; return Opcode.reverseMap[this.code];
}; };
Opcode.map = { Opcode.map = {
// push value // push value
OP_FALSE : 0, OP_FALSE : 0,
OP_0 : 0, OP_0 : 0,
@ -146,16 +145,14 @@ function spec(b) {
OP_PUBKEYHASH : 253, OP_PUBKEYHASH : 253,
OP_PUBKEY : 254, OP_PUBKEY : 254,
OP_INVALIDOPCODE : 255 OP_INVALIDOPCODE : 255
}; };
Opcode.reverseMap = []; Opcode.reverseMap = [];
for (var k in Opcode.map) { for (var k in Opcode.map) {
if(Opcode.map.hasOwnProperty(k)) { if(Opcode.map.hasOwnProperty(k)) {
Opcode.reverseMap[Opcode.map[k]] = k.substr(3); Opcode.reverseMap[Opcode.map[k]] = k.substr(3);
} }
} }
return Opcode; module.exports = require('soop')(Opcode);
};
module.defineClass(spec);

35
Peer.js
View File

@ -1,11 +1,10 @@
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(':');
@ -30,32 +29,30 @@ function spec(b) {
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.IPV6_IPV4_PADDING = new Buffer([0,0,0,0,0,0,0,0,0,0,255,255]);
Peer.prototype.createConnection = function () { Peer.prototype.createConnection = function () {
var c = Net.createConnection(this.port, this.host); var c = Net.createConnection(this.port, this.host);
return c; return c;
}; };
Peer.prototype.getHostAsBuffer = function () { Peer.prototype.getHostAsBuffer = function () {
return new Buffer(this.host.split('.')); return new Buffer(this.host.split('.'));
}; };
Peer.prototype.toString = function () { Peer.prototype.toString = function () {
return this.host + ":" + this.port; return this.host + ":" + this.port;
}; };
Peer.prototype.toBuffer = function () { Peer.prototype.toBuffer = function () {
var put = Binary.put(); var put = Binary.put();
put.word32le(this.lastSeen); put.word32le(this.lastSeen);
put.word64le(this.services); put.word64le(this.services);
put.put(this.getHostAsBuffer()); put.put(this.getHostAsBuffer());
put.word16be(this.port); put.word16be(this.port);
return put.buffer(); return put.buffer();
};
return Peer;
}; };
module.defineClass(spec);
module.exports = require('soop')(Peer);

View File

@ -1,20 +1,21 @@
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 ||
require('soop').load('Connection', {config: config, network: network}) ||
require ('./Connection');
var Peer = imports.Peer || require('./Peer');
GetAdjustedTime = imports.GetAdjustedTime || function () {
// TODO: Implement actual adjustment // TODO: Implement actual adjustment
return Math.floor(new Date().getTime() / 1000); return Math.floor(new Date().getTime() / 1000);
}; };
function PeerManager() { function PeerManager() {
this.active = false; this.active = false;
this.timer = null; this.timer = null;
@ -27,19 +28,19 @@ function spec(b) {
this.interval = 5000; this.interval = 5000;
this.minConnections = 8; this.minConnections = 8;
this.minKnownPeers = 10; this.minKnownPeers = 10;
}; };
PeerManager.superclass = b.superclass || require('events').EventEmitter;
PeerManager.Connection = Connection; PeerManager.parent = imports.parent || require('events').EventEmitter;
PeerManager.Connection = Connection;
PeerManager.prototype.start = function() { PeerManager.prototype.start = function() {
this.active = true; this.active = true;
if(!this.timer) { if(!this.timer) {
this.timer = setInterval(this.checkStatus.bind(this), this.interval); this.timer = setInterval(this.checkStatus.bind(this), this.interval);
} }
}; };
PeerManager.prototype.stop = function() { PeerManager.prototype.stop = function() {
this.active = false; this.active = false;
if(this.timer) { if(this.timer) {
clearInterval(this.timer); clearInterval(this.timer);
@ -48,9 +49,9 @@ function spec(b) {
for(var i=0; i<this.connections.length; i++) { for(var i=0; i<this.connections.length; i++) {
this.connections[i].socket.end(); this.connections[i].socket.end();
}; };
}; };
PeerManager.prototype.addPeer = function(peer, port) { PeerManager.prototype.addPeer = function(peer, port) {
if(peer instanceof Peer) { if(peer instanceof Peer) {
this.peers.push(peer); this.peers.push(peer);
} else if ("string" == typeof peer) { } else if ("string" == typeof peer) {
@ -60,9 +61,9 @@ function spec(b) {
{val: peer}); {val: peer});
throw 'Node.addPeer(): Invalid value provided for peer.'; throw 'Node.addPeer(): Invalid value provided for peer.';
} }
}; };
PeerManager.prototype.checkStatus = function checkStatus() { PeerManager.prototype.checkStatus = function checkStatus() {
// Make sure we are connected to all forcePeers // Make sure we are connected to all forcePeers
if(this.peers.length) { if(this.peers.length) {
var peerIndex = {}; var peerIndex = {};
@ -82,9 +83,9 @@ function spec(b) {
this.connectTo(peerIndex[i]); this.connectTo(peerIndex[i]);
}.bind(this)); }.bind(this));
} }
}; };
PeerManager.prototype.connectTo = function(peer) { PeerManager.prototype.connectTo = function(peer) {
log.info('connecting to '+peer); log.info('connecting to '+peer);
try { try {
return this.addConnection(peer.createConnection(), peer); return this.addConnection(peer.createConnection(), peer);
@ -92,9 +93,9 @@ function spec(b) {
log.err('creating connection',e); log.err('creating connection',e);
return null; return null;
} }
}; };
PeerManager.prototype.addConnection = function(socketConn, peer) { PeerManager.prototype.addConnection = function(socketConn, peer) {
var conn = new Connection(socketConn, peer); var conn = new Connection(socketConn, peer);
this.connections.push(conn); this.connections.push(conn);
this.emit('connection', conn); this.emit('connection', conn);
@ -107,9 +108,9 @@ function spec(b) {
conn.addListener('disconnect', this.handleDisconnect.bind(this)); conn.addListener('disconnect', this.handleDisconnect.bind(this));
return conn; return conn;
}; };
PeerManager.prototype.handleVersion = function(e) { PeerManager.prototype.handleVersion = function(e) {
if (!e.conn.inbound) { if (!e.conn.inbound) {
// TODO: Advertise our address (if listening) // TODO: Advertise our address (if listening)
} }
@ -119,9 +120,9 @@ function spec(b) {
e.conn.sendGetAddr(); e.conn.sendGetAddr();
e.conn.getaddr = true; e.conn.getaddr = true;
} }
}; };
PeerManager.prototype.handleReady = function (e) { PeerManager.prototype.handleReady = function (e) {
log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port); log.info('connected to '+e.conn.peer.host+':'+e.conn.peer.port);
this.emit('connect', { this.emit('connect', {
pm: this, pm: this,
@ -134,9 +135,9 @@ function spec(b) {
this.emit('netConnected'); this.emit('netConnected');
this.isConnected = true; this.isConnected = true;
} }
}; };
PeerManager.prototype.handleAddr = function (e) { PeerManager.prototype.handleAddr = function (e) {
if(!this.peerDiscovery) return; if(!this.peerDiscovery) return;
var now = GetAdjustedTime(); var now = GetAdjustedTime();
@ -160,18 +161,18 @@ function spec(b) {
if (e.message.addrs.length < 1000 ) { if (e.message.addrs.length < 1000 ) {
e.conn.getaddr = false; e.conn.getaddr = false;
} }
}; };
PeerManager.prototype.handleGetAddr = function(e) { PeerManager.prototype.handleGetAddr = function(e) {
// TODO: Reply with addr message. // TODO: Reply with addr message.
}; };
PeerManager.prototype.handleError = function(e) { PeerManager.prototype.handleError = function(e) {
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err); log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
this.handleDisconnect.apply(this, [].slice.call(arguments)); this.handleDisconnect.apply(this, [].slice.call(arguments));
}; };
PeerManager.prototype.handleDisconnect = function(e) { PeerManager.prototype.handleDisconnect = function(e) {
log.info('disconnected from peer '+e.peer); log.info('disconnected from peer '+e.peer);
var i = this.connections.indexOf(e.conn); var i = this.connections.indexOf(e.conn);
if(i != -1) this.connections.splice(i, 1); if(i != -1) this.connections.splice(i, 1);
@ -180,9 +181,9 @@ function spec(b) {
this.emit('netDisconnected'); this.emit('netDisconnected');
this.isConnected = false; this.isConnected = false;
} }
}; };
PeerManager.prototype.getActiveConnection = function () { PeerManager.prototype.getActiveConnection = function () {
var activeConnections = this.connections.filter(function (conn) { var activeConnections = this.connections.filter(function (conn) {
return conn.active; return conn.active;
}); });
@ -204,12 +205,10 @@ function spec(b) {
} else { } else {
return null; return null;
} }
};
PeerManager.prototype.getActiveConnections = function () {
return this.connections.slice(0);
};
return PeerManager;
}; };
module.defineClass(spec);
PeerManager.prototype.getActiveConnections = function () {
return this.connections.slice(0);
};
module.exports = require('soop')(PeerManager);

View File

@ -1,29 +1,28 @@
require('classtool'); var imports = require('soop').imports();
function ClassSpec(b) { var parent = imports.parent || require('./util/VersionedData');
var superclass = b.superclass || require('./util/VersionedData').class();
//compressed is true if public key is compressed; false otherwise //compressed is true if public key is compressed; false otherwise
function PrivateKey(version, buf, compressed) { function PrivateKey(version, buf, compressed) {
PrivateKey.super(this, arguments); PrivateKey.super(this, arguments);
if (compressed !== undefined) if (compressed !== undefined)
this.compressed(compressed); this.compressed(compressed);
}; };
PrivateKey.superclass = superclass; PrivateKey.parent = parent;
superclass.applyEncodingsTo(PrivateKey); parent.applyEncodingsTo(PrivateKey);
PrivateKey.prototype.validate = function() { PrivateKey.prototype.validate = function() {
this.doAsBinary(function() { this.doAsBinary(function() {
PrivateKey.super(this, 'validate', arguments); PrivateKey.super(this, 'validate', arguments);
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1) if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
throw new Error('invalid data length'); throw new Error('invalid data length');
}); });
}; };
// get or set the payload data (as a Buffer object) // get or set the payload data (as a Buffer object)
// overloaded from VersionedData // overloaded from VersionedData
PrivateKey.prototype.payload = function(data) { PrivateKey.prototype.payload = function(data) {
if(data) { if(data) {
this.doAsBinary(function() {data.copy(this.data,1);}); this.doAsBinary(function() {data.copy(this.data,1);});
return data; return data;
@ -33,10 +32,10 @@ function ClassSpec(b) {
return buf.slice(1,1+32); return buf.slice(1,1+32);
else if (buf.length==1+32) else if (buf.length==1+32)
return buf.slice(1); return buf.slice(1);
}; };
// get or set whether the corresponding public key is compressed // get or set whether the corresponding public key is compressed
PrivateKey.prototype.compressed = function(compressed) { PrivateKey.prototype.compressed = function(compressed) {
if (compressed !== undefined) { if (compressed !== undefined) {
this.doAsBinary(function(){ this.doAsBinary(function(){
var len=1+32+1; var len=1+32+1;
@ -60,8 +59,6 @@ function ClassSpec(b) {
else else
throw new Error('invalid private key'); throw new Error('invalid private key');
} }
};
return PrivateKey;
}; };
module.defineClass(ClassSpec);
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,14 +1,13 @@
// 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');
var https = b.https || require('https');
var log = b.log || require('./util/log');
function RpcClient(opts) {
opts = opts || {}; opts = opts || {};
this.host = opts.host || '127.0.0.1'; this.host = opts.host || '127.0.0.1';
this.port = opts.port || 8332; this.port = opts.port || 8332;
@ -17,16 +16,16 @@ function ClassSpec(b) {
this.protocol = (opts.protocol == 'http') ? http : https; this.protocol = (opts.protocol == 'http') ? http : https;
this.batchedCalls = null; this.batchedCalls = null;
this.disableAgent = opts.disableAgent || false; this.disableAgent = opts.disableAgent || false;
} }
RpcClient.prototype.batch = function(batchCallback, resultCallback) { RpcClient.prototype.batch = function(batchCallback, resultCallback) {
this.batchedCalls = []; this.batchedCalls = [];
batchCallback(); batchCallback();
rpc.call(this, this.batchedCalls, resultCallback); rpc.call(this, this.batchedCalls, resultCallback);
this.batchedCalls = null; this.batchedCalls = null;
} }
var callspec = { var callspec = {
addMultiSigAddress: '', addMultiSigAddress: '',
addNode: '', addNode: '',
backupWallet: '', backupWallet: '',
@ -93,13 +92,13 @@ function ClassSpec(b) {
walletLock: '', walletLock: '',
walletPassPhrase: 'string int', walletPassPhrase: 'string int',
walletPassphraseChange: '', walletPassphraseChange: '',
}; };
var slice = function(arr, start, end) { var slice = function(arr, start, end) {
return Array.prototype.slice.call(arr, start, end); return Array.prototype.slice.call(arr, start, end);
}; };
function generateRPCMethods(constructor, apiCalls, rpc) { function generateRPCMethods(constructor, apiCalls, rpc) {
function createRPCMethod(methodName, argMap) { function createRPCMethod(methodName, argMap) {
return function() { return function() {
var limit = arguments.length - 1; var limit = arguments.length - 1;
@ -137,9 +136,9 @@ function ClassSpec(b) {
constructor.prototype[methodName] = constructor.prototype[k]; constructor.prototype[methodName] = constructor.prototype[k];
} }
} }
} }
function rpc(request, callback) { function rpc(request, callback) {
var self = this; var self = this;
var request; var request;
request = JSON.stringify(request); request = JSON.stringify(request);
@ -201,10 +200,9 @@ function ClassSpec(b) {
req.setHeader('Authorization', 'Basic ' + auth); req.setHeader('Authorization', 'Basic ' + auth);
req.write(request); req.write(request);
req.end(); req.end();
};
generateRPCMethods(RpcClient, callspec, rpc);
return RpcClient;
}; };
module.defineClass(ClassSpec);
generateRPCMethods(RpcClient, callspec, rpc);
module.exports = require('soop')(RpcClient);

45
SIN.js
View File

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

View File

@ -1,29 +1,26 @@
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');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var SIN = require('./SIN').class();
function SINKey(cfg) {
if (typeof cfg != 'object') if (typeof cfg != 'object')
cfg = {}; cfg = {};
this.created = cfg.created; this.created = cfg.created;
this.privKey = cfg.privKey; this.privKey = cfg.privKey;
}; };
SINKey.prototype.generate = function() { SINKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync(); this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime(); this.created = timeUtil.curtime();
}; };
SINKey.prototype.pubkeyHash = function() { SINKey.prototype.pubkeyHash = function() {
return coinUtil.sha256ripe160(this.privKey.public); return coinUtil.sha256ripe160(this.privKey.public);
}; };
SINKey.prototype.storeObj = function() { SINKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex'); var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = this.pubkeyHash(); var pubKeyHash = this.pubkeyHash();
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash); var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
@ -35,9 +32,6 @@ function ClassSpec(b) {
}; };
return obj; return obj;
};
return SINKey;
}; };
module.defineClass(ClassSpec);
module.exports = require('soop')(SINKey);

213
Script.js
View File

@ -1,36 +1,33 @@
require('classtool'); var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var Opcode = imports.Opcode || require('./Opcode');
var buffertools = imports.buffertools || require('buffertools');
function spec(b) { // Make opcodes available as pseudo-constants
var config = b.config || require('./config'); for (var i in Opcode.map) {
var log = b.log || require('./util/log');
var Opcode = b.Opcode || require('./Opcode').class();
var buffertools = b.buffertools || require('buffertools');
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval(i + " = " + Opcode.map[i] + ";"); eval(i + " = " + Opcode.map[i] + ";");
} }
var util = b.util || require('./util/util'); var util = imports.util || require('./util/util');
var Parser = b.Parser || require('./util/BinaryParser').class(); var Parser = imports.Parser || require('./util/BinaryParser');
var Put = b.Put || require('bufferput'); var Put = imports.Put || require('bufferput');
var TX_UNKNOWN = 0; var TX_UNKNOWN = 0;
var TX_PUBKEY = 1; var TX_PUBKEY = 1;
var TX_PUBKEYHASH = 2; var TX_PUBKEYHASH = 2;
var TX_MULTISIG = 3; var TX_MULTISIG = 3;
var TX_SCRIPTHASH = 4; var TX_SCRIPTHASH = 4;
var TX_TYPES = [ var TX_TYPES = [
'unknown', 'unknown',
'pubkey', 'pubkey',
'pubkeyhash', 'pubkeyhash',
'multisig', 'multisig',
'scripthash' 'scripthash'
]; ];
function Script(buffer) { function Script(buffer) {
if (buffer) { if (buffer) {
this.buffer = buffer; this.buffer = buffer;
} else { } else {
@ -38,16 +35,16 @@ function spec(b) {
} }
this.chunks = []; this.chunks = [];
this.parse(); this.parse();
}; };
this.class = Script; this.class = Script;
Script.TX_UNKNOWN = TX_UNKNOWN; Script.TX_UNKNOWN = TX_UNKNOWN;
Script.TX_PUBKEY = TX_PUBKEY; Script.TX_PUBKEY = TX_PUBKEY;
Script.TX_PUBKEYHASH = TX_PUBKEYHASH; Script.TX_PUBKEYHASH = TX_PUBKEYHASH;
Script.TX_MULTISIG = TX_MULTISIG; Script.TX_MULTISIG = TX_MULTISIG;
Script.TX_SCRIPTHASH = TX_SCRIPTHASH; Script.TX_SCRIPTHASH = TX_SCRIPTHASH;
Script.prototype.parse = function() { Script.prototype.parse = function() {
this.chunks = []; this.chunks = [];
var parser = new Parser(this.buffer); var parser = new Parser(this.buffer);
@ -71,31 +68,31 @@ function spec(b) {
this.chunks.push(opcode); this.chunks.push(opcode);
} }
} }
}; };
Script.prototype.isPushOnly = function() { Script.prototype.isPushOnly = function() {
for (var i = 0; i < this.chunks.length; i++) for (var i = 0; i < this.chunks.length; i++)
if (!Buffer.isBuffer(this.chunks[i])) if (!Buffer.isBuffer(this.chunks[i]))
return false; return false;
return true; return true;
}; };
Script.prototype.isP2SH = function() { Script.prototype.isP2SH = function() {
return (this.chunks.length == 3 && return (this.chunks.length == 3 &&
this.chunks[0] == OP_HASH160 && this.chunks[0] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[1]) && Buffer.isBuffer(this.chunks[1]) &&
this.chunks[1].length == 20 && this.chunks[1].length == 20 &&
this.chunks[2] == OP_EQUAL); this.chunks[2] == OP_EQUAL);
}; };
Script.prototype.isPubkey = function() { Script.prototype.isPubkey = function() {
return (this.chunks.length == 2 && return (this.chunks.length == 2 &&
Buffer.isBuffer(this.chunks[0]) && Buffer.isBuffer(this.chunks[0]) &&
this.chunks[1] == OP_CHECKSIG); this.chunks[1] == OP_CHECKSIG);
}; };
Script.prototype.isPubkeyHash = function() { Script.prototype.isPubkeyHash = function() {
return (this.chunks.length == 5 && return (this.chunks.length == 5 &&
this.chunks[0] == OP_DUP && this.chunks[0] == OP_DUP &&
this.chunks[1] == OP_HASH160 && this.chunks[1] == OP_HASH160 &&
@ -103,21 +100,21 @@ function spec(b) {
this.chunks[2].length == 20 && this.chunks[2].length == 20 &&
this.chunks[3] == OP_EQUALVERIFY && this.chunks[3] == OP_EQUALVERIFY &&
this.chunks[4] == OP_CHECKSIG); this.chunks[4] == OP_CHECKSIG);
}; };
function isSmallIntOp(opcode) { function isSmallIntOp(opcode) {
return ((opcode == OP_0) || return ((opcode == OP_0) ||
((opcode >= OP_1) && (opcode <= OP_16))); ((opcode >= OP_1) && (opcode <= OP_16)));
}; };
Script.prototype.isMultiSig = function() { Script.prototype.isMultiSig = function() {
return (this.chunks.length > 3 && return (this.chunks.length > 3 &&
isSmallIntOp(this.chunks[0]) && isSmallIntOp(this.chunks[0]) &&
isSmallIntOp(this.chunks[this.chunks.length - 2]) && isSmallIntOp(this.chunks[this.chunks.length - 2]) &&
this.chunks[this.chunks.length - 1] == OP_CHECKMULTISIG); this.chunks[this.chunks.length - 1] == OP_CHECKMULTISIG);
}; };
Script.prototype.finishedMultiSig = function() { Script.prototype.finishedMultiSig = function() {
var nsigs = 0; var nsigs = 0;
for (var i = 0; i < this.chunks.length - 1; i++) for (var i = 0; i < this.chunks.length - 1; i++)
if (this.chunks[i] !== 0) if (this.chunks[i] !== 0)
@ -131,9 +128,9 @@ function spec(b) {
return true; return true;
else else
return false; return false;
} }
Script.prototype.removePlaceHolders = function() { Script.prototype.removePlaceHolders = function() {
var chunks = []; var chunks = [];
for (var i in this.chunks) { for (var i in this.chunks) {
if (this.chunks.hasOwnProperty(i)) { if (this.chunks.hasOwnProperty(i)) {
@ -145,9 +142,9 @@ function spec(b) {
this.chunks = chunks; this.chunks = chunks;
this.updateBuffer(); this.updateBuffer();
return this; return this;
} }
Script.prototype.prependOp0 = function() { Script.prototype.prependOp0 = function() {
var chunks = [0]; var chunks = [0];
for (i in this.chunks) { for (i in this.chunks) {
if (this.chunks.hasOwnProperty(i)) { if (this.chunks.hasOwnProperty(i)) {
@ -157,10 +154,10 @@ function spec(b) {
this.chunks = chunks; this.chunks = chunks;
this.updateBuffer(); this.updateBuffer();
return this; return this;
} }
// is this a script form we know? // is this a script form we know?
Script.prototype.classify = function() { Script.prototype.classify = function() {
if (this.isPubkeyHash()) if (this.isPubkeyHash())
return TX_PUBKEYHASH; return TX_PUBKEYHASH;
if (this.isP2SH()) if (this.isP2SH())
@ -170,10 +167,10 @@ function spec(b) {
if (this.isPubkey()) if (this.isPubkey())
return TX_PUBKEY; return TX_PUBKEY;
return TX_UNKNOWN; return TX_UNKNOWN;
}; };
// extract useful data items from known scripts // extract useful data items from known scripts
Script.prototype.capture = function() { Script.prototype.capture = function() {
var txType = this.classify(); var txType = this.classify();
var res = []; var res = [];
switch (txType) { switch (txType) {
@ -198,15 +195,15 @@ function spec(b) {
} }
return res; return res;
}; };
// return first extracted data item from script // return first extracted data item from script
Script.prototype.captureOne = function() { Script.prototype.captureOne = function() {
var arr = this.capture(); var arr = this.capture();
return arr[0]; return arr[0];
}; };
Script.prototype.getOutType = function() { Script.prototype.getOutType = function() {
var txType = this.classify(); var txType = this.classify();
switch (txType) { switch (txType) {
case TX_PUBKEY: case TX_PUBKEY:
@ -216,13 +213,13 @@ function spec(b) {
default: default:
return 'Strange'; return 'Strange';
} }
}; };
Script.prototype.getRawOutType = function() { Script.prototype.getRawOutType = function() {
return TX_TYPES[this.classify()]; return TX_TYPES[this.classify()];
}; };
Script.prototype.simpleOutHash = function() { Script.prototype.simpleOutHash = function() {
switch (this.getOutType()) { switch (this.getOutType()) {
case 'Address': case 'Address':
return this.chunks[2]; return this.chunks[2];
@ -233,9 +230,9 @@ function spec(b) {
log.debug("Strange script was: " + this.toString()); log.debug("Strange script was: " + this.toString());
return null; return null;
} }
}; };
Script.prototype.getInType = function() { Script.prototype.getInType = function() {
if (this.chunks.length == 1) { if (this.chunks.length == 1) {
// Direct IP to IP transactions only have the public key in their scriptSig. // Direct IP to IP transactions only have the public key in their scriptSig.
return 'Pubkey'; return 'Pubkey';
@ -246,9 +243,9 @@ function spec(b) {
} else { } else {
return 'Strange'; return 'Strange';
} }
}; };
Script.prototype.simpleInPubKey = function() { Script.prototype.simpleInPubKey = function() {
switch (this.getInType()) { switch (this.getInType()) {
case 'Address': case 'Address':
return this.chunks[1]; return this.chunks[1];
@ -259,13 +256,13 @@ function spec(b) {
log.debug("Strange script was: " + this.toString()); log.debug("Strange script was: " + this.toString());
return null; return null;
} }
}; };
Script.prototype.getBuffer = function() { Script.prototype.getBuffer = function() {
return this.buffer; return this.buffer;
}; };
Script.fromStringContent = function(s) { Script.fromStringContent = function(s) {
var chunks = []; var chunks = [];
var split = s.split(' '); var split = s.split(' ');
for (var i = 0; i < split.length; i++) { for (var i = 0; i < split.length; i++) {
@ -287,9 +284,9 @@ function spec(b) {
} }
} }
return Script.fromChunks(chunks); return Script.fromChunks(chunks);
}; };
Script.prototype.getStringContent = function(truncate, maxEl) { Script.prototype.getStringContent = function(truncate, maxEl) {
if (truncate === null) { if (truncate === null) {
truncate = true; truncate = true;
} }
@ -318,17 +315,17 @@ function spec(b) {
} }
} }
return s; return s;
}; };
Script.prototype.toString = function(truncate, maxEl) { Script.prototype.toString = function(truncate, maxEl) {
var script = "<Script "; var script = "<Script ";
script += this.getStringContent(truncate, maxEl); script += this.getStringContent(truncate, maxEl);
script += ">"; script += ">";
return script; return script;
}; };
Script.prototype.writeOp = function(opcode) { Script.prototype.writeOp = function(opcode) {
var buf = Buffer(this.buffer.length + 1); var buf = Buffer(this.buffer.length + 1);
this.buffer.copy(buf); this.buffer.copy(buf);
buf.writeUInt8(opcode, this.buffer.length); buf.writeUInt8(opcode, this.buffer.length);
@ -336,9 +333,9 @@ function spec(b) {
this.buffer = buf; this.buffer = buf;
this.chunks.push(opcode); this.chunks.push(opcode);
}; };
Script.prototype.writeN = function(n) { Script.prototype.writeN = function(n) {
if (n < 0 || n > 16) if (n < 0 || n > 16)
throw new Error("writeN: out of range value " + n); throw new Error("writeN: out of range value " + n);
@ -346,9 +343,9 @@ function spec(b) {
this.writeOp(OP_0); this.writeOp(OP_0);
else else
this.writeOp(OP_1 + n - 1); this.writeOp(OP_1 + n - 1);
}; };
function prefixSize(data_length) { function prefixSize(data_length) {
if (data_length < OP_PUSHDATA1) { if (data_length < OP_PUSHDATA1) {
return 1; return 1;
} else if (data_length <= 0xff) { } else if (data_length <= 0xff) {
@ -358,9 +355,9 @@ function spec(b) {
} else { } else {
return 1 + 4; return 1 + 4;
} }
}; };
function encodeLen(data_length) { function encodeLen(data_length) {
var buf = undefined; var buf = undefined;
if (data_length < OP_PUSHDATA1) { if (data_length < OP_PUSHDATA1) {
buf = new Buffer(1); buf = new Buffer(1);
@ -380,19 +377,19 @@ function spec(b) {
} }
return buf; return buf;
}; };
Script.prototype.writeBytes = function(data) { Script.prototype.writeBytes = function(data) {
var newSize = this.buffer.length + prefixSize(data.length) + data.length; var newSize = this.buffer.length + prefixSize(data.length) + data.length;
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]); this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]);
this.chunks.push(data); this.chunks.push(data);
}; };
Script.prototype.updateBuffer = function() { Script.prototype.updateBuffer = function() {
this.buffer = Script.chunksToBuffer(this.chunks); this.buffer = Script.chunksToBuffer(this.chunks);
}; };
Script.prototype.findAndDelete = function(chunk) { Script.prototype.findAndDelete = function(chunk) {
var dirty = false; var dirty = false;
if (Buffer.isBuffer(chunk)) { if (Buffer.isBuffer(chunk)) {
for (var i = 0, l = this.chunks.length; i < l; i++) { for (var i = 0, l = this.chunks.length; i < l; i++) {
@ -415,25 +412,25 @@ function spec(b) {
if (dirty) { if (dirty) {
this.updateBuffer(); this.updateBuffer();
} }
}; };
/** /**
* Creates a simple OP_CHECKSIG with pubkey output script. * Creates a simple OP_CHECKSIG with pubkey output script.
* *
* These are used for coinbase transactions and at some point were used for * These are used for coinbase transactions and at some point were used for
* IP-based transactions as well. * IP-based transactions as well.
*/ */
Script.createPubKeyOut = function(pubkey) { Script.createPubKeyOut = function(pubkey) {
var script = new Script(); var script = new Script();
script.writeBytes(pubkey); script.writeBytes(pubkey);
script.writeOp(OP_CHECKSIG); script.writeOp(OP_CHECKSIG);
return script; return script;
}; };
/** /**
* Creates a standard txout script. * Creates a standard txout script.
*/ */
Script.createPubKeyHashOut = function(pubKeyHash) { Script.createPubKeyHashOut = function(pubKeyHash) {
var script = new Script(); var script = new Script();
script.writeOp(OP_DUP); script.writeOp(OP_DUP);
script.writeOp(OP_HASH160); script.writeOp(OP_HASH160);
@ -441,9 +438,9 @@ function spec(b) {
script.writeOp(OP_EQUALVERIFY); script.writeOp(OP_EQUALVERIFY);
script.writeOp(OP_CHECKSIG); script.writeOp(OP_CHECKSIG);
return script; return script;
}; };
Script.createMultisig = function(n_required, keys) { Script.createMultisig = function(n_required, keys) {
var script = new Script(); var script = new Script();
script.writeN(n_required); script.writeN(n_required);
keys.forEach(function(key) { keys.forEach(function(key) {
@ -452,17 +449,17 @@ function spec(b) {
script.writeN(keys.length); script.writeN(keys.length);
script.writeOp(OP_CHECKMULTISIG); script.writeOp(OP_CHECKMULTISIG);
return script; return script;
}; };
Script.createP2SH = function(scriptHash) { Script.createP2SH = function(scriptHash) {
var script = new Script(); var script = new Script();
script.writeOp(OP_HASH160); script.writeOp(OP_HASH160);
script.writeBytes(scriptHash); script.writeBytes(scriptHash);
script.writeOp(OP_EQUAL); script.writeOp(OP_EQUAL);
return script; return script;
}; };
Script.fromTestData = function(testData) { Script.fromTestData = function(testData) {
testData = testData.map(function(chunk) { testData = testData.map(function(chunk) {
if ("string" === typeof chunk) { if ("string" === typeof chunk) {
return new Buffer(chunk, 'hex'); return new Buffer(chunk, 'hex');
@ -475,16 +472,16 @@ function spec(b) {
script.chunks = testData; script.chunks = testData;
script.updateBuffer(); script.updateBuffer();
return script; return script;
}; };
Script.fromChunks = function(chunks) { Script.fromChunks = function(chunks) {
var script = new Script(); var script = new Script();
script.chunks = chunks; script.chunks = chunks;
script.updateBuffer(); script.updateBuffer();
return script; return script;
}; };
Script.chunksToBuffer = function(chunks) { Script.chunksToBuffer = function(chunks) {
var buf = new Put(); var buf = new Put();
for (var i = 0, l = chunks.length; i < l; i++) { for (var i = 0, l = chunks.length; i < l; i++) {
@ -510,8 +507,6 @@ function spec(b) {
} }
} }
return buf.buffer(); return buf.buffer();
};
return Script;
}; };
module.defineClass(spec);
module.exports = require('soop')(Script);

View File

@ -1,28 +1,23 @@
require('classtool'); var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var Opcode = imports.Opcode || require('./Opcode');
var buffertools = imports.buffertools || require('buffertools');
var bignum = imports.bignum || require('bignum');
var Util = imports.Util || require('./util/util');
var Script = require('./Script');
function spec(b) { // Make opcodes available as pseudo-constants
var assert = require('assert'); for (var i in Opcode.map) {
var config = b.config || require('./config');
var log = b.log || require('./util/log');
var Opcode = b.Opcode || require('./Opcode').class();
var buffertools = b.buffertools || require('buffertools');
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval(i + " = " + Opcode.map[i] + ";"); eval(i + " = " + Opcode.map[i] + ";");
} }
var bignum = b.bignum || require('bignum'); function ScriptInterpreter() {
var Util = b.Util || require('./util/util');
var Script = require('./Script').class();
function ScriptInterpreter() {
this.stack = []; this.stack = [];
this.disableUnsafeOpcodes = true; this.disableUnsafeOpcodes = true;
}; };
ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, callback) { ScriptInterpreter.prototype.eval = function eval(script, tx, inIndex, hashType, callback) {
if ("function" !== typeof callback) { if ("function" !== typeof callback) {
throw new Error("ScriptInterpreter.eval() requires a callback"); throw new Error("ScriptInterpreter.eval() requires a callback");
} }
@ -767,9 +762,9 @@ function spec(b) {
cb(e); cb(e);
} }
} }
}; };
ScriptInterpreter.prototype.evalTwo = ScriptInterpreter.prototype.evalTwo =
function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback) { function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback) {
var self = this; var self = this;
@ -781,15 +776,15 @@ function spec(b) {
self.eval(scriptPubkey, tx, n, hashType, callback); self.eval(scriptPubkey, tx, n, hashType, callback);
}); });
}; };
/** /**
* Get the top element of the stack. * Get the top element of the stack.
* *
* Using the offset parameter this function can also access lower elements * Using the offset parameter this function can also access lower elements
* from the stack. * from the stack.
*/ */
ScriptInterpreter.prototype.stackTop = function stackTop(offset) { ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
offset = +offset || 1; offset = +offset || 1;
if (offset < 1) offset = 1; if (offset < 1) offset = 1;
@ -798,24 +793,24 @@ function spec(b) {
} }
return this.stack[this.stack.length - offset]; return this.stack[this.stack.length - offset];
}; };
ScriptInterpreter.prototype.stackBack = function stackBack() { ScriptInterpreter.prototype.stackBack = function stackBack() {
return this.stack[-1]; return this.stack[-1];
}; };
/** /**
* Pop the top element off the stack and return it. * Pop the top element off the stack and return it.
*/ */
ScriptInterpreter.prototype.stackPop = function stackPop() { ScriptInterpreter.prototype.stackPop = function stackPop() {
if (this.stack.length < 1) { if (this.stack.length < 1) {
throw new Error('ScriptInterpreter.stackTop(): Stack underrun'); throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
} }
return this.stack.pop(); return this.stack.pop();
}; };
ScriptInterpreter.prototype.stackSwap = function stackSwap(a, b) { ScriptInterpreter.prototype.stackSwap = function stackSwap(a, b) {
if (this.stack.length < a || this.stack.length < b) { if (this.stack.length < a || this.stack.length < b) {
throw new Error('ScriptInterpreter.stackTop(): Stack underrun'); throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
} }
@ -826,15 +821,15 @@ function spec(b) {
var tmp = s[l - a]; var tmp = s[l - a];
s[l - a] = s[l - b]; s[l - a] = s[l - b];
s[l - b] = tmp; s[l - b] = tmp;
}; };
/** /**
* Returns a version of the stack with only primitive types. * Returns a version of the stack with only primitive types.
* *
* The return value is an array. Any single byte buffer is converted to an * The return value is an array. Any single byte buffer is converted to an
* integer. Any longer Buffer is converted to a hex string. * integer. Any longer Buffer is converted to a hex string.
*/ */
ScriptInterpreter.prototype.getPrimitiveStack = function getPrimitiveStack() { ScriptInterpreter.prototype.getPrimitiveStack = function getPrimitiveStack() {
return this.stack.map(function(entry) { return this.stack.map(function(entry) {
if (entry.length > 2) { if (entry.length > 2) {
return buffertools.toHex(entry.slice(0)); return buffertools.toHex(entry.slice(0));
@ -846,9 +841,9 @@ function spec(b) {
return buffertools.toHex(entry.slice(0)); return buffertools.toHex(entry.slice(0));
} }
}); });
}; };
var castBool = ScriptInterpreter.castBool = function castBool(v) { var castBool = ScriptInterpreter.castBool = function castBool(v) {
for (var i = 0, l = v.length; i < l; i++) { for (var i = 0, l = v.length; i < l; i++) {
if (v[i] != 0) { if (v[i] != 0) {
// Negative zero is still zero // Negative zero is still zero
@ -859,11 +854,11 @@ function spec(b) {
} }
} }
return false; return false;
}; };
var castInt = ScriptInterpreter.castInt = function castInt(v) { var castInt = ScriptInterpreter.castInt = function castInt(v) {
return castBigint(v).toNumber(); return castBigint(v).toNumber();
}; };
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) { var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
if (!v.length) { if (!v.length) {
return bignum(0); return bignum(0);
} }
@ -883,8 +878,8 @@ function spec(b) {
// Positive number // Positive number
return bignum.fromBuffer(w); return bignum.fromBuffer(w);
} }
}; };
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) { var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
if ("number" === typeof v) { if ("number" === typeof v) {
v = bignum(v); v = bignum(v);
} }
@ -916,17 +911,17 @@ function spec(b) {
return buffertools.reverse(b); return buffertools.reverse(b);
} }
} }
}; };
ScriptInterpreter.prototype.getResult = function getResult() { ScriptInterpreter.prototype.getResult = function getResult() {
if (this.stack.length === 0) { if (this.stack.length === 0) {
throw new Error("Empty stack after script evaluation"); throw new Error("Empty stack after script evaluation");
} }
return castBool(this.stack[this.stack.length - 1]); return castBool(this.stack[this.stack.length - 1]);
}; };
ScriptInterpreter.verify = ScriptInterpreter.verify =
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback) { function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback) {
if ("function" !== typeof callback) { if ("function" !== typeof callback) {
throw new Error("ScriptInterpreter.verify() requires a callback"); throw new Error("ScriptInterpreter.verify() requires a callback");
@ -954,9 +949,9 @@ function spec(b) {
}); });
return si; return si;
}; };
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn, function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) { hashType, opts, callback, si, siCopy) {
if (siCopy.stack.length == 0) { if (siCopy.stack.length == 0) {
callback(null, false); callback(null, false);
@ -964,9 +959,9 @@ function spec(b) {
} }
callback(null, castBool(siCopy.stackBack())); callback(null, castBool(siCopy.stackBack()));
} }
function verifyStep3(scriptSig, scriptPubKey, txTo, nIn, function verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) { hashType, opts, callback, si, siCopy) {
if (si.stack.length == 0) { if (si.stack.length == 0) {
callback(null, false); callback(null, false);
@ -1000,9 +995,9 @@ function spec(b) {
verifyStep4(scriptSig, scriptPubKey, txTo, nIn, verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy); hashType, opts, callback, si, siCopy);
}); });
} }
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn, function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy) { hashType, opts, callback, si, siCopy) {
if (opts.verifyP2SH) { if (opts.verifyP2SH) {
si.stack.forEach(function(item) { si.stack.forEach(function(item) {
@ -1017,9 +1012,9 @@ function spec(b) {
verifyStep3(scriptSig, scriptPubKey, txTo, nIn, verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy); hashType, opts, callback, si, siCopy);
}); });
} }
ScriptInterpreter.verifyFull = ScriptInterpreter.verifyFull =
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType, function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
opts, callback) { opts, callback) {
var si = new ScriptInterpreter(); var si = new ScriptInterpreter();
@ -1032,9 +1027,9 @@ function spec(b) {
verifyStep2(scriptSig, scriptPubKey, txTo, nIn, verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy); hashType, opts, callback, si, siCopy);
}); });
}; };
var checkSig = ScriptInterpreter.checkSig = var checkSig = ScriptInterpreter.checkSig =
function(sig, pubkey, scriptCode, tx, n, hashType, callback) { function(sig, pubkey, scriptCode, tx, n, hashType, callback) {
if (!sig.length) { if (!sig.length) {
callback(null, false); callback(null, false);
@ -1060,8 +1055,6 @@ function spec(b) {
} catch (err) { } catch (err) {
callback(null, false); callback(null, false);
} }
};
return ScriptInterpreter;
}; };
module.defineClass(spec);
module.exports = require('soop')(ScriptInterpreter);

View File

@ -1,25 +1,20 @@
require('classtool'); var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var Address = imports.Address || require('./Address');
var Script = imports.Script || require('./Script');
var ScriptInterpreter = imports.ScriptInterpreter || require('./ScriptInterpreter');
var util = imports.util || require('./util/util');
var bignum = imports.bignum || require('bignum');
var Put = imports.Put || require('bufferput');
var Parser = imports.Parser || require('./util/BinaryParser');
var Step = imports.Step || require('step');
var buffertools = imports.buffertools || require('buffertools');
var error = imports.error || require('./util/error');
function spec(b) { var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
var config = b.config || require('./config');
var log = b.log || require('./util/log');
var Address = b.Address || require('./Address').class();
var Script = b.Script || require('./Script').class();
var ScriptInterpreter = b.ScriptInterpreter || require('./ScriptInterpreter').class();
var util = b.util || require('./util/util');
var bignum = b.bignum || require('bignum');
var Put = b.Put || require('bufferput');
var Parser = b.Parser || require('./util/BinaryParser').class();
var Step = b.Step || require('step');
var buffertools = b.buffertools || require('buffertools');
var error = b.error || require('./util/error'); function TransactionIn(data) {
var VerificationError = error.VerificationError;
var MissingSourceError = error.MissingSourceError;
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
function TransactionIn(data) {
if ("object" !== typeof data) { if ("object" !== typeof data) {
data = {}; data = {};
} }
@ -37,70 +32,70 @@ function spec(b) {
this.s = Buffer.isBuffer(data.s) ? data.s : this.s = Buffer.isBuffer(data.s) ? data.s :
Buffer.isBuffer(data.script) ? data.script : util.EMPTY_BUFFER; Buffer.isBuffer(data.script) ? data.script : util.EMPTY_BUFFER;
this.q = data.q ? data.q : data.sequence; this.q = data.q ? data.q : data.sequence;
} }
TransactionIn.prototype.getScript = function getScript() { TransactionIn.prototype.getScript = function getScript() {
return new Script(this.s); return new Script(this.s);
}; };
TransactionIn.prototype.isCoinBase = function isCoinBase() { TransactionIn.prototype.isCoinBase = function isCoinBase() {
return buffertools.compare(this.o, COINBASE_OP) === 0; return buffertools.compare(this.o, COINBASE_OP) === 0;
}; };
TransactionIn.prototype.serialize = function serialize() { TransactionIn.prototype.serialize = function serialize() {
var slen = util.varIntBuf(this.s.length); var slen = util.varIntBuf(this.s.length);
var qbuf = new Buffer(4); var qbuf = new Buffer(4);
qbuf.writeUInt32LE(this.q, 0); qbuf.writeUInt32LE(this.q, 0);
var ret = Buffer.concat([this.o, slen, this.s, qbuf]); var ret = Buffer.concat([this.o, slen, this.s, qbuf]);
return ret; return ret;
}; };
TransactionIn.prototype.getOutpointHash = function getOutpointHash() { TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
if ("undefined" !== typeof this.o.outHashCache) { if ("undefined" !== typeof this.o.outHashCache) {
return this.o.outHashCache; return this.o.outHashCache;
} }
return this.o.outHashCache = this.o.slice(0, 32); return this.o.outHashCache = this.o.slice(0, 32);
}; };
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() { TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() {
return (this.o[32] ) + return (this.o[32] ) +
(this.o[33] << 8) + (this.o[33] << 8) +
(this.o[34] << 16) + (this.o[34] << 16) +
(this.o[35] << 24); (this.o[35] << 24);
}; };
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) { TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) {
this.o[32] = n & 0xff; this.o[32] = n & 0xff;
this.o[33] = n >> 8 & 0xff; this.o[33] = n >> 8 & 0xff;
this.o[34] = n >> 16 & 0xff; this.o[34] = n >> 16 & 0xff;
this.o[35] = n >> 24 & 0xff; this.o[35] = n >> 24 & 0xff;
}; };
function TransactionOut(data) { function TransactionOut(data) {
if ("object" !== typeof data) { if ("object" !== typeof data) {
data = {}; data = {};
} }
this.v = data.v ? data.v : data.value; this.v = data.v ? data.v : data.value;
this.s = data.s ? data.s : data.script; this.s = data.s ? data.s : data.script;
}; };
TransactionOut.prototype.getValue = function getValue() { TransactionOut.prototype.getValue = function getValue() {
return new Parser(this.v).word64lu(); return new Parser(this.v).word64lu();
}; };
TransactionOut.prototype.getScript = function getScript() { TransactionOut.prototype.getScript = function getScript() {
return new Script(this.s); return new Script(this.s);
}; };
TransactionOut.prototype.serialize = function serialize() { TransactionOut.prototype.serialize = function serialize() {
var slen = util.varIntBuf(this.s.length); var slen = util.varIntBuf(this.s.length);
return Buffer.concat([this.v, slen, this.s]); return Buffer.concat([this.v, slen, this.s]);
}; };
function Transaction(data) { function Transaction(data) {
if ("object" !== typeof data) { if ("object" !== typeof data) {
data = {}; data = {};
} }
@ -121,16 +116,16 @@ function spec(b) {
return txout; return txout;
}) : []; }) : [];
if (data.buffer) this._buffer = data.buffer; if (data.buffer) this._buffer = data.buffer;
}; };
this.class = Transaction; this.class = Transaction;
Transaction.In = TransactionIn; Transaction.In = TransactionIn;
Transaction.Out = TransactionOut; Transaction.Out = TransactionOut;
Transaction.prototype.isCoinBase = function () { Transaction.prototype.isCoinBase = function () {
return this.ins.length == 1 && this.ins[0].isCoinBase(); return this.ins.length == 1 && this.ins[0].isCoinBase();
}; };
Transaction.prototype.isStandard = function isStandard() { Transaction.prototype.isStandard = function isStandard() {
var i; var i;
for (i = 0; i < this.ins.length; i++) { for (i = 0; i < this.ins.length; i++) {
if (this.ins[i].getScript().getInType() == "Strange") { if (this.ins[i].getScript().getInType() == "Strange") {
@ -143,9 +138,9 @@ function spec(b) {
} }
} }
return true; return true;
}; };
Transaction.prototype.serialize = function serialize() { Transaction.prototype.serialize = function serialize() {
var bufs = []; var bufs = [];
var buf = new Buffer(4); var buf = new Buffer(4);
@ -168,34 +163,34 @@ function spec(b) {
this._buffer = Buffer.concat(bufs); this._buffer = Buffer.concat(bufs);
return this._buffer; return this._buffer;
}; };
Transaction.prototype.getBuffer = function getBuffer() { Transaction.prototype.getBuffer = function getBuffer() {
if (this._buffer) return this._buffer; if (this._buffer) return this._buffer;
return this.serialize(); return this.serialize();
}; };
Transaction.prototype.calcHash = function calcHash() { Transaction.prototype.calcHash = function calcHash() {
this.hash = util.twoSha256(this.getBuffer()); this.hash = util.twoSha256(this.getBuffer());
return this.hash; return this.hash;
}; };
Transaction.prototype.checkHash = function checkHash() { Transaction.prototype.checkHash = function checkHash() {
if (!this.hash || !this.hash.length) return false; if (!this.hash || !this.hash.length) return false;
return buffertools.compare(this.calcHash(), this.hash) === 0; return buffertools.compare(this.calcHash(), this.hash) === 0;
}; };
Transaction.prototype.getHash = function getHash() { Transaction.prototype.getHash = function getHash() {
if (!this.hash || !this.hash.length) { if (!this.hash || !this.hash.length) {
this.hash = this.calcHash(); this.hash = this.calcHash();
} }
return this.hash; return this.hash;
}; };
// convert encoded list of inputs to easy-to-use JS list-of-lists // convert encoded list of inputs to easy-to-use JS list-of-lists
Transaction.prototype.inputs = function inputs() { Transaction.prototype.inputs = function inputs() {
var res = []; var res = [];
for (var i = 0; i < this.ins.length; i++) { for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i]; var txin = this.ins[i];
@ -205,9 +200,9 @@ function spec(b) {
} }
return res; return res;
} }
/** /**
* Load and cache transaction inputs. * Load and cache transaction inputs.
* *
* This function will try to load the inputs for a transaction. * This function will try to load the inputs for a transaction.
@ -218,15 +213,15 @@ function spec(b) {
* met (or a timeout occurs.) * met (or a timeout occurs.)
* @param {Function} callback Function to call on completion. * @param {Function} callback Function to call on completion.
*/ */
Transaction.prototype.cacheInputs = Transaction.prototype.cacheInputs =
function cacheInputs(blockChain, txStore, wait, callback) { function cacheInputs(blockChain, txStore, wait, callback) {
var self = this; var self = this;
var txCache = new TransactionInputsCache(this); var txCache = new TransactionInputsCache(this);
txCache.buffer(blockChain, txStore, wait, callback); txCache.buffer(blockChain, txStore, wait, callback);
}; };
Transaction.prototype.verify = function verify(txCache, blockChain, callback) { Transaction.prototype.verify = function verify(txCache, blockChain, callback) {
var self = this; var self = this;
var txIndex = txCache.txIndex; var txIndex = txCache.txIndex;
@ -350,22 +345,22 @@ function spec(b) {
}, },
callback callback
); );
}; };
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) { Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
return ScriptInterpreter.verify(this.ins[n].getScript(), return ScriptInterpreter.verify(this.ins[n].getScript(),
scriptPubKey, scriptPubKey,
this, n, 0, this, n, 0,
callback); callback);
}; };
/** /**
* Returns an object containing all pubkey hashes affected by this transaction. * Returns an object containing all pubkey hashes affected by this transaction.
* *
* The return object contains the base64-encoded pubKeyHash values as keys * The return object contains the base64-encoded pubKeyHash values as keys
* and the original pubKeyHash buffers as values. * and the original pubKeyHash buffers as values.
*/ */
Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) { Transaction.prototype.getAffectedKeys = function getAffectedKeys(txCache) {
// TODO: Function won't consider results cached if there are no affected // TODO: Function won't consider results cached if there are no affected
// accounts. // accounts.
if (!(this.affects && this.affects.length)) { if (!(this.affects && this.affects.length)) {
@ -432,22 +427,22 @@ function spec(b) {
}); });
return affectedKeys; return affectedKeys;
}; };
var OP_CODESEPARATOR = 171; var OP_CODESEPARATOR = 171;
var SIGHASH_ALL = 1; var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2; var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3; var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80; var SIGHASH_ANYONECANPAY = 80;
Transaction.SIGHASH_ALL=SIGHASH_ALL; Transaction.SIGHASH_ALL=SIGHASH_ALL;
Transaction.SIGHASH_NONE=SIGHASH_NONE; Transaction.SIGHASH_NONE=SIGHASH_NONE;
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE; Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE;
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY; Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY;
Transaction.prototype.hashForSignature = Transaction.prototype.hashForSignature =
function hashForSignature(script, inIndex, hashType) { function hashForSignature(script, inIndex, hashType) {
if (+inIndex !== inIndex || if (+inIndex !== inIndex ||
inIndex < 0 || inIndex >= this.ins.length) { inIndex < 0 || inIndex >= this.ins.length) {
throw new Error("Input index '"+inIndex+"' invalid or out of bounds "+ throw new Error("Input index '"+inIndex+"' invalid or out of bounds "+
@ -549,12 +544,12 @@ function spec(b) {
buffer = Buffer.concat([buffer, new Buffer([parseInt(hashType), 0, 0, 0])]); buffer = Buffer.concat([buffer, new Buffer([parseInt(hashType), 0, 0, 0])]);
return util.twoSha256(buffer); return util.twoSha256(buffer);
}; };
/** /**
* Returns an object with the same field names as jgarzik's getblock patch. * Returns an object with the same field names as jgarzik's getblock patch.
*/ */
Transaction.prototype.getStandardizedObject = function getStandardizedObject() { Transaction.prototype.getStandardizedObject = function getStandardizedObject() {
var tx = { var tx = {
hash: util.formatHashFull(this.getHash()), hash: util.formatHashFull(this.getHash()),
version: this.version, version: this.version,
@ -596,14 +591,14 @@ function spec(b) {
tx["out"] = outs; tx["out"] = outs;
return tx; return tx;
}; };
// Add some Mongoose compatibility functions to the plain object // Add some Mongoose compatibility functions to the plain object
Transaction.prototype.toObject = function toObject() { Transaction.prototype.toObject = function toObject() {
return this; return this;
}; };
Transaction.prototype.fromObj = function fromObj(obj) { Transaction.prototype.fromObj = function fromObj(obj) {
var txobj = {}; var txobj = {};
txobj.version = obj.version || 1; txobj.version = obj.version || 1;
txobj.lock_time = obj.lock_time || 0; txobj.lock_time = obj.lock_time || 0;
@ -645,9 +640,9 @@ function spec(b) {
this.version = txobj.version; this.version = txobj.version;
this.ins = txobj.ins; this.ins = txobj.ins;
this.outs = txobj.outs; this.outs = txobj.outs;
} }
Transaction.prototype.parse = function (parser) { Transaction.prototype.parse = function (parser) {
if (Buffer.isBuffer(parser)) { if (Buffer.isBuffer(parser)) {
this._buffer = parser; this._buffer = parser;
parser = new Parser(parser); parser = new Parser(parser);
@ -682,11 +677,11 @@ function spec(b) {
this.lock_time = parser.word32le(); this.lock_time = parser.word32le();
this.calcHash(); this.calcHash();
}; };
var TransactionInputsCache = exports.TransactionInputsCache = var TransactionInputsCache = exports.TransactionInputsCache =
function TransactionInputsCache(tx) function TransactionInputsCache(tx)
{ {
var txList = []; var txList = [];
var txList64 = []; var txList64 = [];
var reqOuts = {}; var reqOuts = {};
@ -713,10 +708,10 @@ function spec(b) {
this.txIndex = {}; this.txIndex = {};
this.requiredOuts = reqOuts; this.requiredOuts = reqOuts;
this.callbacks = []; this.callbacks = [];
}; };
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback) TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback)
{ {
var self = this; var self = this;
var complete = false; var complete = false;
@ -799,11 +794,11 @@ function spec(b) {
}, },
self.callback.bind(self) self.callback.bind(self)
); );
}; };
TransactionInputsCache.prototype.callback = function callback(err) TransactionInputsCache.prototype.callback = function callback(err)
{ {
var args = Array.prototype.slice.apply(arguments); var args = Array.prototype.slice.apply(arguments);
// Empty the callback array first (because downstream functions could add new // Empty the callback array first (because downstream functions could add new
@ -819,8 +814,6 @@ function spec(b) {
log.err("Callback error after connecting tx inputs: "+ log.err("Callback error after connecting tx inputs: "+
(err.stack ? err.stack : err.toString())); (err.stack ? err.stack : err.toString()));
} }
};
return Transaction;
}; };
module.defineClass(spec);
module.exports = require('soop')(Transaction);

View File

@ -1,15 +1,15 @@
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',
@ -19,9 +19,9 @@ function ClassSpec(b) {
keys: [], keys: [],
sin: {}, sin: {},
scripts: {}, scripts: {},
}; };
function Wallet(cfg) { function Wallet(cfg) {
if (typeof cfg !== 'object') if (typeof cfg !== 'object')
cfg = {}; cfg = {};
@ -33,15 +33,15 @@ function ClassSpec(b) {
this.network = undefined; this.network = undefined;
this.dirty = cfg.dirty || true; this.dirty = cfg.dirty || true;
}; };
Wallet.prototype.readSync = function(filename, passphrase) { Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD, this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename); passphrase, filename);
this.dirty = false; this.dirty = false;
}; };
Wallet.prototype.writeSync = function(filename, passphrase) { Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp"; var tmp_fn = filename + ".tmp";
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn, EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
@ -49,9 +49,9 @@ function ClassSpec(b) {
fs.renameSync(tmp_fn, filename); fs.renameSync(tmp_fn, filename);
this.dirty = false; this.dirty = false;
}; };
Wallet.prototype.setNetwork = function(netname) { Wallet.prototype.setNetwork = function(netname) {
if (!netname) if (!netname)
netname = this.datastore.network; netname = this.datastore.network;
@ -70,19 +70,19 @@ function ClassSpec(b) {
// store+canonicalize name // store+canonicalize name
this.datastore['network'] = this.network.name; this.datastore['network'] = this.network.name;
this.dirty = true; this.dirty = true;
}; };
Wallet.prototype.addKey = function(wkey) { Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey); this.datastore.keys.push(wkey);
this.dirty = true; this.dirty = true;
}; };
Wallet.prototype.addSIN = function(sinObj) { Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj; this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true; this.dirty = true;
}; };
Wallet.prototype.findKeyHash = function(pubKeyHash) { Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString(); var pkhStr = pubKeyHash.toString();
for (var i = 0; i < this.datastore.keys.length; i++) { for (var i = 0; i < this.datastore.keys.length; i++) {
@ -94,9 +94,9 @@ function ClassSpec(b) {
} }
return undefined; return undefined;
}; };
Wallet.prototype.expandKey = function(key) { Wallet.prototype.expandKey = function(key) {
var addr = new Address(key); var addr = new Address(key);
var isAddr = true; var isAddr = true;
@ -113,9 +113,9 @@ function ClassSpec(b) {
if (!key.match(re)) if (!key.match(re))
throw new Error("Unknown key type"); throw new Error("Unknown key type");
return hex(key); return hex(key);
}; };
Wallet.prototype.expandKeys = function(keys) { Wallet.prototype.expandKeys = function(keys) {
var res = []; var res = [];
var us = this; var us = this;
keys.forEach(function(key) { keys.forEach(function(key) {
@ -123,9 +123,9 @@ function ClassSpec(b) {
res.push(expKey); res.push(expKey);
}); });
return res; return res;
}; };
Wallet.prototype.addScript = function(script) { Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer(); var buf = script.getBuffer();
var hash = util.sha256ripe160(buf); var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash); var addr = new Address(this.network.addressScript, hash);
@ -134,9 +134,7 @@ function ClassSpec(b) {
this.dirty = true; this.dirty = true;
return addrStr; return addrStr;
};
return Wallet;
}; };
module.defineClass(ClassSpec);
module.exports = require('soop')(Wallet);

View File

@ -1,26 +1,25 @@
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() { WalletKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync(); this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime(); this.created = timeUtil.curtime();
}; };
WalletKey.prototype.storeObj = function() { WalletKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex'); var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public); var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
var addr = new Address(this.network.addressPubkey, pubKeyHash); var addr = new Address(this.network.addressPubkey, pubKeyHash);
@ -33,9 +32,9 @@ function ClassSpec(b) {
}; };
return obj; return obj;
}; };
WalletKey.prototype.fromObj = function(obj) { WalletKey.prototype.fromObj = function(obj) {
this.created = obj.created; this.created = obj.created;
this.privKey = new KeyModule.Key(); this.privKey = new KeyModule.Key();
if (obj.priv.length==64) { if (obj.priv.length==64) {
@ -48,8 +47,6 @@ function ClassSpec(b) {
this.privKey.compressed = priv.compressed(); this.privKey.compressed = priv.compressed();
} }
this.privKey.regenerateSync(); this.privKey.regenerateSync();
};
return WalletKey;
}; };
module.defineClass(ClassSpec);
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>
<pre>
<div id='content'></div> <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,20 +2,20 @@
* 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) { Parser.prototype.buffer = function buffer(len) {
var buf = this.subject.slice(this.pos, this.pos+len); var buf = this.subject.slice(this.pos, this.pos+len);
this.pos += len; this.pos += len;
return buf; return buf;
}; };
Parser.prototype.search = function search(needle) { Parser.prototype.search = function search(needle) {
var len; var len;
if ("string" === typeof needle || Buffer.isBuffer(needle)) { if ("string" === typeof needle || Buffer.isBuffer(needle)) {
@ -38,12 +38,12 @@ function spec(b) {
} }
return -1; return -1;
} }
}; };
/** /**
* Like search(), but returns the skipped bytes * Like search(), but returns the skipped bytes
*/ */
Parser.prototype.scan = function scan(needle) { Parser.prototype.scan = function scan(needle) {
var startPos = this.pos; var startPos = this.pos;
var len = this.search(needle); var len = this.search(needle);
if (len !== -1) { if (len !== -1) {
@ -51,55 +51,55 @@ function spec(b) {
} else { } else {
throw new Error('No match'); throw new Error('No match');
} }
}; };
Parser.prototype.eof = function eof() { Parser.prototype.eof = function eof() {
return this.pos >= this.subject.length; return this.pos >= this.subject.length;
}; };
// convert byte strings to unsigned little endian numbers // convert byte strings to unsigned little endian numbers
function decodeLEu (bytes) { function decodeLEu (bytes) {
var acc = 0; var acc = 0;
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256,i) * bytes[i]; acc += Math.pow(256,i) * bytes[i];
} }
return acc; return acc;
} }
// convert byte strings to unsigned big endian numbers // convert byte strings to unsigned big endian numbers
function decodeBEu (bytes) { function decodeBEu (bytes) {
var acc = 0; var acc = 0;
for (var i = 0; i < bytes.length; i++) { for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, bytes.length - i - 1) * bytes[i]; acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
} }
return acc; return acc;
} }
// convert byte strings to signed big endian numbers // convert byte strings to signed big endian numbers
function decodeBEs (bytes) { function decodeBEs (bytes) {
var val = decodeBEu(bytes); var val = decodeBEu(bytes);
if ((bytes[0] & 0x80) == 0x80) { if ((bytes[0] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length); val -= Math.pow(256, bytes.length);
} }
return val; return val;
} }
// convert byte strings to signed little endian numbers // convert byte strings to signed little endian numbers
function decodeLEs (bytes) { function decodeLEs (bytes) {
var val = decodeLEu(bytes); var val = decodeLEu(bytes);
if ((bytes[bytes.length - 1] & 0x80) == 0x80) { if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length); val -= Math.pow(256, bytes.length);
} }
return val; return val;
} }
function getDecoder(len, fn) { function getDecoder(len, fn) {
return function () { return function () {
var buf = this.buffer(len); var buf = this.buffer(len);
return fn(buf); return fn(buf);
}; };
}; };
[ 1, 2, 4, 8 ].forEach(function (bytes) { [ 1, 2, 4, 8 ].forEach(function (bytes) {
var bits = bytes * 8; var bits = bytes * 8;
Parser.prototype['word' + bits + 'le'] Parser.prototype['word' + bits + 'le']
@ -118,10 +118,10 @@ function spec(b) {
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be; Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
Parser.prototype.word8s = Parser.prototype.word8bs; Parser.prototype.word8s = Parser.prototype.word8bs;
}); });
Parser.prototype.varInt = function () Parser.prototype.varInt = function ()
{ {
var firstByte = this.word8(); var firstByte = this.word8();
switch (firstByte) { switch (firstByte) {
case 0xFD: case 0xFD:
@ -136,13 +136,11 @@ function spec(b) {
default: default:
return firstByte; return firstByte;
} }
}; };
Parser.prototype.varStr = function () { Parser.prototype.varStr = function () {
var len = this.varInt(); var len = this.varInt();
return this.buffer(len); return this.buffer(len);
};
return Parser;
}; };
module.defineClass(spec);
module.exports = require('soop')(Parser);

View File

@ -1,92 +1,91 @@
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) // get or set the encoding used (transforms data)
EncodedData.prototype.encoding = function(encoding) { EncodedData.prototype.encoding = function(encoding) {
if(encoding && (encoding != this._encoding)) { if(encoding && (encoding != this._encoding)) {
this.data = this.as(encoding); this.data = this.as(encoding);
this.__proto__ = this.encodings[encoding]; this.__proto__ = this.encodings[encoding];
} }
return this._encoding; return this._encoding;
}; };
// answer a new instance having the given encoding // answer a new instance having the given encoding
EncodedData.prototype.withEncoding = function(encoding) { EncodedData.prototype.withEncoding = function(encoding) {
return new EncodedData(this.as(encoding), encoding); return new EncodedData(this.as(encoding), encoding);
}; };
// answer the data in the given encoding // answer the data in the given encoding
EncodedData.prototype.as = function(encoding) { EncodedData.prototype.as = function(encoding) {
if(!encodings[encoding]) throw new Error('invalid encoding'); if(!encodings[encoding]) throw new Error('invalid encoding');
return this.converters[encoding].call(this); return this.converters[encoding].call(this);
}; };
// validate that we can convert to binary // validate that we can convert to binary
EncodedData.prototype._validate = function() { EncodedData.prototype._validate = function() {
this.withEncoding('binary'); this.withEncoding('binary');
}; };
// Boolean protocol for testing if valid // Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() { EncodedData.prototype.isValid = function() {
try { try {
this.validate(); this.validate();
return true; return true;
} catch(e) { } catch(e) {
return false; return false;
} }
}; };
// subclasses can override to do more stuff // subclasses can override to do more stuff
EncodedData.prototype.validate = function() { EncodedData.prototype.validate = function() {
this._validate(); this._validate();
}; };
// Boolean protocol for testing if valid // Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() { EncodedData.prototype.isValid = function() {
try { try {
this.validate(); this.validate();
return true; return true;
} catch(e) { } catch(e) {
return false; return false;
} }
}; };
// convert to a string (in base58 form) // convert to a string (in base58 form)
EncodedData.prototype.toString = function() { EncodedData.prototype.toString = function() {
return this.as('base58'); return this.as('base58');
}; };
// utility // utility
EncodedData.prototype.doAsBinary = function(callback) { EncodedData.prototype.doAsBinary = function(callback) {
var oldEncoding = this.encoding(); var oldEncoding = this.encoding();
this.encoding('binary'); this.encoding('binary');
callback.apply(this); callback.apply(this);
this.encoding(oldEncoding); this.encoding(oldEncoding);
}; };
// Setup support for various address encodings. The object for // Setup support for various address encodings. The object for
// each encoding inherits from the EncodedData prototype. This // each encoding inherits from the EncodedData prototype. This
// allows any encoding to override any method...changing the encoding // allows any encoding to override any method...changing the encoding
// for an instance will change the encoding it inherits from. Note, // for an instance will change the encoding it inherits from. Note,
// this will present some problems for anyone wanting to inherit from // this will present some problems for anyone wanting to inherit from
// EncodedData (we'll deal with that when needed). // EncodedData (we'll deal with that when needed).
var encodings = { var encodings = {
'binary': { 'binary': {
converters: { converters: {
'binary': function() { 'binary': function() {
@ -128,18 +127,18 @@ function ClassSpec(b) {
}, },
}, },
}, },
}; };
var no_conversion = function() {return this.data;}; var no_conversion = function() {return this.data;};
for(var k in encodings) { for(var k in encodings) {
if(encodings.hasOwnProperty(k)){ if(encodings.hasOwnProperty(k)){
if(!encodings[k].converters[k]) if(!encodings[k].converters[k])
encodings[k].converters[k] = no_conversion; encodings[k].converters[k] = no_conversion;
encodings[k]._encoding = k; encodings[k]._encoding = k;
} }
} }
EncodedData.applyEncodingsTo = function(aClass) { EncodedData.applyEncodingsTo = function(aClass) {
var tmp = {}; var tmp = {};
for(var k in encodings) { for(var k in encodings) {
var enc = encodings[k]; var enc = encodings[k];
@ -151,9 +150,9 @@ function ClassSpec(b) {
tmp[k] = obj; tmp[k] = obj;
} }
aClass.prototype.encodings = tmp; aClass.prototype.encodings = tmp;
}; };
EncodedData.applyEncodingsTo(EncodedData);
module.exports = require('soop')(EncodedData);
EncodedData.applyEncodingsTo(EncodedData);
return EncodedData;
}
module.defineClass(ClassSpec);

View File

@ -1,9 +1,9 @@
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;
@ -12,28 +12,27 @@ function ClassSpec(b) {
this.__proto__ = this.encodings['binary']; this.__proto__ = this.encodings['binary'];
this.version(version); this.version(version);
this.payload(payload); this.payload(payload);
}; };
VersionedData.superclass = superclass;
superclass.applyEncodingsTo(VersionedData);
// get or set the version data (the first byte of the address) VersionedData.parent = parent;
VersionedData.prototype.version = function(num) { parent.applyEncodingsTo(VersionedData);
// get or set the version data (the first byte of the address)
VersionedData.prototype.version = function(num) {
if(num || (num === 0)) { if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);}); this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num; return num;
} }
return this.as('binary').readUInt8(0); return this.as('binary').readUInt8(0);
}; };
// get or set the payload data (as a Buffer object) // get or set the payload data (as a Buffer object)
VersionedData.prototype.payload = function(data) { VersionedData.prototype.payload = function(data) {
if(data) { if(data) {
this.doAsBinary(function() {data.copy(this.data,1);}); this.doAsBinary(function() {data.copy(this.data,1);});
return data; return data;
} }
return this.as('binary').slice(1); return this.as('binary').slice(1);
};
return VersionedData;
}; };
module.defineClass(ClassSpec);
module.exports = require('soop')(VersionedData);