all classes working with soop and test passing

This commit is contained in:
Matias Alejo Garcia 2014-03-05 16:11:16 -03:00
parent fa1e323d39
commit c0c325dabd
38 changed files with 4700 additions and 4763 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) {
var superclass = b.superclass || require('./util/VersionedData').class();
function Address() {
function Address() {
Address.super(this, arguments);
}
}
Address.superclass = superclass;
superclass.applyEncodingsTo(Address);
Address.parent = parent;
parent.applyEncodingsTo(Address);
Address.prototype.validate = function() {
Address.prototype.validate = function() {
this.doAsBinary(function() {
Address.super(this, 'validate', arguments);
if(this.data.length !== 21) throw new Error('invalid data length');
});
};
};
return Address;
}
module.defineClass(ClassSpec);
module.exports = require('soop')(Address);

193
Block.js
View File

@ -1,25 +1,24 @@
require('classtool');
var imports = require('soop').imports();
function spec(b) {
var util = b.util || require('./util/util');
var Debug1 = b.Debug1 || function() {};
var Script = b.Script || require('./Script').class();
var Bignum = b.Bignum || require('bignum');
var Binary = b.Binary || require('binary');
var Step = b.Step || require('step');
var buffertools = b.buffertools || require('buffertools');
var Transaction = b.Transaction || require('./Transaction').class();
var TransactionIn = Transaction.In;
var TransactionOut = Transaction.Out;
var COINBASE_OP = Transaction.COINBASE_OP;
var VerificationError = b.VerificationError || require('./util/error').VerificationError;
var BlockRules = {
var util = imports.util || require('./util/util');
var Debug1 = imports.Debug1 || function() {};
var Script = imports.Script || require('./Script');
var Bignum = imports.Bignum || require('bignum');
var Binary = imports.Binary || require('binary');
var Step = imports.Step || require('step');
var buffertools = imports.buffertools || require('buffertools');
var Transaction = imports.Transaction || require('./Transaction');
var TransactionIn = Transaction.In;
var TransactionOut = Transaction.Out;
var COINBASE_OP = Transaction.COINBASE_OP;
var VerificationError = imports.VerificationError || require('./util/error').VerificationError;
var BlockRules = {
maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future
largestHash: Bignum(2).pow(256)
};
};
function Block(data)
{
function Block(data)
{
if ("object" !== typeof data) {
data = {};
}
@ -35,9 +34,9 @@ function spec(b) {
this.active = data.active || false;
this.chainWork = data.chainWork || util.EMPTY_BUFFER;
this.txs = data.txs || [];
}
}
Block.prototype.getHeader = function getHeader() {
Block.prototype.getHeader = function getHeader() {
var buf = new Buffer(80);
var ofs = 0;
buf.writeUInt32LE(this.version, ofs); ofs += 4;
@ -47,9 +46,9 @@ function spec(b) {
buf.writeUInt32LE(this.bits, ofs); ofs += 4;
buf.writeUInt32LE(this.nonce, ofs); ofs += 4;
return buf;
};
};
Block.prototype.parse = function parse(parser, headerOnly) {
Block.prototype.parse = function parse(parser, headerOnly) {
this.version = parser.word32le();
this.prev_hash = parser.buffer(32);
this.merkle_root = parser.buffer(32);
@ -70,26 +69,26 @@ function spec(b) {
tx.parse(parser);
this.txs.push(tx);
}
};
};
Block.prototype.calcHash = function calcHash() {
Block.prototype.calcHash = function calcHash() {
var header = this.getHeader();
return util.twoSha256(header);
};
};
Block.prototype.checkHash = function checkHash() {
Block.prototype.checkHash = function checkHash() {
if (!this.hash || !this.hash.length) return false;
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();
return this.hash;
};
};
Block.prototype.checkProofOfWork = function checkProofOfWork() {
Block.prototype.checkProofOfWork = function checkProofOfWork() {
var target = util.decodeDiffBits(this.bits);
// TODO: Create a compare method in node-buffertools that uses the correct
@ -104,30 +103,30 @@ function spec(b) {
buffertools.reverse(this.hash);
return true;
};
};
/**
/**
* Returns the amount of work that went into this block.
*
* 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%
* 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);
return BlockRules.largestHash.div(target.add(1));
};
};
Block.prototype.checkTimestamp = function checkTimestamp() {
Block.prototype.checkTimestamp = function checkTimestamp() {
var currentTime = new Date().getTime() / 1000;
if (this.timestamp > currentTime + BlockRules.maxTimeOffset) {
throw new VerificationError('Timestamp too far into the future');
}
return true;
};
};
Block.prototype.checkTransactions = function checkTransactions(txs) {
Block.prototype.checkTransactions = function checkTransactions(txs) {
if (!Array.isArray(txs) || txs.length <= 0) {
throw new VerificationError('No transactions');
}
@ -141,15 +140,15 @@ function spec(b) {
}
return true;
};
};
/**
/**
* Build merkle tree.
*
* Ported from Java. Original code: BitcoinJ by Mike Hearn
* 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:
//
// merkleHash
@ -188,14 +187,14 @@ function spec(b) {
}
return tree;
};
};
Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) {
Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) {
var tree = this.getMerkleTree(txs);
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) {
throw new VerificationError('No merkle root');
}
@ -205,9 +204,9 @@ function spec(b) {
}
return true;
};
};
Block.prototype.checkBlock = function checkBlock(txs) {
Block.prototype.checkBlock = function checkBlock(txs) {
if (!this.checkHash()) {
throw new VerificationError("Block hash invalid");
}
@ -221,31 +220,31 @@ function spec(b) {
}
}
return true;
};
};
Block.getBlockValue = function getBlockValue(height) {
Block.getBlockValue = function getBlockValue(height) {
var subsidy = Bignum(50).mul(util.COIN);
subsidy = subsidy.div(Bignum(2).pow(Math.floor(height / 210000)));
return subsidy;
};
};
Block.prototype.getBlockValue = function getBlockValue() {
Block.prototype.getBlockValue = function getBlockValue() {
return Block.getBlockValue(this.height);
};
};
Block.prototype.toString = function toString() {
Block.prototype.toString = function toString() {
return "<Block " + util.formatHashAlt(this.hash) + " height="+this.height+">";
};
};
/**
/**
* 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.setChainWork(parent.getChainWork().add(this.getWork()));
};
};
Block.prototype.setChainWork = function setChainWork(chainWork) {
Block.prototype.setChainWork = function setChainWork(chainWork) {
if (Buffer.isBuffer(chainWork)) {
// Nothing to do
} else if ("function" === typeof chainWork.toBuffer) { // duck-typing bignum
@ -255,24 +254,24 @@ function spec(b) {
}
this.chainWork = chainWork;
};
};
Block.prototype.getChainWork = function getChainWork() {
Block.prototype.getChainWork = function getChainWork() {
return Bignum.fromBuffer(this.chainWork);
};
};
/**
/**
* 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;
};
};
/**
/**
* Returns the difficulty target for the next block after this one.
*/
Block.prototype.getNextWork =
function getNextWork(blockChain, nextBlock, callback) {
Block.prototype.getNextWork =
function getNextWork(blockChain, nextBlock, callback) {
var self = this;
var powLimit = blockChain.getMinDiff();
@ -371,13 +370,13 @@ function spec(b) {
}
);
}
};
};
var medianTimeSpan = 11;
var medianTimeSpan = 11;
Block.prototype.getMedianTimePast =
function getMedianTimePast(blockChain, callback)
{
Block.prototype.getMedianTimePast =
function getMedianTimePast(blockChain, callback)
{
var self = this;
Step(
@ -407,11 +406,11 @@ function spec(b) {
},
callback
);
};
};
Block.prototype.verifyChild =
function verifyChild(blockChain, child, callback)
{
Block.prototype.verifyChild =
function verifyChild(blockChain, child, callback)
{
var self = this;
Step(
@ -444,11 +443,11 @@ function spec(b) {
},
callback
);
};
};
Block.prototype.createCoinbaseTx =
function createCoinbaseTx(beneficiary)
{
Block.prototype.createCoinbaseTx =
function createCoinbaseTx(beneficiary)
{
var tx = new Transaction();
tx.ins.push(new TransactionIn({
s: util.EMPTY_BUFFER,
@ -460,11 +459,11 @@ function spec(b) {
s: Script.createPubKeyOut(beneficiary).getBuffer()
}));
return tx;
};
};
Block.prototype.prepareNextBlock =
function prepareNextBlock(blockChain, beneficiary, time, callback)
{
Block.prototype.prepareNextBlock =
function prepareNextBlock(blockChain, beneficiary, time, callback)
{
var self = this;
var newBlock = new Block();
@ -512,11 +511,11 @@ function spec(b) {
},
callback
);
};
};
Block.prototype.mineNextBlock =
function mineNextBlock(blockChain, beneficiary, time, miner, callback)
{
Block.prototype.mineNextBlock =
function mineNextBlock(blockChain, beneficiary, time, miner, callback)
{
this.prepareNextBlock(blockChain, beneficiary, time, function (err, data) {
try {
if (err) throw err;
@ -539,20 +538,20 @@ function spec(b) {
callback(e);
}
});
};
};
Block.prototype.solve = function solve(miner, callback) {
Block.prototype.solve = function solve(miner, callback) {
var header = this.getHeader();
var target = util.decodeDiffBits(this.bits);
miner.solve(header, target, callback);
};
};
/**
/**
* Returns an object with the same field names as jgarzik's getblock patch.
*/
Block.prototype.getStandardizedObject =
function getStandardizedObject(txs)
{
Block.prototype.getStandardizedObject =
function getStandardizedObject(txs)
{
var block = {
hash: util.formatHashFull(this.getHash()),
version: this.version,
@ -587,8 +586,6 @@ function spec(b) {
block.size = this.size;
}
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) {
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() {
function Bloom() {
this.data = '';
this.hashFuncs = 0;
};
};
function ROTL32(x, r) {
function ROTL32(x, r) {
return (x << r) | (x >> (32 - r));
};
};
function getBlockU32(blockIdx, data) {
function getBlockU32(blockIdx, data) {
var idx = blockIdx * 4;
var v = (data[idx + 0] << (0 * 8)) |
(data[idx + 1] << (1 * 8)) |
(data[idx + 2] << (2 * 8)) |
(data[idx + 3] << (3 * 8));
return v;
};
};
Bloom.prototype.hash = function(hashNum, data) {
Bloom.prototype.hash = function(hashNum, data) {
var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1));
var c1 = 0xcc9e2d51;
var c2 = 0x1b873593;
@ -68,16 +65,16 @@ function ClassSpec(b) {
h1 ^= h1 >> 16;
return h1 % (this.data.length * 8);
};
};
Bloom.prototype.insert = function(data) {
Bloom.prototype.insert = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
this.data[index >> 3] |= bit_mask[7 & index];
}
};
};
Bloom.prototype.contains = function(data) {
Bloom.prototype.contains = function(data) {
for (var i = 0; i < this.hashFuncs; i++) {
var index = this.hash(i, data);
if (!(this.data[index >> 3] & bit_mask[7 & index]))
@ -85,32 +82,30 @@ function ClassSpec(b) {
}
return true;
};
};
Bloom.prototype.sizeOk = function() {
Bloom.prototype.sizeOk = function() {
return this.data.length <= MAX_BLOOM_FILTER_SIZE &&
this.hashFuncs <= MAX_HASH_FUNCS;
};
};
function toInt(v) {
function toInt(v) {
return ~~v;
}
}
function min(a, b) {
function min(a, b) {
if (a < b)
return a;
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)),
MAX_BLOOM_FILTER_SIZE * 8) / 8;
this.data[filterSize] = 0;
this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2),
MAX_HASH_FUNCS);
};
return Bloom;
};
module.defineClass(ClassSpec);
module.exports = require('soop')(Bloom);

View File

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

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

35
Peer.js
View File

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

View File

@ -1,20 +1,19 @@
require('classtool');
function spec(b) {
var config = b.config || require('./config');
var log = b.log || require('./util/log');
var network = b.network || require('./networks')[config.network];
var Connection = b.Connection || require('./Connection').createClass(
{config: config, network: network});
var Peer = b.Peer || require('./Peer').class();
var noop = function() {};
var imports = require('soop').imports();
var config = imports.config || require('./config');
var log = imports.log || require('./util/log');
var network = imports.network || require('./networks')[config.network];
var Connection = imports.Connection ||
require('soop').load('./Connection', {config: config, network: network});
GetAdjustedTime = b.GetAdjustedTime || function () {
var Peer = imports.Peer || require('./Peer');
GetAdjustedTime = imports.GetAdjustedTime || function () {
// TODO: Implement actual adjustment
return Math.floor(new Date().getTime() / 1000);
};
};
function PeerManager() {
function PeerManager() {
this.active = false;
this.timer = null;
@ -27,19 +26,19 @@ function spec(b) {
this.interval = 5000;
this.minConnections = 8;
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;
if(!this.timer) {
this.timer = setInterval(this.checkStatus.bind(this), this.interval);
}
};
};
PeerManager.prototype.stop = function() {
PeerManager.prototype.stop = function() {
this.active = false;
if(this.timer) {
clearInterval(this.timer);
@ -48,9 +47,9 @@ function spec(b) {
for(var i=0; i<this.connections.length; i++) {
this.connections[i].socket.end();
};
};
};
PeerManager.prototype.addPeer = function(peer, port) {
PeerManager.prototype.addPeer = function(peer, port) {
if(peer instanceof Peer) {
this.peers.push(peer);
} else if ("string" == typeof peer) {
@ -60,9 +59,9 @@ function spec(b) {
{val: 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
if(this.peers.length) {
var peerIndex = {};
@ -82,9 +81,9 @@ function spec(b) {
this.connectTo(peerIndex[i]);
}.bind(this));
}
};
};
PeerManager.prototype.connectTo = function(peer) {
PeerManager.prototype.connectTo = function(peer) {
log.info('connecting to '+peer);
try {
return this.addConnection(peer.createConnection(), peer);
@ -92,9 +91,9 @@ function spec(b) {
log.err('creating connection',e);
return null;
}
};
};
PeerManager.prototype.addConnection = function(socketConn, peer) {
PeerManager.prototype.addConnection = function(socketConn, peer) {
var conn = new Connection(socketConn, peer);
this.connections.push(conn);
this.emit('connection', conn);
@ -107,9 +106,9 @@ function spec(b) {
conn.addListener('disconnect', this.handleDisconnect.bind(this));
return conn;
};
};
PeerManager.prototype.handleVersion = function(e) {
PeerManager.prototype.handleVersion = function(e) {
if (!e.conn.inbound) {
// TODO: Advertise our address (if listening)
}
@ -119,9 +118,9 @@ function spec(b) {
e.conn.sendGetAddr();
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);
this.emit('connect', {
pm: this,
@ -134,9 +133,9 @@ function spec(b) {
this.emit('netConnected');
this.isConnected = true;
}
};
};
PeerManager.prototype.handleAddr = function (e) {
PeerManager.prototype.handleAddr = function (e) {
if(!this.peerDiscovery) return;
var now = GetAdjustedTime();
@ -160,18 +159,18 @@ function spec(b) {
if (e.message.addrs.length < 1000 ) {
e.conn.getaddr = false;
}
};
};
PeerManager.prototype.handleGetAddr = function(e) {
PeerManager.prototype.handleGetAddr = function(e) {
// TODO: Reply with addr message.
};
};
PeerManager.prototype.handleError = function(e) {
PeerManager.prototype.handleError = function(e) {
log.err('unkown error with peer '+e.peer+' (disconnecting): '+e.err);
this.handleDisconnect.apply(this, [].slice.call(arguments));
};
};
PeerManager.prototype.handleDisconnect = function(e) {
PeerManager.prototype.handleDisconnect = function(e) {
log.info('disconnected from peer '+e.peer);
var i = this.connections.indexOf(e.conn);
if(i != -1) this.connections.splice(i, 1);
@ -180,9 +179,9 @@ function spec(b) {
this.emit('netDisconnected');
this.isConnected = false;
}
};
};
PeerManager.prototype.getActiveConnection = function () {
PeerManager.prototype.getActiveConnection = function () {
var activeConnections = this.connections.filter(function (conn) {
return conn.active;
});
@ -204,12 +203,10 @@ function spec(b) {
} else {
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 superclass = b.superclass || require('./util/VersionedData').class();
var parent = imports.parent || require('./util/VersionedData');
//compressed is true if public key is compressed; false otherwise
function PrivateKey(version, buf, compressed) {
//compressed is true if public key is compressed; false otherwise
function PrivateKey(version, buf, compressed) {
PrivateKey.super(this, arguments);
if (compressed !== undefined)
this.compressed(compressed);
};
};
PrivateKey.superclass = superclass;
superclass.applyEncodingsTo(PrivateKey);
PrivateKey.parent = parent;
parent.applyEncodingsTo(PrivateKey);
PrivateKey.prototype.validate = function() {
PrivateKey.prototype.validate = function() {
this.doAsBinary(function() {
PrivateKey.super(this, 'validate', arguments);
if (this.data.length < 32 || (this.data.length > 1+32 && !this.compressed()) || (this.data.length==1+32+1 && this.data[1+32+1-1]!=1) || this.data.length>1+32+1)
throw new Error('invalid data length');
});
};
};
// get or set the payload data (as a Buffer object)
// overloaded from VersionedData
PrivateKey.prototype.payload = function(data) {
// get or set the payload data (as a Buffer object)
// overloaded from VersionedData
PrivateKey.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data,1);});
return data;
@ -33,10 +32,10 @@ function ClassSpec(b) {
return buf.slice(1,1+32);
else if (buf.length==1+32)
return buf.slice(1);
};
};
// get or set whether the corresponding public key is compressed
PrivateKey.prototype.compressed = function(compressed) {
// get or set whether the corresponding public key is compressed
PrivateKey.prototype.compressed = function(compressed) {
if (compressed !== undefined) {
this.doAsBinary(function(){
var len=1+32+1;
@ -60,8 +59,6 @@ function ClassSpec(b) {
else
throw new Error('invalid private key');
}
};
return PrivateKey;
};
module.defineClass(ClassSpec);
module.exports = require('soop')(PrivateKey);

View File

@ -1,14 +1,13 @@
// RpcClient.js
// MIT/X11-like license. See LICENSE.txt.
// Copyright 2013 BitPay, Inc.
require('classtool');
//
var imports = require('soop').imports();
var http = imports.http || require('http');
var https = imports.https || require('https');
var log = imports.log || require('./util/log');
function ClassSpec(b) {
var http = b.http || require('http');
var https = b.https || require('https');
var log = b.log || require('./util/log');
function RpcClient(opts) {
function RpcClient(opts) {
opts = opts || {};
this.host = opts.host || '127.0.0.1';
this.port = opts.port || 8332;
@ -17,16 +16,16 @@ function ClassSpec(b) {
this.protocol = (opts.protocol == 'http') ? http : https;
this.batchedCalls = null;
this.disableAgent = opts.disableAgent || false;
}
}
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
RpcClient.prototype.batch = function(batchCallback, resultCallback) {
this.batchedCalls = [];
batchCallback();
rpc.call(this, this.batchedCalls, resultCallback);
this.batchedCalls = null;
}
}
var callspec = {
var callspec = {
addMultiSigAddress: '',
addNode: '',
backupWallet: '',
@ -93,13 +92,13 @@ function ClassSpec(b) {
walletLock: '',
walletPassPhrase: 'string int',
walletPassphraseChange: '',
};
};
var slice = function(arr, start, end) {
var slice = function(arr, start, end) {
return Array.prototype.slice.call(arr, start, end);
};
};
function generateRPCMethods(constructor, apiCalls, rpc) {
function generateRPCMethods(constructor, apiCalls, rpc) {
function createRPCMethod(methodName, argMap) {
return function() {
var limit = arguments.length - 1;
@ -137,9 +136,9 @@ function ClassSpec(b) {
constructor.prototype[methodName] = constructor.prototype[k];
}
}
}
}
function rpc(request, callback) {
function rpc(request, callback) {
var self = this;
var request;
request = JSON.stringify(request);
@ -201,10 +200,9 @@ function ClassSpec(b) {
req.setHeader('Authorization', 'Basic ' + auth);
req.write(request);
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) {
var superclass = b.superclass || require('./util/VersionedData').class();
function SIN(type, payload) {
function SIN(type, payload) {
if (typeof type != 'number') {
SIN.super(this, arguments);
return;
@ -14,47 +11,45 @@ function ClassSpec(b) {
this.prefix(0x0F); // SIN magic number, in numberspace
this.type(type);
this.payload(payload);
};
SIN.superclass = superclass;
superclass.applyEncodingsTo(SIN);
};
SIN.parent = parent;
parent.applyEncodingsTo(SIN);
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX
SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX
SIN.SIN_EPHEM = 0x02; // generate off-net at any time
// get or set the prefix data (the first byte of the address)
SIN.prototype.prefix = function(num) {
// get or set the prefix data (the first byte of the address)
SIN.prototype.prefix = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
};
// get or set the SIN-type data (the second byte of the address)
SIN.prototype.type = function(num) {
// get or set the SIN-type data (the second byte of the address)
SIN.prototype.type = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 1);});
return num;
}
return this.as('binary').readUInt8(1);
};
};
// get or set the payload data (as a Buffer object)
SIN.prototype.payload = function(data) {
// get or set the payload data (as a Buffer object)
SIN.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data, 2);});
return data;
}
return this.as('binary').slice(1);
};
};
SIN.prototype.validate = function() {
SIN.prototype.validate = function() {
this.doAsBinary(function() {
SIN.super(this, 'validate', arguments);
if (this.data.length != 22) throw new Error('invalid data length');
});
};
return SIN;
};
module.defineClass(ClassSpec);
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) {
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var SIN = require('./SIN').class();
function SINKey(cfg) {
function SINKey(cfg) {
if (typeof cfg != 'object')
cfg = {};
this.created = cfg.created;
this.privKey = cfg.privKey;
};
};
SINKey.prototype.generate = function() {
SINKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
};
SINKey.prototype.pubkeyHash = function() {
SINKey.prototype.pubkeyHash = function() {
return coinUtil.sha256ripe160(this.privKey.public);
};
};
SINKey.prototype.storeObj = function() {
SINKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = this.pubkeyHash();
var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash);
@ -35,9 +32,6 @@ function ClassSpec(b) {
};
return obj;
};
return SINKey;
};
module.defineClass(ClassSpec);
module.exports = require('soop')(SINKey);

290
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) {
var config = b.config || require('./config');
var log = b.log || require('./util/log');
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval(i + ' = ' + Opcode.map[i] + ';');
}
var Opcode = b.Opcode || require('./Opcode').class();
var buffertools = b.buffertools || require('buffertools');
var util = imports.util || require('./util/util');
var Parser = imports.Parser || require('./util/BinaryParser');
var Put = imports.Put || require('bufferput');
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval(i + " = " + Opcode.map[i] + ";");
}
var TX_UNKNOWN = 0;
var TX_PUBKEY = 1;
var TX_PUBKEYHASH = 2;
var TX_MULTISIG = 3;
var TX_SCRIPTHASH = 4;
var util = b.util || require('./util/util');
var Parser = b.Parser || require('./util/BinaryParser').class();
var Put = b.Put || require('bufferput');
var TX_UNKNOWN = 0;
var TX_PUBKEY = 1;
var TX_PUBKEYHASH = 2;
var TX_MULTISIG = 3;
var TX_SCRIPTHASH = 4;
var TX_TYPES = [
var TX_TYPES = [
'unknown',
'pubkey',
'pubkeyhash',
'multisig',
'scripthash'
];
];
function Script(buffer) {
function Script(buffer) {
if(buffer) {
this.buffer = buffer;
} else {
@ -38,16 +35,16 @@ function spec(b) {
}
this.chunks = [];
this.parse();
};
this.class = Script;
};
this.class = Script;
Script.TX_UNKNOWN=TX_UNKNOWN;
Script.TX_PUBKEY=TX_PUBKEY;
Script.TX_PUBKEYHASH=TX_PUBKEYHASH;
Script.TX_MULTISIG=TX_MULTISIG;
Script.TX_SCRIPTHASH=TX_SCRIPTHASH;
Script.TX_UNKNOWN=TX_UNKNOWN;
Script.TX_PUBKEY=TX_PUBKEY;
Script.TX_PUBKEYHASH=TX_PUBKEYHASH;
Script.TX_MULTISIG=TX_MULTISIG;
Script.TX_SCRIPTHASH=TX_SCRIPTHASH;
Script.prototype.parse = function () {
Script.prototype.parse = function () {
this.chunks = [];
var parser = new Parser(this.buffer);
@ -71,35 +68,35 @@ function spec(b) {
this.chunks.push(opcode);
}
}
};
};
Script.prototype.isPushOnly = function ()
{
Script.prototype.isPushOnly = function ()
{
for (var i = 0; i < this.chunks.length; i++)
if (!Buffer.isBuffer(this.chunks[i]))
return false;
return true;
};
};
Script.prototype.isP2SH = function ()
{
Script.prototype.isP2SH = function ()
{
return (this.chunks.length == 3 &&
this.chunks[0] == OP_HASH160 &&
Buffer.isBuffer(this.chunks[1]) &&
this.chunks[1].length == 20 &&
this.chunks[2] == OP_EQUAL);
};
};
Script.prototype.isPubkey = function ()
{
Script.prototype.isPubkey = function ()
{
return (this.chunks.length == 2 &&
Buffer.isBuffer(this.chunks[0]) &&
this.chunks[1] == OP_CHECKSIG);
};
};
Script.prototype.isPubkeyHash = function ()
{
Script.prototype.isPubkeyHash = function ()
{
return (this.chunks.length == 5 &&
this.chunks[0] == OP_DUP &&
this.chunks[1] == OP_HASH160 &&
@ -107,24 +104,24 @@ function spec(b) {
this.chunks[2].length == 20 &&
this.chunks[3] == OP_EQUALVERIFY &&
this.chunks[4] == OP_CHECKSIG);
};
};
function isSmallIntOp(opcode)
{
function isSmallIntOp(opcode)
{
return ((opcode == OP_0) ||
((opcode >= OP_1) && (opcode <= OP_16)));
};
};
Script.prototype.isMultiSig = function ()
{
Script.prototype.isMultiSig = function ()
{
return (this.chunks.length > 3 &&
isSmallIntOp(this.chunks[0]) &&
isSmallIntOp(this.chunks[this.chunks.length-2]) &&
this.chunks[this.chunks.length-1] == OP_CHECKMULTISIG);
};
};
Script.prototype.finishedMultiSig = function()
{
Script.prototype.finishedMultiSig = function()
{
var nsigs = 0;
for (var i = 0; i < this.chunks.length-1; i++)
if (this.chunks[i] !== 0)
@ -138,10 +135,10 @@ function spec(b) {
return true;
else
return false;
}
}
Script.prototype.removePlaceHolders = function()
{
Script.prototype.removePlaceHolders = function()
{
var chunks = [];
for (var i in this.chunks)
{
@ -154,10 +151,10 @@ function spec(b) {
this.chunks = chunks;
this.updateBuffer();
return this;
}
}
Script.prototype.prependOp0 = function()
{
Script.prototype.prependOp0 = function()
{
var chunks = [0];
for (i in this.chunks) {
if (this.chunks.hasOwnProperty(i)) {
@ -167,74 +164,74 @@ function spec(b) {
this.chunks = chunks;
this.updateBuffer();
return this;
}
}
// is this a script form we know?
Script.prototype.classify = function ()
{
// is this a script form we know?
Script.prototype.classify = function ()
{
if (this.isPubkeyHash())
return TX_PUBKEYHASH;
if (this.isP2SH())
if (this.isP2SH())
return TX_SCRIPTHASH;
if (this.isMultiSig())
if (this.isMultiSig())
return TX_MULTISIG;
if (this.isPubkey())
if (this.isPubkey())
return TX_PUBKEY;
return TX_UNKNOWN;
};
return TX_UNKNOWN;
};
// extract useful data items from known scripts
Script.prototype.capture = function ()
{
// extract useful data items from known scripts
Script.prototype.capture = function ()
{
var txType = this.classify();
var res = [];
switch (txType) {
case TX_PUBKEY:
var res = [];
switch (txType) {
case TX_PUBKEY:
res.push(this.chunks[0]);
break;
case TX_PUBKEYHASH:
case TX_PUBKEYHASH:
res.push(this.chunks[2]);
break;
case TX_MULTISIG:
case TX_MULTISIG:
for (var i = 1; i < (this.chunks.length - 2); i++)
res.push(this.chunks[i]);
break;
case TX_SCRIPTHASH:
case TX_SCRIPTHASH:
res.push(this.chunks[1]);
break;
case TX_UNKNOWN:
default:
case TX_UNKNOWN:
default:
// do nothing
break;
}
}
return res;
};
return res;
};
// return first extracted data item from script
Script.prototype.captureOne = function ()
{
// return first extracted data item from script
Script.prototype.captureOne = function ()
{
var arr = this.capture();
return arr[0];
};
return arr[0];
};
Script.prototype.getOutType = function ()
{
Script.prototype.getOutType = function ()
{
var txType = this.classify();
switch (txType) {
case TX_PUBKEY: return 'Pubkey';
case TX_PUBKEYHASH: return 'Address';
default: return 'Strange';
}
};
};
Script.prototype.getRawOutType = function() {
Script.prototype.getRawOutType = function() {
return TX_TYPES[this.classify()];
};
};
Script.prototype.simpleOutHash = function ()
{
Script.prototype.simpleOutHash = function ()
{
switch (this.getOutType()) {
case 'Address':
return this.chunks[2];
@ -245,10 +242,10 @@ function spec(b) {
log.debug("Strange script was: " + this.toString());
return null;
}
};
};
Script.prototype.getInType = function ()
{
Script.prototype.getInType = function ()
{
if (this.chunks.length == 1) {
// Direct IP to IP transactions only have the public key in their scriptSig.
return 'Pubkey';
@ -259,10 +256,10 @@ function spec(b) {
} else {
return 'Strange';
}
};
};
Script.prototype.simpleInPubKey = function ()
{
Script.prototype.simpleInPubKey = function ()
{
switch (this.getInType()) {
case 'Address':
return this.chunks[1];
@ -273,15 +270,15 @@ function spec(b) {
log.debug("Strange script was: " + this.toString());
return null;
}
};
};
Script.prototype.getBuffer = function ()
{
Script.prototype.getBuffer = function ()
{
return this.buffer;
};
};
Script.prototype.getStringContent = function (truncate, maxEl)
{
Script.prototype.getStringContent = function (truncate, maxEl)
{
if (truncate === null) {
truncate = true;
}
@ -310,19 +307,19 @@ function spec(b) {
}
}
return script;
};
};
Script.prototype.toString = function (truncate, maxEl)
{
Script.prototype.toString = function (truncate, maxEl)
{
var script = "<Script ";
script += this.getStringContent(truncate, maxEl);
script += ">";
return script;
};
};
Script.prototype.writeOp = function (opcode)
{
Script.prototype.writeOp = function (opcode)
{
var buf = Buffer(this.buffer.length + 1);
this.buffer.copy(buf);
buf.writeUInt8(opcode, this.buffer.length);
@ -330,10 +327,10 @@ function spec(b) {
this.buffer = buf;
this.chunks.push(opcode);
};
};
Script.prototype.writeN = function (n)
{
Script.prototype.writeN = function (n)
{
if (n < 0 || n > 16)
throw new Error("writeN: out of range value " + n);
@ -341,10 +338,10 @@ function spec(b) {
this.writeOp(OP_0);
else
this.writeOp(OP_1 + n - 1);
};
};
function prefixSize(data_length)
{
function prefixSize(data_length)
{
if (data_length < OP_PUSHDATA1) {
return 1;
} else if (data_length <= 0xff) {
@ -354,9 +351,9 @@ function spec(b) {
} else {
return 1 + 4;
}
};
};
function encodeLen(data_length) {
function encodeLen(data_length) {
var buf = undefined;
if (data_length < OP_PUSHDATA1) {
buf = new Buffer(1);
@ -382,22 +379,22 @@ function spec(b) {
}
return buf;
};
};
Script.prototype.writeBytes = function (data)
{
Script.prototype.writeBytes = function (data)
{
var newSize = this.buffer.length + prefixSize(data.length) + data.length;
this.buffer = Buffer.concat([this.buffer, encodeLen(data.length), data]);
this.chunks.push(data);
};
};
Script.prototype.updateBuffer = function ()
{
Script.prototype.updateBuffer = function ()
{
this.buffer = Script.chunksToBuffer(this.chunks);
};
};
Script.prototype.findAndDelete = function (chunk)
{
Script.prototype.findAndDelete = function (chunk)
{
var dirty = false;
if (Buffer.isBuffer(chunk)) {
for (var i = 0, l = this.chunks.length; i < l; i++) {
@ -420,25 +417,25 @@ function spec(b) {
if (dirty) {
this.updateBuffer();
}
};
};
/**
/**
* Creates a simple OP_CHECKSIG with pubkey output script.
*
* These are used for coinbase transactions and at some point were used for
* IP-based transactions as well.
*/
Script.createPubKeyOut = function (pubkey) {
Script.createPubKeyOut = function (pubkey) {
var script = new Script();
script.writeBytes(pubkey);
script.writeOp(OP_CHECKSIG);
return script;
};
};
/**
/**
* Creates a standard txout script.
*/
Script.createPubKeyHashOut = function (pubKeyHash) {
Script.createPubKeyHashOut = function (pubKeyHash) {
var script = new Script();
script.writeOp(OP_DUP);
script.writeOp(OP_HASH160);
@ -446,9 +443,9 @@ function spec(b) {
script.writeOp(OP_EQUALVERIFY);
script.writeOp(OP_CHECKSIG);
return script;
};
};
Script.createMultisig = function(n_required, keys) {
Script.createMultisig = function(n_required, keys) {
var script = new Script();
script.writeN(n_required);
keys.forEach(function(key) {
@ -457,17 +454,17 @@ function spec(b) {
script.writeN(keys.length);
script.writeOp(OP_CHECKMULTISIG);
return script;
};
};
Script.createP2SH = function(scriptHash) {
Script.createP2SH = function(scriptHash) {
var script = new Script();
script.writeOp(OP_HASH160);
script.writeBytes(scriptHash);
script.writeOp(OP_EQUAL);
return script;
};
};
Script.fromTestData = function (testData) {
Script.fromTestData = function (testData) {
testData = testData.map(function (chunk) {
if ("string" === typeof chunk) {
return new Buffer(chunk, 'hex');
@ -480,16 +477,16 @@ function spec(b) {
script.chunks = testData;
script.updateBuffer();
return script;
};
};
Script.fromChunks = function (chunks) {
Script.fromChunks = function (chunks) {
var script = new Script();
script.chunks = chunks;
script.updateBuffer();
return script;
};
};
Script.chunksToBuffer = function (chunks) {
Script.chunksToBuffer = function (chunks) {
var buf = new Put();
for (var i = 0, l = chunks.length; i < l; i++) {
@ -515,9 +512,6 @@ function spec(b) {
}
}
return buf.buffer();
};
return Script;
};
module.defineClass(spec);
module.exports = require('soop')(Script);

View File

@ -1,29 +1,27 @@
require('classtool');
var imports = require('soop').imports();
function spec(b) {
var assert = require('assert');
var config = b.config || require('./config');
var log = b.log || require('./util/log');
var assert = require('assert');
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 Opcode = b.Opcode || require('./Opcode').class();
var buffertools = b.buffertools || require('buffertools');
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
// Make opcodes available as pseudo-constants
for (var i in Opcode.map) {
eval(i + " = " + Opcode.map[i] + ";");
}
}
var bignum = b.bignum || require('bignum');
var Util = b.Util || require('./util/util');
var Script = require('./Script').class();
var bignum = imports.bignum || require('bignum');
var Util = imports.Util || require('./util/util');
var Script = require('./Script');
function ScriptInterpreter() {
function ScriptInterpreter() {
this.stack = [];
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) {
throw new Error("ScriptInterpreter.eval() requires a callback");
}
@ -726,11 +724,11 @@ function spec(b) {
cb(e);
}
}
};
};
ScriptInterpreter.prototype.evalTwo =
function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback)
{
ScriptInterpreter.prototype.evalTwo =
function evalTwo(scriptSig, scriptPubkey, tx, n, hashType, callback)
{
var self = this;
self.eval(scriptSig, tx, n, hashType, function (e) {
@ -741,15 +739,15 @@ function spec(b) {
self.eval(scriptPubkey, tx, n, hashType, callback);
});
};
};
/**
/**
* Get the top element of the stack.
*
* Using the offset parameter this function can also access lower elements
* from the stack.
*/
ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
ScriptInterpreter.prototype.stackTop = function stackTop(offset) {
offset = +offset || 1;
if (offset < 1) offset = 1;
@ -758,25 +756,25 @@ function spec(b) {
}
return this.stack[this.stack.length-offset];
};
};
ScriptInterpreter.prototype.stackBack = function stackBack()
{
ScriptInterpreter.prototype.stackBack = function stackBack()
{
return this.stack[-1];
};
};
/**
/**
* 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) {
throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
}
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) {
throw new Error('ScriptInterpreter.stackTop(): Stack underrun');
}
@ -787,15 +785,15 @@ function spec(b) {
var tmp = s[l - a];
s[l - a] = s[l - b];
s[l - b] = tmp;
};
};
/**
/**
* Returns a version of the stack with only primitive types.
*
* The return value is an array. Any single byte buffer is converted to an
* 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) {
if (entry.length > 2) {
return buffertools.toHex(entry.slice(0));
@ -807,9 +805,9 @@ function spec(b) {
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++) {
if (v[i] != 0) {
// Negative zero is still zero
@ -820,11 +818,11 @@ function spec(b) {
}
}
return false;
};
var castInt = ScriptInterpreter.castInt = function castInt(v) {
};
var castInt = ScriptInterpreter.castInt = function castInt(v) {
return castBigint(v).toNumber();
};
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
};
var castBigint = ScriptInterpreter.castBigint = function castBigint(v) {
if (!v.length) {
return bignum(0);
}
@ -844,8 +842,8 @@ function spec(b) {
// Positive number
return bignum.fromBuffer(w);
}
};
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
};
var bigintToBuffer = ScriptInterpreter.bigintToBuffer = function bigintToBuffer(v) {
if ("number" === typeof v) {
v = bignum(v);
}
@ -877,19 +875,19 @@ function spec(b) {
return buffertools.reverse(b);
}
}
};
};
ScriptInterpreter.prototype.getResult = function getResult() {
ScriptInterpreter.prototype.getResult = function getResult() {
if (this.stack.length === 0) {
throw new Error("Empty stack after script evaluation");
}
return castBool(this.stack[this.stack.length-1]);
};
};
ScriptInterpreter.verify =
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback)
{
ScriptInterpreter.verify =
function verify(scriptSig, scriptPubKey, txTo, n, hashType, callback)
{
if ("function" !== typeof callback) {
throw new Error("ScriptInterpreter.verify() requires a callback");
}
@ -916,92 +914,92 @@ function spec(b) {
});
return si;
};
};
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
function verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy)
{
if (siCopy.stack.length == 0) {
{
if (siCopy.stack.length == 0) {
callback(null, false);
return;
}
}
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)
{
if (si.stack.length == 0) {
{
if (si.stack.length == 0) {
callback(null, false);
return;
}
}
if (castBool(si.stackBack()) == false) {
callback(null, false);
return;
}
}
// if not P2SH, we're done
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
// if not P2SH, we're done
if (!opts.verifyP2SH || !scriptPubKey.isP2SH()) {
callback(null, true);
return;
}
}
if (!scriptSig.isPushOnly()) {
if (!scriptSig.isPushOnly()) {
callback(null, false);
return;
}
}
assert.notEqual(siCopy.length, 0);
assert.notEqual(siCopy.length, 0);
var subscript = new Script(siCopy.stackPop());
var subscript = new Script(siCopy.stackPop());
ok = true;
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
ok = true;
siCopy.eval(subscript, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep4(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
}
});
}
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
function verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy)
{
if (opts.verifyP2SH) {
{
if (opts.verifyP2SH) {
si.stack.forEach(function(item) {
siCopy.stack.push(item);
});
}
}
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
si.eval(scriptPubKey, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep3(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
}
});
}
ScriptInterpreter.verifyFull =
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
ScriptInterpreter.verifyFull =
function verifyFull(scriptSig, scriptPubKey, txTo, nIn, hashType,
opts, callback)
{
{
var si = new ScriptInterpreter();
var siCopy = new ScriptInterpreter();
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
si.eval(scriptSig, txTo, nIn, hashType, function (err) {
if (err)
callback(err);
else
verifyStep2(scriptSig, scriptPubKey, txTo, nIn,
hashType, opts, callback, si, siCopy);
});
};
});
};
var checkSig = ScriptInterpreter.checkSig =
function (sig, pubkey, scriptCode, tx, n, hashType, callback) {
var checkSig = ScriptInterpreter.checkSig =
function (sig, pubkey, scriptCode, tx, n, hashType, callback) {
if (!sig.length) {
callback(null, false);
return;
@ -1026,8 +1024,6 @@ function spec(b) {
} catch (err) {
callback(null, false);
}
};
return ScriptInterpreter;
};
module.defineClass(spec);
module.exports = require('soop')(ScriptInterpreter);

View File

@ -1,25 +1,23 @@
require('classtool');
var imports = require('soop').imports();
function spec(b) {
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 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');
var VerificationError = error.VerificationError;
var MissingSourceError = error.MissingSourceError;
var error = b.error || require('./util/error');
var VerificationError = error.VerificationError;
var MissingSourceError = error.MissingSourceError;
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
var COINBASE_OP = Buffer.concat([util.NULL_HASH, new Buffer('FFFFFFFF', 'hex')]);
function TransactionIn(data) {
function TransactionIn(data) {
if ("object" !== typeof data) {
data = {};
}
@ -29,69 +27,69 @@ function spec(b) {
this.s = Buffer.isBuffer(data.s) ? data.s :
Buffer.isBuffer(data.script) ? data.script : util.EMPTY_BUFFER;
this.q = data.q ? data.q : data.sequence;
}
}
TransactionIn.prototype.getScript = function getScript() {
TransactionIn.prototype.getScript = function getScript() {
return new Script(this.s);
};
};
TransactionIn.prototype.isCoinBase = function isCoinBase() {
TransactionIn.prototype.isCoinBase = function isCoinBase() {
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 qbuf = new Buffer(4);
qbuf.writeUInt32LE(this.q, 0);
return Buffer.concat([this.o, slen, this.s, qbuf]);
};
};
TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
TransactionIn.prototype.getOutpointHash = function getOutpointHash() {
if ("undefined" !== typeof this.o.outHashCache) {
return this.o.outHashCache;
}
return this.o.outHashCache = this.o.slice(0, 32);
};
};
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() {
TransactionIn.prototype.getOutpointIndex = function getOutpointIndex() {
return (this.o[32] ) +
(this.o[33] << 8) +
(this.o[34] << 16) +
(this.o[35] << 24);
};
};
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) {
TransactionIn.prototype.setOutpointIndex = function setOutpointIndex(n) {
this.o[32] = n & 0xff;
this.o[33] = n >> 8 & 0xff;
this.o[34] = n >> 16 & 0xff;
this.o[35] = n >> 24 & 0xff;
};
};
function TransactionOut(data) {
function TransactionOut(data) {
if ("object" !== typeof data) {
data = {};
}
this.v = data.v ? data.v : data.value;
this.s = data.s ? data.s : data.script;
};
};
TransactionOut.prototype.getValue = function getValue() {
TransactionOut.prototype.getValue = function getValue() {
return new Parser(this.v).word64lu();
};
};
TransactionOut.prototype.getScript = function getScript() {
TransactionOut.prototype.getScript = function getScript() {
return new Script(this.s);
};
};
TransactionOut.prototype.serialize = function serialize() {
TransactionOut.prototype.serialize = function serialize() {
var slen = util.varIntBuf(this.s.length);
return Buffer.concat([this.v, slen, this.s]);
};
};
function Transaction(data) {
function Transaction(data) {
if ("object" !== typeof data) {
data = {};
}
@ -112,16 +110,16 @@ function spec(b) {
return txout;
}) : [];
if (data.buffer) this._buffer = data.buffer;
};
this.class = Transaction;
Transaction.In = TransactionIn;
Transaction.Out = TransactionOut;
};
this.class = Transaction;
Transaction.In = TransactionIn;
Transaction.Out = TransactionOut;
Transaction.prototype.isCoinBase = function () {
Transaction.prototype.isCoinBase = function () {
return this.ins.length == 1 && this.ins[0].isCoinBase();
};
};
Transaction.prototype.isStandard = function isStandard() {
Transaction.prototype.isStandard = function isStandard() {
var i;
for (i = 0; i < this.ins.length; i++) {
if (this.ins[i].getScript().getInType() == "Strange") {
@ -134,9 +132,9 @@ function spec(b) {
}
}
return true;
};
};
Transaction.prototype.serialize = function serialize() {
Transaction.prototype.serialize = function serialize() {
var bufs = [];
var buf = new Buffer(4);
@ -159,34 +157,34 @@ function spec(b) {
this._buffer = Buffer.concat(bufs);
return this._buffer;
};
};
Transaction.prototype.getBuffer = function getBuffer() {
Transaction.prototype.getBuffer = function getBuffer() {
if (this._buffer) return this._buffer;
return this.serialize();
};
};
Transaction.prototype.calcHash = function calcHash() {
Transaction.prototype.calcHash = function calcHash() {
this.hash = util.twoSha256(this.getBuffer());
return this.hash;
};
};
Transaction.prototype.checkHash = function checkHash() {
Transaction.prototype.checkHash = function checkHash() {
if (!this.hash || !this.hash.length) return false;
return buffertools.compare(this.calcHash(), this.hash) === 0;
};
};
Transaction.prototype.getHash = function getHash() {
Transaction.prototype.getHash = function getHash() {
if (!this.hash || !this.hash.length) {
this.hash = this.calcHash();
}
return this.hash;
};
};
// convert encoded list of inputs to easy-to-use JS list-of-lists
Transaction.prototype.inputs = function inputs() {
// convert encoded list of inputs to easy-to-use JS list-of-lists
Transaction.prototype.inputs = function inputs() {
var res = [];
for (var i = 0; i < this.ins.length; i++) {
var txin = this.ins[i];
@ -196,9 +194,9 @@ function spec(b) {
}
return res;
}
}
/**
/**
* Load and cache transaction inputs.
*
* This function will try to load the inputs for a transaction.
@ -209,15 +207,15 @@ function spec(b) {
* met (or a timeout occurs.)
* @param {Function} callback Function to call on completion.
*/
Transaction.prototype.cacheInputs =
function cacheInputs(blockChain, txStore, wait, callback) {
Transaction.prototype.cacheInputs =
function cacheInputs(blockChain, txStore, wait, callback) {
var self = this;
var txCache = new TransactionInputsCache(this);
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 txIndex = txCache.txIndex;
@ -341,22 +339,22 @@ function spec(b) {
},
callback
);
};
};
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
Transaction.prototype.verifyInput = function verifyInput(n, scriptPubKey, callback) {
return ScriptInterpreter.verify(this.ins[n].getScript(),
scriptPubKey,
this, n, 0,
callback);
};
};
/**
/**
* Returns an object containing all pubkey hashes affected by this transaction.
*
* The return object contains the base64-encoded pubKeyHash values as keys
* 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
// accounts.
if (!(this.affects && this.affects.length)) {
@ -423,22 +421,22 @@ function spec(b) {
});
return affectedKeys;
};
};
var OP_CODESEPARATOR = 171;
var OP_CODESEPARATOR = 171;
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
var SIGHASH_ALL = 1;
var SIGHASH_NONE = 2;
var SIGHASH_SINGLE = 3;
var SIGHASH_ANYONECANPAY = 80;
Transaction.SIGHASH_ALL=SIGHASH_ALL;
Transaction.SIGHASH_NONE=SIGHASH_NONE;
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE;
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY;
Transaction.SIGHASH_ALL=SIGHASH_ALL;
Transaction.SIGHASH_NONE=SIGHASH_NONE;
Transaction.SIGHASH_SINGLE=SIGHASH_SINGLE;
Transaction.SIGHASH_ANYONECANPAY=SIGHASH_ANYONECANPAY;
Transaction.prototype.hashForSignature =
function hashForSignature(script, inIndex, hashType) {
Transaction.prototype.hashForSignature =
function hashForSignature(script, inIndex, hashType) {
if (+inIndex !== inIndex ||
inIndex < 0 || inIndex >= this.ins.length) {
throw new Error("Input index '"+inIndex+"' invalid or out of bounds "+
@ -540,12 +538,12 @@ function spec(b) {
buffer = Buffer.concat([buffer, new Buffer([parseInt(hashType), 0, 0, 0])]);
return util.twoSha256(buffer);
};
};
/**
/**
* 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 = {
hash: util.formatHashFull(this.getHash()),
version: this.version,
@ -587,14 +585,14 @@ function spec(b) {
tx["out"] = outs;
return tx;
};
};
// Add some Mongoose compatibility functions to the plain object
Transaction.prototype.toObject = function toObject() {
// Add some Mongoose compatibility functions to the plain object
Transaction.prototype.toObject = function toObject() {
return this;
};
};
Transaction.prototype.fromObj = function fromObj(obj) {
Transaction.prototype.fromObj = function fromObj(obj) {
var txobj = {};
txobj.version = obj.version || 1;
txobj.lock_time = obj.lock_time || 0;
@ -636,9 +634,9 @@ function spec(b) {
this.version = txobj.version;
this.ins = txobj.ins;
this.outs = txobj.outs;
}
}
Transaction.prototype.parse = function (parser) {
Transaction.prototype.parse = function (parser) {
if (Buffer.isBuffer(parser)) {
parser = new Parser(parser);
}
@ -672,11 +670,11 @@ function spec(b) {
this.lock_time = parser.word32le();
this.calcHash();
};
};
var TransactionInputsCache = exports.TransactionInputsCache =
function TransactionInputsCache(tx)
{
var TransactionInputsCache = exports.TransactionInputsCache =
function TransactionInputsCache(tx)
{
var txList = [];
var txList64 = [];
var reqOuts = {};
@ -703,10 +701,10 @@ function spec(b) {
this.txIndex = {};
this.requiredOuts = reqOuts;
this.callbacks = [];
};
};
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback)
{
TransactionInputsCache.prototype.buffer = function buffer(blockChain, txStore, wait, callback)
{
var self = this;
var complete = false;
@ -789,11 +787,11 @@ function spec(b) {
},
self.callback.bind(self)
);
};
};
TransactionInputsCache.prototype.callback = function callback(err)
{
TransactionInputsCache.prototype.callback = function callback(err)
{
var args = Array.prototype.slice.apply(arguments);
// Empty the callback array first (because downstream functions could add new
@ -809,8 +807,6 @@ function spec(b) {
log.err("Callback error after connecting tx inputs: "+
(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');};
function ClassSpec(b) {
var fs = require('fs');
var EncFile = require('./util/EncFile');
var Address = require('./Address').class();
var networks = require('./networks');
var util = b.util || require('./util/util');
var ENC_METHOD = 'aes-256-cbc';
var fs = require('fs');
var EncFile = require('./util/EncFile');
var Address = require('./Address');
var networks = require('./networks');
var util = imports.util || require('./util/util');
var ENC_METHOD = 'aes-256-cbc';
var skeleton = {
var skeleton = {
client: 'libcoin',
client_version: '0.0.1',
network: 'testnet',
@ -19,9 +19,9 @@ function ClassSpec(b) {
keys: [],
sin: {},
scripts: {},
};
};
function Wallet(cfg) {
function Wallet(cfg) {
if (typeof cfg !== 'object')
cfg = {};
@ -33,15 +33,15 @@ function ClassSpec(b) {
this.network = undefined;
this.dirty = cfg.dirty || true;
};
};
Wallet.prototype.readSync = function(filename, passphrase) {
Wallet.prototype.readSync = function(filename, passphrase) {
this.datastore = EncFile.readJFileSync(ENC_METHOD,
passphrase, filename);
this.dirty = false;
};
};
Wallet.prototype.writeSync = function(filename, passphrase) {
Wallet.prototype.writeSync = function(filename, passphrase) {
var tmp_fn = filename + ".tmp";
EncFile.writeJFileSync(ENC_METHOD, passphrase, tmp_fn,
@ -49,9 +49,9 @@ function ClassSpec(b) {
fs.renameSync(tmp_fn, filename);
this.dirty = false;
};
};
Wallet.prototype.setNetwork = function(netname) {
Wallet.prototype.setNetwork = function(netname) {
if (!netname)
netname = this.datastore.network;
@ -70,19 +70,19 @@ function ClassSpec(b) {
// store+canonicalize name
this.datastore['network'] = this.network.name;
this.dirty = true;
};
};
Wallet.prototype.addKey = function(wkey) {
Wallet.prototype.addKey = function(wkey) {
this.datastore.keys.push(wkey);
this.dirty = true;
};
};
Wallet.prototype.addSIN = function(sinObj) {
Wallet.prototype.addSIN = function(sinObj) {
this.datastore.sin[sinObj.sin] = sinObj;
this.dirty = true;
};
};
Wallet.prototype.findKeyHash = function(pubKeyHash) {
Wallet.prototype.findKeyHash = function(pubKeyHash) {
var pkhStr = pubKeyHash.toString();
for (var i = 0; i < this.datastore.keys.length; i++) {
@ -94,9 +94,9 @@ function ClassSpec(b) {
}
return undefined;
};
};
Wallet.prototype.expandKey = function(key) {
Wallet.prototype.expandKey = function(key) {
var addr = new Address(key);
var isAddr = true;
@ -113,9 +113,9 @@ function ClassSpec(b) {
if (!key.match(re))
throw new Error("Unknown key type");
return hex(key);
};
};
Wallet.prototype.expandKeys = function(keys) {
Wallet.prototype.expandKeys = function(keys) {
var res = [];
var us = this;
keys.forEach(function(key) {
@ -123,9 +123,9 @@ function ClassSpec(b) {
res.push(expKey);
});
return res;
};
};
Wallet.prototype.addScript = function(script) {
Wallet.prototype.addScript = function(script) {
var buf = script.getBuffer();
var hash = util.sha256ripe160(buf);
var addr = new Address(this.network.addressScript, hash);
@ -134,9 +134,7 @@ function ClassSpec(b) {
this.dirty = true;
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 timeUtil = require('./util/time');
var KeyModule = require('./Key');
var PrivateKey = require('./PrivateKey').class();
var Address = require('./Address').class();
var coinUtil = require('./util/util');
var timeUtil = require('./util/time');
var KeyModule = require('./Key');
var PrivateKey = require('./PrivateKey');
var Address = require('./Address');
function WalletKey(cfg) {
function WalletKey(cfg) {
if (!cfg) cfg = {};
if (!cfg.network) throw new Error('network parameter is required');
this.network = cfg.network; // required
this.created = cfg.created;
this.privKey = cfg.privKey;
};
};
WalletKey.prototype.generate = function() {
WalletKey.prototype.generate = function() {
this.privKey = KeyModule.Key.generateSync();
this.created = timeUtil.curtime();
};
};
WalletKey.prototype.storeObj = function() {
WalletKey.prototype.storeObj = function() {
var pubKey = this.privKey.public.toString('hex');
var pubKeyHash = coinUtil.sha256ripe160(this.privKey.public);
var addr = new Address(this.network.addressPubkey, pubKeyHash);
@ -33,9 +32,9 @@ function ClassSpec(b) {
};
return obj;
};
};
WalletKey.prototype.fromObj = function(obj) {
WalletKey.prototype.fromObj = function(obj) {
this.created = obj.created;
this.privKey = new KeyModule.Key();
if (obj.priv.length==64) {
@ -48,8 +47,6 @@ function ClassSpec(b) {
this.privKey.compressed = priv.compressed();
}
this.privKey.regenerateSync();
};
return WalletKey;
};
module.defineClass(ClassSpec);
module.exports = require('soop')(WalletKey);

View File

@ -13,7 +13,7 @@ describe('Address', function() {
should.exist(AddressModule);
});
it('should be able to create class', function() {
Address = AddressModule.class();
Address = AddressModule;
should.exist(Address);
});
it('should be able to create instance', function() {

View File

@ -12,7 +12,7 @@ describe('Block', function() {
should.exist(BlockModule);
});
it('should be able to create class', function() {
Block = BlockModule.class();
Block = BlockModule;
should.exist(Block);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('Bloom', function() {
should.exist(BloomModule);
});
it('should be able to create class', function() {
Bloom = BloomModule.class();
Bloom = BloomModule;
should.exist(Bloom);
});
it('should be able to create instance', function() {

View File

@ -14,7 +14,7 @@ describe('Connection', function() {
should.exist(ConnectionModule);
});
it('should be able to create class', function() {
Connection = ConnectionModule.class();
Connection = ConnectionModule;
should.exist(Connection);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('EncodedData', function() {
should.exist(EncodedDataModule);
});
it('should be able to create class', function() {
EncodedData = EncodedDataModule.class();
EncodedData = EncodedDataModule;
should.exist(EncodedData);
});
it('should be able to create an instance', function() {

View File

@ -13,7 +13,7 @@ describe('Opcode', function() {
should.exist(OpcodeModule);
});
it('should be able to create class', function() {
Opcode = OpcodeModule.class();
Opcode = OpcodeModule;
should.exist(Opcode);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('Peer', function() {
should.exist(PeerModule);
});
it('should be able to create class', function() {
Peer = PeerModule.class();
Peer = PeerModule;
should.exist(Peer);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('PeerManager', function() {
should.exist(PeerManagerModule);
});
it('should be able to create class', function() {
PeerManager = PeerManagerModule.class();
PeerManager = PeerManagerModule;
should.exist(PeerManager);
});
it('should be able to create instance', function() {

View File

@ -15,7 +15,7 @@ describe('PrivateKey', function() {
should.exist(PrivateKeyModule);
});
it('should be able to create class', function() {
PrivateKey = PrivateKeyModule.class();
PrivateKey = PrivateKeyModule;
should.exist(PrivateKey);
});
it('should be able to create instance', function() {

View File

@ -7,7 +7,7 @@ var should = chai.should();
var RpcClientModule = bitcore.RpcClient;
var RpcClient;
RpcClient = RpcClientModule.class();
RpcClient = RpcClientModule;
describe('RpcClient', function() {
it('should initialze the main object', function() {

View File

@ -13,7 +13,7 @@ describe('SIN', function() {
should.exist(SINModule);
});
it('should be able to create class', function() {
SIN = SINModule.class();
SIN = SINModule;
should.exist(SIN);
});
it('should be able to create instance', function() {

View File

@ -16,7 +16,7 @@ describe('SINKey', function() {
should.exist(SINKeyModule);
});
it('should be able to create class', function() {
SINKey = SINKeyModule.class();
SINKey = SINKeyModule;
should.exist(SINKey);
});
it('should be able to create instance', function() {

View File

@ -6,7 +6,7 @@ var bitcore = require('../bitcore');
var should = chai.should();
var ScriptModule = bitcore.Script;
var Address = bitcore.Address.class();
var Address = bitcore.Address;
var networks = bitcore.networks;
var Script;
@ -15,7 +15,7 @@ describe('Script', function() {
should.exist(ScriptModule);
});
it('should be able to create class', function() {
Script = ScriptModule.class();
Script = ScriptModule;
should.exist(Script);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('ScriptInterpreter', function() {
should.exist(ScriptInterpreterModule);
});
it('should be able to create class', function() {
ScriptInterpreter = ScriptInterpreterModule.class();
ScriptInterpreter = ScriptInterpreterModule;
should.exist(ScriptInterpreter);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('Transaction', function() {
should.exist(TransactionModule);
});
it('should be able to create class', function() {
Transaction = TransactionModule.class();
Transaction = TransactionModule;
should.exist(Transaction);
});
it('should be able to create instance', function() {

View File

@ -13,7 +13,7 @@ describe('VersionedData', function() {
should.exist(VersionedDataModule);
});
it('should be able to create class', function() {
VersionedData = VersionedDataModule.class();
VersionedData = VersionedDataModule;
should.exist(VersionedData);
});
it('should be able to create an instance', function() {

View File

@ -13,7 +13,7 @@ describe('Wallet', function() {
should.exist(WalletModule);
});
it('should be able to create class', function() {
Wallet = WalletModule.class();
Wallet = WalletModule;
should.exist(Wallet);
});
it('should be able to create instance', function() {

View File

@ -14,7 +14,7 @@ describe('WalletKey', function() {
should.exist(WalletKeyModule);
});
it('should be able to create class', function() {
WalletKey = WalletKeyModule.class();
WalletKey = WalletKeyModule;
should.exist(WalletKey);
});
it('should be able to create instance', function() {

View File

@ -4,8 +4,8 @@ var chai = require('chai');
var bitcore = require('../bitcore');
var should = chai.should();
var Address = bitcore.Address.class();
var PrivateKey = bitcore.PrivateKey.class();
var Address = bitcore.Address;
var PrivateKey = bitcore.PrivateKey;
var networks = bitcore.networks;
var KeyModule = bitcore.KeyModule;

View File

@ -2,20 +2,20 @@
* Simple synchronous parser based on node-binary.
*/
function spec(b) {
function Parser(buffer)
{
var imports = require('soop').imports();
function Parser(buffer)
{
this.subject = buffer;
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);
this.pos += len;
return buf;
};
};
Parser.prototype.search = function search(needle) {
Parser.prototype.search = function search(needle) {
var len;
if ("string" === typeof needle || Buffer.isBuffer(needle)) {
@ -38,12 +38,12 @@ function spec(b) {
}
return -1;
}
};
};
/**
/**
* Like search(), but returns the skipped bytes
*/
Parser.prototype.scan = function scan(needle) {
Parser.prototype.scan = function scan(needle) {
var startPos = this.pos;
var len = this.search(needle);
if (len !== -1) {
@ -51,55 +51,55 @@ function spec(b) {
} else {
throw new Error('No match');
}
};
};
Parser.prototype.eof = function eof() {
Parser.prototype.eof = function eof() {
return this.pos >= this.subject.length;
};
};
// convert byte strings to unsigned little endian numbers
function decodeLEu (bytes) {
// convert byte strings to unsigned little endian numbers
function decodeLEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256,i) * bytes[i];
}
return acc;
}
}
// convert byte strings to unsigned big endian numbers
function decodeBEu (bytes) {
// convert byte strings to unsigned big endian numbers
function decodeBEu (bytes) {
var acc = 0;
for (var i = 0; i < bytes.length; i++) {
acc += Math.pow(256, bytes.length - i - 1) * bytes[i];
}
return acc;
}
}
// convert byte strings to signed big endian numbers
function decodeBEs (bytes) {
// convert byte strings to signed big endian numbers
function decodeBEs (bytes) {
var val = decodeBEu(bytes);
if ((bytes[0] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
}
// convert byte strings to signed little endian numbers
function decodeLEs (bytes) {
// convert byte strings to signed little endian numbers
function decodeLEs (bytes) {
var val = decodeLEu(bytes);
if ((bytes[bytes.length - 1] & 0x80) == 0x80) {
val -= Math.pow(256, bytes.length);
}
return val;
}
}
function getDecoder(len, fn) {
function getDecoder(len, fn) {
return function () {
var buf = this.buffer(len);
return fn(buf);
};
};
[ 1, 2, 4, 8 ].forEach(function (bytes) {
};
[ 1, 2, 4, 8 ].forEach(function (bytes) {
var bits = bytes * 8;
Parser.prototype['word' + bits + 'le']
@ -118,10 +118,10 @@ function spec(b) {
Parser.prototype.word8 = Parser.prototype.word8u = Parser.prototype.word8be;
Parser.prototype.word8s = Parser.prototype.word8bs;
});
});
Parser.prototype.varInt = function ()
{
Parser.prototype.varInt = function ()
{
var firstByte = this.word8();
switch (firstByte) {
case 0xFD:
@ -136,13 +136,11 @@ function spec(b) {
default:
return firstByte;
}
};
};
Parser.prototype.varStr = function () {
Parser.prototype.varStr = function () {
var len = this.varInt();
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:
// new EncodedData(<base58_address_string>)
// new EncodedData(<binary_buffer>)
// new EncodedData(<data>, <encoding>)
// new EncodedData(<version>, <20-byte-hash>)
function EncodedData(data, encoding) {
// Constructor. Takes the following forms:
// new EncodedData(<base58_address_string>)
// new EncodedData(<binary_buffer>)
// new EncodedData(<data>, <encoding>)
// new EncodedData(<version>, <20-byte-hash>)
function EncodedData(data, encoding) {
this.data = data;
if(!encoding && (typeof data == 'string')) {
this.__proto__ = this.encodings['base58'];
} else {
this.__proto__ = this.encodings[encoding || 'binary'];
}
};
};
// get or set the encoding used (transforms data)
EncodedData.prototype.encoding = function(encoding) {
// get or set the encoding used (transforms data)
EncodedData.prototype.encoding = function(encoding) {
if(encoding && (encoding != this._encoding)) {
this.data = this.as(encoding);
this.__proto__ = this.encodings[encoding];
}
return this._encoding;
};
};
// answer a new instance having the given encoding
EncodedData.prototype.withEncoding = function(encoding) {
// answer a new instance having the given encoding
EncodedData.prototype.withEncoding = function(encoding) {
return new EncodedData(this.as(encoding), encoding);
};
};
// answer the data in the given encoding
EncodedData.prototype.as = function(encoding) {
// answer the data in the given encoding
EncodedData.prototype.as = function(encoding) {
if(!encodings[encoding]) throw new Error('invalid encoding');
return this.converters[encoding].call(this);
};
};
// validate that we can convert to binary
EncodedData.prototype._validate = function() {
// validate that we can convert to binary
EncodedData.prototype._validate = function() {
this.withEncoding('binary');
};
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
};
// subclasses can override to do more stuff
EncodedData.prototype.validate = function() {
// subclasses can override to do more stuff
EncodedData.prototype.validate = function() {
this._validate();
};
};
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
// Boolean protocol for testing if valid
EncodedData.prototype.isValid = function() {
try {
this.validate();
return true;
} catch(e) {
return false;
}
};
};
// convert to a string (in base58 form)
EncodedData.prototype.toString = function() {
// convert to a string (in base58 form)
EncodedData.prototype.toString = function() {
return this.as('base58');
};
};
// utility
EncodedData.prototype.doAsBinary = function(callback) {
// utility
EncodedData.prototype.doAsBinary = function(callback) {
var oldEncoding = this.encoding();
this.encoding('binary');
callback.apply(this);
this.encoding(oldEncoding);
};
};
// Setup support for various address encodings. The object for
// each encoding inherits from the EncodedData prototype. This
// allows any encoding to override any method...changing the encoding
// for an instance will change the encoding it inherits from. Note,
// this will present some problems for anyone wanting to inherit from
// EncodedData (we'll deal with that when needed).
var encodings = {
// Setup support for various address encodings. The object for
// each encoding inherits from the EncodedData prototype. This
// allows any encoding to override any method...changing the encoding
// for an instance will change the encoding it inherits from. Note,
// this will present some problems for anyone wanting to inherit from
// EncodedData (we'll deal with that when needed).
var encodings = {
'binary': {
converters: {
'binary': function() {
@ -128,18 +127,18 @@ function ClassSpec(b) {
},
},
},
};
};
var no_conversion = function() {return this.data;};
for(var k in encodings) {
var no_conversion = function() {return this.data;};
for(var k in encodings) {
if(encodings.hasOwnProperty(k)){
if(!encodings[k].converters[k])
encodings[k].converters[k] = no_conversion;
encodings[k]._encoding = k;
}
}
}
EncodedData.applyEncodingsTo = function(aClass) {
EncodedData.applyEncodingsTo = function(aClass) {
var tmp = {};
for(var k in encodings) {
var enc = encodings[k];
@ -151,9 +150,9 @@ function ClassSpec(b) {
tmp[k] = obj;
}
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,8 @@
require('classtool');
var imports = require('soop').imports();
var base58 = imports.base58 || require('base58-native').base58Check;
var superclass = imports.parent || require('./EncodedData');
function ClassSpec(b) {
var superclass = b.superclass || require('./EncodedData').class();
function VersionedData(version, payload) {
function VersionedData(version, payload) {
if(typeof version != 'number') {
VersionedData.super(this, arguments);
return;
@ -12,28 +11,27 @@ function ClassSpec(b) {
this.__proto__ = this.encodings['binary'];
this.version(version);
this.payload(payload);
};
VersionedData.superclass = superclass;
superclass.applyEncodingsTo(VersionedData);
};
// get or set the version data (the first byte of the address)
VersionedData.prototype.version = function(num) {
VersionedData.parent = superclass || require('./Person');
superclass.applyEncodingsTo(VersionedData);
// get or set the version data (the first byte of the address)
VersionedData.prototype.version = function(num) {
if(num || (num === 0)) {
this.doAsBinary(function() {this.data.writeUInt8(num, 0);});
return num;
}
return this.as('binary').readUInt8(0);
};
};
// get or set the payload data (as a Buffer object)
VersionedData.prototype.payload = function(data) {
// get or set the payload data (as a Buffer object)
VersionedData.prototype.payload = function(data) {
if(data) {
this.doAsBinary(function() {data.copy(this.data,1);});
return data;
}
return this.as('binary').slice(1);
};
return VersionedData;
};
module.defineClass(ClassSpec);
module.exports = require('soop')(VersionedData);