require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0) { var zb = new Buffer(i); zb.fill(0); if (i == str.length) return zb; answer = answer.toBuffer(); return Buffer.concat([zb, answer], i + answer.length); } else { return answer.toBuffer(); } }, }; // Base58Check Encoding function sha256(data) { return new Buffer(crypto.createHash('sha256').update(data).digest('binary'), 'binary'); }; function doubleSHA256(data) { return sha256(sha256(data)); }; var base58Check = { encode: function(buf) { var checkedBuf = new Buffer(buf.length + 4); var hash = doubleSHA256(buf); buf.copy(checkedBuf); hash.copy(checkedBuf, buf.length); return base58.encode(checkedBuf); }, decode: function(s) { var buf = base58.decode(s); if (buf.length < 4) { throw new Error("invalid input: too short"); } var data = buf.slice(0, -4); var csum = buf.slice(-4); var hash = doubleSHA256(data); var hash4 = hash.slice(0, 4); if (csum.toString('hex') !== hash4.toString('hex')) { throw new Error("checksum mismatch"); } return data; }, }; // if you frequently do base58 encodings with data larger // than 512 bytes, you can use this method to expand the // size of the reusable buffer exports.setBuffer = function(buf) { globalBuffer = buf; }; exports.base58 = base58; exports.base58Check = base58Check; exports.encode = base58.encode; exports.decode = base58.decode; }).call(this,require("buffer").Buffer) },{"bignum":57,"buffer":91,"crypto":95}],"./lib/Block":[function(require,module,exports){ module.exports=require('pJEQEB'); },{}],"pJEQEB":[function(require,module,exports){ (function (Buffer){ var util = require('../util'); var Script = require('./Script'); var Bignum = require('bignum'); var Binary = require('binary'); var Step = require('step'); var buffertools = require('buffertools'); var Transaction = require('./Transaction'); var TransactionIn = Transaction.In; var TransactionOut = Transaction.Out; var COINBASE_OP = Transaction.COINBASE_OP; var VerificationError = require('../util/error').VerificationError; var BlockRules = { maxTimeOffset: 2 * 60 * 60, // How far block timestamps can be into the future //largestHash: (new Bignum(2)).pow(256) //largestHash: new Bignum('115792089237316195423570985008687907853269984665640564039457584007913129639936') // = 2^256 largestHash: new Bignum('10000000000000000000000000000000000000000000000000000000000000000', 16) }; function Block(data) { if ("object" !== typeof data) { data = {}; } this.hash = data.hash || null; this.prev_hash = data.prev_hash || util.NULL_HASH; this.merkle_root = data.merkle_root || util.NULL_HASH; this.timestamp = data.timestamp || 0; this.bits = data.bits || 0; this.nonce = data.nonce || 0; this.version = data.version || 0; this.height = data.height || 0; this.size = data.size || 0; this.active = data.active || false; this.chainWork = data.chainWork || util.EMPTY_BUFFER; this.txs = data.txs || []; } Block.prototype.getHeader = function getHeader() { var buf = new Buffer(80); var ofs = 0; buf.writeUInt32LE(this.version, ofs); ofs += 4; this.prev_hash.copy(buf, ofs); ofs += 32; this.merkle_root.copy(buf, ofs); ofs += 32; buf.writeUInt32LE(this.timestamp, ofs); ofs += 4; buf.writeUInt32LE(this.bits, ofs); ofs += 4; buf.writeUInt32LE(this.nonce, ofs); ofs += 4; return buf; }; Block.prototype.parse = function parse(parser, headerOnly) { this.version = parser.word32le(); this.prev_hash = parser.buffer(32); this.merkle_root = parser.buffer(32); this.timestamp = parser.word32le(); this.bits = parser.word32le(); this.nonce = parser.word32le(); this.txs = []; this.size = 0; if (headerOnly) return; var txCount = parser.varInt(); for (var i = 0; i < txCount; i++) { var tx = new Transaction(); tx.parse(parser); this.txs.push(tx); } }; Block.prototype.calcHash = function calcHash() { var header = this.getHeader(); return util.twoSha256(header); }; 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() { if (!this.hash || !this.hash.length) this.hash = this.calcHash(); return this.hash; }; Block.prototype.checkProofOfWork = function checkProofOfWork() { var target = util.decodeDiffBits(this.bits); // TODO: Create a compare method in node-buffertools that uses the correct // endian so we don't have to reverse both buffers before comparing. var reverseHash = buffertools.reverse(this.hash); if (buffertools.compare(reverseHash, target) > 0) { throw new VerificationError('Difficulty target not met'); } 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() { var target = util.decodeDiffBits(this.bits, true); return BlockRules.largestHash.div(target.add(1)); }; 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) { if (!Array.isArray(txs) || txs.length <= 0) { throw new VerificationError('No transactions'); } if (!txs[0].isCoinBase()) { throw new VerificationError('First tx must be coinbase'); } for (var i = 1; i < txs.length; i++) { if (txs[i].isCoinBase()) { throw new VerificationError('Tx index ' + i + ' must not be coinbase'); } } 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) { // The merkle hash is based on a tree of hashes calculated from the transactions: // // merkleHash // /\ // / \ // A B // / \ / \ // tx1 tx2 tx3 tx4 // // Basically transactions are hashed, then the hashes of the transactions are hashed // again and so on upwards into the tree. The point of this scheme is to allow for // disk space savings later on. // // This function is a direct translation of CBlock::BuildMerkleTree(). if (txs.length == 0) { return [util.NULL_HASH.slice(0)]; } // Start by adding all the hashes of the transactions as leaves of the tree. var tree = txs.map(function(tx) { return tx instanceof Transaction ? tx.getHash() : tx; }); var j = 0; // Now step through each level ... for (var size = txs.length; size > 1; size = Math.floor((size + 1) / 2)) { // and for each leaf on that level .. for (var i = 0; i < size; i += 2) { var i2 = Math.min(i + 1, size - 1); var a = tree[j + i]; var b = tree[j + i2]; tree.push(util.twoSha256(Buffer.concat([a, b]))); } j += size; } return tree; }; Block.prototype.calcMerkleRoot = function calcMerkleRoot(txs) { var tree = this.getMerkleTree(txs); return tree[tree.length - 1]; }; Block.prototype.checkMerkleRoot = function checkMerkleRoot(txs) { if (!this.merkle_root || !this.merkle_root.length) { throw new VerificationError('No merkle root'); } if (buffertools.compare(this.calcMerkleRoot(txs), new Buffer(this.merkle_root)) !== 0) { throw new VerificationError('Merkle root incorrect'); } return true; }; Block.prototype.checkBlock = function checkBlock(txs) { if (!this.checkHash()) { throw new VerificationError("Block hash invalid"); } this.checkProofOfWork(); this.checkTimestamp(); if (txs) { this.checkTransactions(txs); if (!this.checkMerkleRoot(txs)) { throw new VerificationError("Merkle hash invalid"); } } return true; }; Block.getBlockValue = function getBlockValue(height) { var subsidy = 50 * util.COIN; subsidy = subsidy / (Math.pow(2, Math.floor(height / 210000))); subsidy = Math.floor(subsidy); subsidy = new Bignum(subsidy); return subsidy; }; Block.prototype.getBlockValue = function getBlockValue() { return Block.getBlockValue(this.height); }; Block.prototype.toString = function toString() { return ""; }; Block.prototype.createCoinbaseTx = function createCoinbaseTx(beneficiary) { var tx = new Transaction(); tx.ins.push(new TransactionIn({ s: util.EMPTY_BUFFER, q: 0xffffffff, o: COINBASE_OP })); tx.outs.push(new TransactionOut({ v: util.bigIntToValue(this.getBlockValue()), s: Script.createPubKeyOut(beneficiary).getBuffer() })); return tx; }; 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) { var block = { hash: util.formatHashFull(this.getHash()), version: this.version, prev_block: util.formatHashFull(this.prev_hash), mrkl_root: util.formatHashFull(this.merkle_root), time: this.timestamp, bits: this.bits, nonce: this.nonce, height: this.height }; if (txs) { var mrkl_tree = this.getMerkleTree(txs).map(function(buffer) { return util.formatHashFull(buffer); }); block.mrkl_root = mrkl_tree[mrkl_tree.length - 1]; block.n_tx = txs.length; var totalSize = 80; // Block header totalSize += util.getVarIntSize(txs.length); // txn_count txs = txs.map(function(tx) { tx = tx.getStandardizedObject(); totalSize += tx.size; return tx; }); block.size = totalSize; block.tx = txs; block.mrkl_tree = mrkl_tree; } else { block.size = this.size; } return block; }; module.exports = Block; }).call(this,require("buffer").Buffer) },{"../util":181,"../util/error":180,"./Script":"hQ0t76","./Transaction":"LJhYtm","bignum":57,"binary":79,"buffer":91,"buffertools":"fugeBw","step":168}],"KifRG4":[function(require,module,exports){ var MAX_BLOOM_FILTER_SIZE = 36000; // bytes var MAX_HASH_FUNCS = 50; var LN2SQUARED = 0.4804530139182014246671025263266649717305529515945455; var LN2 = 0.6931471805599453094172321214581765680755001343602552; var bit_mask = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80]; function Bloom() { this.data = ''; this.hashFuncs = 0; }; function ROTL32(x, r) { return (x << r) | (x >> (32 - r)); }; function getBlockU32(blockIdx, data) { var idx = blockIdx * 4; var v = (data[idx + 0] << (0 * 8)) | (data[idx + 1] << (1 * 8)) | (data[idx + 2] << (2 * 8)) | (data[idx + 3] << (3 * 8)); return v; }; Bloom.prototype.hash = function(hashNum, data) { var h1 = hashNum * (0xffffffff / (this.hashFuncs - 1)); var c1 = 0xcc9e2d51; var c2 = 0x1b873593; var nBlocks = data.length / 4; // data body for (var i = -nBlocks; i; i++) { var k1 = getBlockU32(i); k1 *= c1; k1 = ROTLF32(k1, 15); k1 *= c2; h1 ^= k1; h1 = ROTFL(h1, 13); h1 = h1 * 5 + 0xe6546b64; } // tail (trailing 1-3 bytes) var tail = data.slice(nBlocks * 4); var k1 = 0; switch (data.length & 3) { case 3: k1 ^= tail[2] << 16; case 2: k1 ^= tail[1] << 8; case 1: k1 ^= tail[0]; k1 *= c1; k1 = ROTL32(k1, 15); k1 *= c2; h1 ^= k1; } // finalize h1 ^= data.length; h1 ^= h1 >> 16; h1 *= 0x85ebca6b; h1 ^= h1 >> 13; h1 *= 0xc2b2ae35; h1 ^= h1 >> 16; return h1 % (this.data.length * 8); }; Bloom.prototype.insert = function(data) { for (var i = 0; i < this.hashFuncs; i++) { var index = this.hash(i, data); this.data[index >> 3] |= bit_mask[7 & index]; } }; Bloom.prototype.contains = function(data) { for (var i = 0; i < this.hashFuncs; i++) { var index = this.hash(i, data); if (!(this.data[index >> 3] & bit_mask[7 & index])) return false; } return true; }; Bloom.prototype.sizeOk = function() { return this.data.length <= MAX_BLOOM_FILTER_SIZE && this.hashFuncs <= MAX_HASH_FUNCS; }; function toInt(v) { return~~ v; } function min(a, b) { if (a < b) return a; return b; } Bloom.prototype.init = function(elements, FPRate) { var filterSize = min(toInt(-1.0 / LN2SQUARED * elements * Math.log(FPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8; this.data[filterSize] = 0; this.hashFuncs = min(toInt(this.data.length * 8 / elements * LN2), MAX_HASH_FUNCS); }; module.exports = Bloom; },{}],"./lib/Bloom":[function(require,module,exports){ module.exports=require('KifRG4'); },{}],"DB/p3X":[function(require,module,exports){ (function (Buffer){ var log = require('../util/log'); var MAX_RECEIVE_BUFFER = 10000000; var PROTOCOL_VERSION = 70000; var Put = require('bufferput'); var Buffers = require('buffers'); require('../patches/Buffers.monkey').patch(Buffers); var bitcoreDefaults = require('../config'); var networks = require('../networks'); var Block = require('./Block'); var Transaction = require('./Transaction'); var util = require('../util'); var Parser = require('../util/BinaryParser'); var buffertools = require('buffertools'); var doubleSha256 = util.twoSha256; var SecureRandom = require('./SecureRandom'); var nonce = SecureRandom.getPseudoRandomBuffer(8); var nodeUtil = require('util'); var BIP0031_VERSION = 60000; function Connection(socket, peer, opts) { this.config = opts || bitcoreDefaults; this.network = networks[this.config.network] || networks.livenet; this.socket = socket; this.peer = peer; // check for socks5 proxy options and construct a proxied socket if (this.config.proxy) { var Socks5Client = require('socks5-client'); this.socket = new Socks5Client(this.config.proxy.host, this.config.proxy.port); } // A connection is considered "active" once we have received verack this.active = false; // The version incoming packages are interpreted as this.recvVer = 0; // The version outgoing packages are sent as this.sendVer = 0; // The (claimed) height of the remote peer's block chain this.bestHeight = 0; // Is this an inbound connection? this.inbound = !!this.socket.server; // Have we sent a getaddr on this connection? this.getaddr = false; // Receive buffer this.buffers = new Buffers(); // Starting 20 Feb 2012, Version 0.2 is obsolete // This is the same behavior as the official client if (new Date().getTime() > 1329696000000) { this.recvVer = 209; this.sendVer = 209; } this.setupHandlers(); } var EventEmitter = require('events').EventEmitter; nodeUtil.inherits(Connection, EventEmitter); Connection.prototype.open = function(callback) { if (typeof callback === 'function') this.once('connect', callback); this.socket.connect(this.peer.port, this.peer.host); return this; }; 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)); this.socket.addListener('data', (function(data) { var dumpLen = 35; log.debug('[' + this.peer + '] ' + 'Recieved ' + data.length + ' bytes of data:'); log.debug('... ' + buffertools.toHex(data.slice(0, dumpLen > data.length ? data.length : dumpLen)) + (data.length > dumpLen ? '...' : '')); }).bind(this)); this.socket.addListener('data', this.handleData.bind(this)); }; Connection.prototype.handleConnect = function() { if (!this.inbound) { this.sendVersion(); } this.emit('connect', { conn: this, socket: this.socket, peer: this.peer }); }; 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') { log.info('connection refused for ' + this.peer); } else { log.warn('connection with ' + this.peer + ' ' + err.toString()); } this.emit('error', { conn: this, socket: this.socket, peer: this.peer, err: err }); }; Connection.prototype.handleDisconnect = function() { this.emit('disconnect', { conn: this, socket: this.socket, peer: this.peer }); }; Connection.prototype.handleMessage = function(message) { if (!message) { // Parser was unable to make sense of the message, drop it return; } try { switch (message.command) { case 'version': // Did we connect to ourself? if (buffertools.compare(nonce, message.nonce) === 0) { this.socket.end(); return; } if (this.inbound) { this.sendVersion(); } if (message.version >= 209) { this.sendMessage('verack', new Buffer([])); } this.sendVer = Math.min(message.version, PROTOCOL_VERSION); if (message.version < 209) { this.recvVer = Math.min(message.version, PROTOCOL_VERSION); } else { // We won't start expecting a checksum until after we've received // the 'verack' message. this.once('verack', (function() { this.recvVer = message.version; }).bind(this)); } this.bestHeight = message.start_height; break; case 'verack': this.recvVer = Math.min(message.version, PROTOCOL_VERSION); this.active = true; break; case 'ping': if ('object' === typeof message.nonce) { this.sendPong(message.nonce); } break; } } catch (e) { log.err('Error while handling "' + message.command + '" message from ' + this.peer + ':\n' + (e.stack ? e.stack : e.toString())); return; } this.emit(message.command, { conn: this, socket: this.socket, peer: this.peer, message: message }); }; Connection.prototype.sendPong = function(nonce) { this.sendMessage('pong', nonce); }; Connection.prototype.sendVersion = function() { var subversion = '/BitcoinX:0.1/'; var put = new Put(); put.word32le(PROTOCOL_VERSION); // version put.word64le(1); // services put.word64le(Math.round(new Date().getTime() / 1000)); // timestamp put.pad(26); // addr_me put.pad(26); // addr_you put.put(nonce); put.varint(subversion.length); put.put(new Buffer(subversion, 'ascii')); put.word32le(0); this.sendMessage('version', put.buffer()); }; Connection.prototype.sendGetBlocks = function(starts, stop, wantHeaders) { // Default value for stop is 0 to get as many blocks as possible (500) stop = stop || util.NULL_HASH; var put = new Put(); // https://en.bitcoin.it/wiki/Protocol_specification#getblocks put.word32le(this.sendVer); put.varint(starts.length); for (var i = 0; i < starts.length; i++) { if (starts[i].length != 32) { throw new Error('Invalid hash length'); } put.put(starts[i]); } var stopBuffer = new Buffer(stop, 'binary'); if (stopBuffer.length != 32) { throw new Error('Invalid hash length'); } put.put(stopBuffer); var command = 'getblocks'; if (wantHeaders) command = 'getheaders'; this.sendMessage(command, put.buffer()); }; Connection.prototype.sendGetHeaders = function(starts, stop) { this.sendGetBlocks(starts, stop, true); }; Connection.prototype.sendGetData = function(invs) { var put = new Put(); put.varint(invs.length); for (var i = 0; i < invs.length; i++) { put.word32le(invs[i].type); put.put(invs[i].hash); } this.sendMessage('getdata', put.buffer()); }; Connection.prototype.sendGetAddr = function(invs) { var put = new Put(); this.sendMessage('getaddr', put.buffer()); }; Connection.prototype.sendInv = function(data) { if (!Array.isArray(data)) data = [data]; var put = new Put(); put.varint(data.length); data.forEach(function(value) { if (value instanceof Block) { // Block put.word32le(2); // MSG_BLOCK } else { // Transaction put.word32le(1); // MSG_TX } put.put(value.getHash()); }); this.sendMessage('inv', put.buffer()); }; Connection.prototype.sendHeaders = function(headers) { var put = new Put(); put.varint(headers.length); headers.forEach(function(header) { put.put(header); // Indicate 0 transactions put.word8(0); }); this.sendMessage('headers', put.buffer()); }; Connection.prototype.sendTx = function(tx) { this.sendMessage('tx', tx.serialize()); }; Connection.prototype.sendBlock = function(block, txs) { var put = new Put(); // Block header put.put(block.getHeader()); // List of transactions put.varint(txs.length); txs.forEach(function(tx) { put.put(tx.serialize()); }); this.sendMessage('block', put.buffer()); }; Connection.prototype.sendMessage = function(command, payload) { try { var magic = this.network.magic; var commandBuf = new Buffer(command, 'ascii'); if (commandBuf.length > 12) throw 'Command name too long'; var checksum; if (this.sendVer >= 209) { checksum = doubleSha256(payload).slice(0, 4); } else { checksum = new Buffer([]); } var message = new Put(); // -- HEADER -- message.put(magic); // magic bytes message.put(commandBuf); // command name message.pad(12 - commandBuf.length); // zero-padded message.word32le(payload.length); // payload length message.put(checksum); // checksum // -- BODY -- message.put(payload); // payload data var buffer = message.buffer(); log.debug('[' + this.peer + '] ' + 'Sending message ' + command + ' (' + payload.length + ' bytes)'); this.socket.write(buffer); } catch (err) { // TODO: We should catch this error one level higher in order to better // determine how to react to it. For now though, ignoring it will do. log.err('Error while sending message to peer ' + this.peer + ': ' + (err.stack ? err.stack : err.toString())); } }; Connection.prototype.handleData = function(data) { this.buffers.push(data); if (this.buffers.length > MAX_RECEIVE_BUFFER) { log.err('Peer ' + this.peer + ' exceeded maxreceivebuffer, disconnecting.' + (err.stack ? err.stack : err.toString())); this.socket.destroy(); return; } this.processData(); }; Connection.prototype.processData = function() { // If there are less than 20 bytes there can't be a message yet. if (this.buffers.length < 20) return; var magic = this.network.magic; var i = 0; for (;;) { if (this.buffers.get(i) === magic[0] && this.buffers.get(i + 1) === magic[1] && this.buffers.get(i + 2) === magic[2] && this.buffers.get(i + 3) === magic[3]) { if (i !== 0) { log.debug('[' + this.peer + '] ' + 'Received ' + i + ' bytes of inter-message garbage: '); log.debug('... ' + this.buffers.slice(0, i)); this.buffers.skip(i); } break; } if (i > (this.buffers.length - 4)) { this.buffers.skip(i); return; } i++; } var payloadLen = (this.buffers.get(16)) + (this.buffers.get(17) << 8) + (this.buffers.get(18) << 16) + (this.buffers.get(19) << 24); var startPos = (this.recvVer >= 209) ? 24 : 20; var endPos = startPos + payloadLen; if (this.buffers.length < endPos) return; var command = this.buffers.slice(4, 16).toString('ascii').replace(/\0+$/, ''); var payload = this.buffers.slice(startPos, endPos); var checksum = (this.recvVer >= 209) ? this.buffers.slice(20, 24) : null; log.debug('[' + this.peer + '] ' + 'Received message ' + command + ' (' + payloadLen + ' bytes)'); if (checksum !== null) { var checksumConfirm = doubleSha256(payload).slice(0, 4); if (buffertools.compare(checksumConfirm, checksum) !== 0) { log.err('[' + this.peer + '] ' + 'Checksum failed', { cmd: command, expected: checksumConfirm.toString('hex'), actual: checksum.toString('hex') }); return; } } var message; try { message = this.parseMessage(command, payload); } catch (e) { log.err('Error while parsing message ' + command + ' from ' + this.peer + ':\n' + (e.stack ? e.stack : e.toString())); } if (message) { this.handleMessage(message); } this.buffers.skip(endPos); this.processData(); }; Connection.prototype.parseMessage = function(command, payload) { var parser = new Parser(payload); var data = { command: command }; var i; switch (command) { case 'version': // https://en.bitcoin.it/wiki/Protocol_specification#version data.version = parser.word32le(); data.services = parser.word64le(); data.timestamp = parser.word64le(); data.addr_me = parser.buffer(26); data.addr_you = parser.buffer(26); data.nonce = parser.buffer(8); data.subversion = parser.varStr(); data.start_height = parser.word32le(); break; case 'inv': case 'getdata': data.count = parser.varInt(); data.invs = []; for (i = 0; i < data.count; i++) { data.invs.push({ type: parser.word32le(), hash: parser.buffer(32) }); } break; case 'headers': data.count = parser.varInt(); data.headers = []; for (i = 0; i < data.count; i++) { var header = new Block(); header.parse(parser); data.headers.push(header); } break; case 'block': var block = new Block(); block.parse(parser); data.block = block; data.version = block.version; data.prev_hash = block.prev_hash; data.merkle_root = block.merkle_root; data.timestamp = block.timestamp; data.bits = block.bits; data.nonce = block.nonce; data.txs = block.txs; data.size = payload.length; break; case 'tx': var tx = new Transaction(); tx.parse(parser); return { command: command, version: tx.version, lock_time: tx.lock_time, ins: tx.ins, outs: tx.outs, tx: tx, }; case 'getblocks': case 'getheaders': // parse out the version data.version = parser.word32le(); // TODO: Limit block locator size? // reference implementation limits to 500 results var startCount = parser.varInt(); data.starts = []; for (i = 0; i < startCount; i++) { data.starts.push(parser.buffer(32)); } data.stop = parser.buffer(32); break; case 'addr': var addrCount = parser.varInt(); // Enforce a maximum number of addresses per message if (addrCount > 1000) { addrCount = 1000; } data.addrs = []; for (i = 0; i < addrCount; i++) { // TODO: Time actually depends on the version of the other peer (>=31402) data.addrs.push({ time: parser.word32le(), services: parser.word64le(), ip: parser.buffer(16), port: parser.word16be() }); } break; case 'alert': data.payload = parser.varStr(); data.signature = parser.varStr(); break; case 'ping': if (this.recvVer > BIP0031_VERSION) { data.nonce = parser.buffer(8); } break; case 'getaddr': case 'verack': case 'reject': // Empty message, nothing to parse break; default: log.err('Connection.parseMessage(): Command not implemented', { cmd: command }); // This tells the calling function not to issue an event return null; } return data; }; module.exports = Connection; }).call(this,require("buffer").Buffer) },{"../config":"4itQ50","../networks":"ULNIu2","../patches/Buffers.monkey":"kytKTK","../util":181,"../util/BinaryParser":"b3ZSD7","../util/log":"AdF7pF","./Block":"pJEQEB","./SecureRandom":"p4SiC2","./Transaction":"LJhYtm","buffer":91,"bufferput":"aXRuS6","buffers":"OBo3aV","buffertools":"fugeBw","events":100,"socks5-client":162,"util":123}],"./lib/Connection":[function(require,module,exports){ module.exports=require('DB/p3X'); },{}],"ez/meX":[function(require,module,exports){ exports.intFromCompact = function(c) { var bytes = ((c >>> 24) & 0xff) >>> 0; var v = ((c & 0xffffff) << (8 * (bytes - 3))) >>> 0; return v; } },{}],"./lib/Deserialize":[function(require,module,exports){ module.exports=require('ez/meX'); },{}],"./lib/Electrum":[function(require,module,exports){ module.exports=require('hdzBvq'); },{}],"hdzBvq":[function(require,module,exports){ (function (Buffer){ var Key = require('./Key'), Point = require('./Point'), twoSha256 = require('../util').twoSha256, buffertools = require('buffertools'), bignum = require('bignum'); /** * Pre-BIP32 Electrum public key derivation (electrum <2.0) * * For now, this class can only understands master public keys. * It doesn't support derivation from a private master key (TODO). * * @example examples/ElectrumMPK.js */ function Electrum(master_public_key) { this.mpk = new Buffer(master_public_key, 'hex'); } Electrum.prototype.getSequence = function(for_change, n) { var mode = for_change ? 1 : 0; var buf = Buffer.concat([new Buffer(n + ':' + mode + ':', 'utf8'), this.mpk]); return bignum.fromBuffer(twoSha256(buf)); }; Electrum.prototype.generatePubKey = function(n, for_change) { var x = bignum.fromBuffer(this.mpk.slice(0, 32), { size: 32 }); var y = bignum.fromBuffer(this.mpk.slice(32, 64), { size: 32 }); var mpk_pt = new Point(x, y); var sequence = this.getSequence(for_change, n); var sequence_key = new Key(); sequence_key.private = sequence.toBuffer(); sequence_key.regenerateSync(); sequence_key.compressed = false; var sequence_pt = Point.fromUncompressedPubKey(sequence_key.public); pt = Point.add(mpk_pt, sequence_pt); var xbuf = pt.x.toBuffer({ size: 32 }); var ybuf = pt.y.toBuffer({ size: 32 }); var prefix = new Buffer([0x04]); var key = new Key(); key.compressed = false; key.public = Buffer.concat([prefix, xbuf, ybuf]); return key.public; }; Electrum.prototype.generateChangePubKey = function(sequence) { return this.generatePubKey(sequence, true); }; module.exports = Electrum; }).call(this,require("buffer").Buffer) },{"../util":181,"./Key":"ALJ4PS","./Point":"6tXgqr","bignum":57,"buffer":91,"buffertools":"fugeBw"}],"./lib/HierarchicalKey":[function(require,module,exports){ module.exports=require('x1O6JW'); },{}],"x1O6JW":[function(require,module,exports){ (function (Buffer){ var base58 = require('./Base58').base58; var coinUtil = require('../util'); var Key = require('./Key'); var Point = require('./Point'); var SecureRandom = require('./SecureRandom'); var bignum = require('bignum'); var networks = require('../networks'); var secp256k1_n = new bignum('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141', 16); var secp256k1_Gx = new bignum('79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798', 16); /* random new HierarchicalKey: new HierarchicalKey(); from extended public or private key: new HierarchicalKey(str); new blank HierarchicalKey: new HierarchicalKey(null); */ var HierarchicalKey = function(bytes) { if (typeof bytes == 'undefined' || bytes == 'mainnet' || bytes == 'livenet') { bytes = 'livenet'; this.version = networks['livenet'].hkeyPrivateVersion; } else if (bytes == 'testnet') { this.version = networks['testnet'].hkeyPrivateVersion; } if (bytes == 'livenet' || bytes == 'testnet') { this.depth = 0x00; this.parentFingerprint = new Buffer([0, 0, 0, 0]); this.childIndex = new Buffer([0, 0, 0, 0]); this.chainCode = SecureRandom.getRandomBuffer(32); this.eckey = Key.generateSync(); this.hasPrivateKey = true; this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); this.buildExtendedPublicKey(); this.buildExtendedPrivateKey(); return; } // decode base58 if (typeof bytes === 'string') { var decoded = base58.decode(bytes); if (decoded.length != 82) throw new Error('Not enough data, expected 82 and received ' + decoded.length); var checksum = decoded.slice(78, 82); bytes = decoded.slice(0, 78); var hash = coinUtil.sha256(coinUtil.sha256(bytes)); if (hash[0] != checksum[0] || hash[1] != checksum[1] || hash[2] != checksum[2] || hash[3] != checksum[3]) { throw new Error('Invalid checksum'); } } if (bytes !== undefined && bytes !== null) this.initFromBytes(bytes); } HierarchicalKey.seed = function(bytes, network) { if (!network) network = 'livenet'; if (!Buffer.isBuffer(bytes)) bytes = new Buffer(bytes, 'hex'); //if not buffer, assume hex if (bytes.length < 128 / 8) return false; //need more entropy if (bytes.length > 512 / 8) return false; var hash = coinUtil.sha512hmac(bytes, new Buffer('Bitcoin seed')); var hkey = new HierarchicalKey(null); hkey.depth = 0x00; hkey.parentFingerprint = new Buffer([0, 0, 0, 0]); hkey.childIndex = new Buffer([0, 0, 0, 0]); hkey.chainCode = hash.slice(32, 64); hkey.version = networks[network].hkeyPrivateVersion; hkey.eckey = new Key(); hkey.eckey.private = hash.slice(0, 32); hkey.eckey.regenerateSync(); hkey.hasPrivateKey = true; hkey.pubKeyHash = coinUtil.sha256ripe160(hkey.eckey.public); hkey.buildExtendedPublicKey(); hkey.buildExtendedPrivateKey(); return hkey; }; HierarchicalKey.prototype.initFromBytes = function(bytes) { // Both pub and private extended keys are 78 bytes if (bytes.length != 78) throw new Error('not enough data'); this.version = u32(bytes.slice(0, 4)); this.depth = u8(bytes.slice(4, 5)); this.parentFingerprint = bytes.slice(5, 9); this.childIndex = u32(bytes.slice(9, 13)); this.chainCode = bytes.slice(13, 45); var keyBytes = bytes.slice(45, 78); var isPrivate = (this.version == networks['livenet'].hkeyPrivateVersion || this.version == networks['testnet'].hkeyPrivateVersion); var isPublic = (this.version == networks['livenet'].hkeyPublicVersion || this.version == networks['testnet'].hkeyPublicVersion); if (isPrivate && keyBytes[0] == 0) { this.eckey = new Key(); this.eckey.private = keyBytes.slice(1, 33); this.eckey.compressed = true; this.eckey.regenerateSync(); this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); this.hasPrivateKey = true; } else if (isPublic && (keyBytes[0] == 0x02 || keyBytes[0] == 0x03)) { this.eckey = new Key(); this.eckey.public = keyBytes; this.pubKeyHash = coinUtil.sha256ripe160(this.eckey.public); this.hasPrivateKey = false; } else { throw new Error('Invalid key'); } this.buildExtendedPublicKey(); this.buildExtendedPrivateKey(); } HierarchicalKey.prototype.buildExtendedPublicKey = function() { this.extendedPublicKey = new Buffer([]); var v = null; switch (this.version) { case networks['livenet'].hkeyPublicVersion: case networks['livenet'].hkeyPrivateVersion: v = networks['livenet'].hkeyPublicVersion; break; case networks['testnet'].hkeyPublicVersion: case networks['testnet'].hkeyPrivateVersion: v = networks['testnet'].hkeyPublicVersion; break; default: throw new Error('Unknown version'); } // Version this.extendedPublicKey = Buffer.concat([ new Buffer([v >> 24]), new Buffer([(v >> 16) & 0xff]), new Buffer([(v >> 8) & 0xff]), new Buffer([v & 0xff]), new Buffer([this.depth]), this.parentFingerprint, new Buffer([this.childIndex >>> 24]), new Buffer([(this.childIndex >>> 16) & 0xff]), new Buffer([(this.childIndex >>> 8) & 0xff]), new Buffer([this.childIndex & 0xff]), this.chainCode, this.eckey.public ]); } HierarchicalKey.prototype.extendedPublicKeyString = function(format) { if (format === undefined || format === 'base58') { var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPublicKey)); var checksum = hash.slice(0, 4); var data = Buffer.concat([this.extendedPublicKey, checksum]); return base58.encode(data); } else if (format === 'hex') { return this.extendedPublicKey.toString('hex');; } else { throw new Error('bad format'); } } HierarchicalKey.prototype.buildExtendedPrivateKey = function() { if (!this.hasPrivateKey) return; this.extendedPrivateKey = new Buffer([]); var v = this.version; this.extendedPrivateKey = Buffer.concat([ new Buffer([v >> 24]), new Buffer([(v >> 16) & 0xff]), new Buffer([(v >> 8) & 0xff]), new Buffer([v & 0xff]), new Buffer([this.depth]), this.parentFingerprint, new Buffer([this.childIndex >>> 24]), new Buffer([(this.childIndex >>> 16) & 0xff]), new Buffer([(this.childIndex >>> 8) & 0xff]), new Buffer([this.childIndex & 0xff]), this.chainCode, new Buffer([0]), this.eckey.private ]); } HierarchicalKey.prototype.extendedPrivateKeyString = function(format) { if (format === undefined || format === 'base58') { var hash = coinUtil.sha256(coinUtil.sha256(this.extendedPrivateKey)); var checksum = hash.slice(0, 4); var data = Buffer.concat([this.extendedPrivateKey, checksum]); return base58.encode(data); } else if (format === 'hex') { return this.extendedPrivateKey.toString('hex'); } else { throw new Error('bad format'); } } HierarchicalKey.prototype.derive = function(path) { var e = path.split('/'); // Special cases: if (path == 'm' || path == 'M' || path == 'm\'' || path == 'M\'') return this; var hkey = this; for (var i in e) { var c = e[i]; if (i == 0) { if (c != 'm') throw new Error('invalid path'); continue; } var usePrivate = (c.length > 1) && (c[c.length - 1] == '\''); var childIndex = parseInt(usePrivate ? c.slice(0, c.length - 1) : c) & 0x7fffffff; if (usePrivate) childIndex += 0x80000000; hkey = hkey.deriveChild(childIndex); } return hkey; } HierarchicalKey.prototype.deriveChild = function(i) { var ib = []; ib.push((i >> 24) & 0xff); ib.push((i >> 16) & 0xff); ib.push((i >> 8) & 0xff); ib.push(i & 0xff); ib = new Buffer(ib); var usePrivate = (i & 0x80000000) != 0; var isPrivate = (this.version == networks['livenet'].hkeyPrivateVersion || this.version == networks['testnet'].hkeyPrivateVersion); if (usePrivate && (!this.hasPrivateKey || !isPrivate)) throw new Error('Cannot do private key derivation without private key'); var ret = null; if (this.hasPrivateKey) { var data = null; if (usePrivate) { data = Buffer.concat([new Buffer([0]), this.eckey.private, ib]); } else { data = Buffer.concat([this.eckey.public, ib]); } var hash = coinUtil.sha512hmac(data, this.chainCode); var il = bignum.fromBuffer(hash.slice(0, 32), { size: 32 }); var ir = hash.slice(32, 64); // ki = IL + kpar (mod n). var priv = bignum.fromBuffer(this.eckey.private, { size: 32 }); var k = il.add(priv).mod(secp256k1_n); ret = new HierarchicalKey(null); ret.chainCode = ir; ret.eckey = new Key(); ret.eckey.private = k.toBuffer({ size: 32 }); ret.eckey.regenerateSync(); ret.hasPrivateKey = true; } else { var data = Buffer.concat([this.eckey.public, ib]); var hash = coinUtil.sha512hmac(data, this.chainCode); var il = hash.slice(0, 32); var ir = hash.slice(32, 64); // Ki = (IL + kpar)*G = IL*G + Kpar var ilGkey = new Key(); ilGkey.private = il; ilGkey.regenerateSync(); ilGkey.compressed = false; var ilG = Point.fromUncompressedPubKey(ilGkey.public); var oldkey = new Key(); oldkey.public = this.eckey.public; oldkey.compressed = false; var Kpar = Point.fromUncompressedPubKey(oldkey.public); var newpub = Point.add(ilG, Kpar).toUncompressedPubKey(); ret = new HierarchicalKey(null); ret.chainCode = new Buffer(ir); var eckey = new Key(); eckey.public = newpub; eckey.compressed = true; ret.eckey = eckey; ret.hasPrivateKey = false; } ret.childIndex = i; ret.parentFingerprint = this.pubKeyHash.slice(0, 4); ret.version = this.version; ret.depth = this.depth + 1; ret.eckey.compressed = true; ret.pubKeyHash = coinUtil.sha256ripe160(ret.eckey.public); ret.buildExtendedPublicKey(); ret.buildExtendedPrivateKey(); return ret; } function uint(f, size) { if (f.length < size) throw new Error('not enough data'); var n = 0; for (var i = 0; i < size; i++) { n *= 256; n += f[i]; } return n; } function u8(f) { return uint(f, 1); } function u16(f) { return uint(f, 2); } function u32(f) { return uint(f, 4); } function u64(f) { return uint(f, 8); } module.exports = HierarchicalKey; }).call(this,require("buffer").Buffer) },{"../networks":"ULNIu2","../util":181,"./Base58":"6VqyzY","./Key":"ALJ4PS","./Point":"6tXgqr","./SecureRandom":"p4SiC2","bignum":57,"buffer":91}],"CBDCgz":[function(require,module,exports){ (function (Buffer){ 'use strict'; var coinUtil = require('../util'); var Key = require('./Key'); var Message = function() {}; Message.sign = function(str, key) { var hash = Message.magicHash(str); var sig = key.signSync(hash); return sig; }; Message.verifyWithPubKey = function(pubkey, message, sig) { var hash = Message.magicHash(message); var key = new Key(); if (pubkey.length == 65) key.compressed = false; key.public = pubkey; return key.verifySignatureSync(hash, sig); }; //TODO: Message.verify ... with address, not pubkey Message.magicBytes = new Buffer('Bitcoin Signed Message:\n'); Message.magicHash = function(str) { var magicBytes = Message.magicBytes; var prefix1 = coinUtil.varIntBuf(magicBytes.length); var message = new Buffer(str); var prefix2 = coinUtil.varIntBuf(message.length); var buf = Buffer.concat([prefix1, magicBytes, prefix2, message]); var hash = coinUtil.twoSha256(buf); return hash; }; module.exports = Message; }).call(this,require("buffer").Buffer) },{"../util":181,"./Key":"ALJ4PS","buffer":91}],"./lib/Message":[function(require,module,exports){ module.exports=require('CBDCgz'); },{}],"Zm7/h9":[function(require,module,exports){ function Opcode(num) { this.code = num; }; Opcode.prototype.toString = function() { return Opcode.reverseMap[this.code]; }; Opcode.map = { // push value OP_FALSE: 0, OP_0: 0, OP_PUSHDATA1: 76, OP_PUSHDATA2: 77, OP_PUSHDATA4: 78, OP_1NEGATE: 79, OP_RESERVED: 80, OP_TRUE: 81, OP_1: 81, OP_2: 82, OP_3: 83, OP_4: 84, OP_5: 85, OP_6: 86, OP_7: 87, OP_8: 88, OP_9: 89, OP_10: 90, OP_11: 91, OP_12: 92, OP_13: 93, OP_14: 94, OP_15: 95, OP_16: 96, // control OP_NOP: 97, OP_VER: 98, OP_IF: 99, OP_NOTIF: 100, OP_VERIF: 101, OP_VERNOTIF: 102, OP_ELSE: 103, OP_ENDIF: 104, OP_VERIFY: 105, OP_RETURN: 106, // stack ops OP_TOALTSTACK: 107, OP_FROMALTSTACK: 108, OP_2DROP: 109, OP_2DUP: 110, OP_3DUP: 111, OP_2OVER: 112, OP_2ROT: 113, OP_2SWAP: 114, OP_IFDUP: 115, OP_DEPTH: 116, OP_DROP: 117, OP_DUP: 118, OP_NIP: 119, OP_OVER: 120, OP_PICK: 121, OP_ROLL: 122, OP_ROT: 123, OP_SWAP: 124, OP_TUCK: 125, // splice ops OP_CAT: 126, OP_SUBSTR: 127, OP_LEFT: 128, OP_RIGHT: 129, OP_SIZE: 130, // bit logic OP_INVERT: 131, OP_AND: 132, OP_OR: 133, OP_XOR: 134, OP_EQUAL: 135, OP_EQUALVERIFY: 136, OP_RESERVED1: 137, OP_RESERVED2: 138, // numeric OP_1ADD: 139, OP_1SUB: 140, OP_2MUL: 141, OP_2DIV: 142, OP_NEGATE: 143, OP_ABS: 144, OP_NOT: 145, OP_0NOTEQUAL: 146, OP_ADD: 147, OP_SUB: 148, OP_MUL: 149, OP_DIV: 150, OP_MOD: 151, OP_LSHIFT: 152, OP_RSHIFT: 153, OP_BOOLAND: 154, OP_BOOLOR: 155, OP_NUMEQUAL: 156, OP_NUMEQUALVERIFY: 157, OP_NUMNOTEQUAL: 158, OP_LESSTHAN: 159, OP_GREATERTHAN: 160, OP_LESSTHANOREQUAL: 161, OP_GREATERTHANOREQUAL: 162, OP_MIN: 163, OP_MAX: 164, OP_WITHIN: 165, // crypto OP_RIPEMD160: 166, OP_SHA1: 167, OP_SHA256: 168, OP_HASH160: 169, OP_HASH256: 170, OP_CODESEPARATOR: 171, OP_CHECKSIG: 172, OP_CHECKSIGVERIFY: 173, OP_CHECKMULTISIG: 174, OP_CHECKMULTISIGVERIFY: 175, // expansion OP_NOP1: 176, OP_NOP2: 177, OP_NOP3: 178, OP_NOP4: 179, OP_NOP5: 180, OP_NOP6: 181, OP_NOP7: 182, OP_NOP8: 183, OP_NOP9: 184, OP_NOP10: 185, // template matching params OP_PUBKEYHASH: 253, OP_PUBKEY: 254, OP_INVALIDOPCODE: 255 }; Opcode.reverseMap = []; for (var k in Opcode.map) { if (Opcode.map.hasOwnProperty(k)) { Opcode.reverseMap[Opcode.map[k]] = k.substr(3); } } Opcode.asList = function() { var keys = []; for (var prop in Opcode.map) { if (Opcode.map.hasOwnProperty(prop)) { keys.push(prop); } } return keys; }; module.exports = Opcode; },{}],"./lib/Opcode":[function(require,module,exports){ module.exports=require('Zm7/h9'); },{}],"./lib/Peer":[function(require,module,exports){ module.exports=require('oolY81'); },{}],"oolY81":[function(require,module,exports){ (function (Buffer){ var Net = require('net'); var Binary = require('binary'); var buffertools = require('buffertools'); function Peer(host, port, services) { if ("string" === typeof host) { if (host.indexOf(':') && !port) { var parts = host.split(':'); host = parts[0]; port = parts[1]; } this.host = host; this.port = +port || 8333; } else if (host instanceof Peer) { this.host = host.host; this.port = host.port; } else if (Buffer.isBuffer(host)) { if (buffertools.compare(Peer.IPV6_IPV4_PADDING, host.slice(0, 12)) != 0) { throw new Error('IPV6 not supported yet! Cannot instantiate host.'); } this.host = Array.prototype.slice.apply(host.slice(12)).join('.'); this.port = +port || 8333; } else { throw new Error('Could not instantiate peer, invalid parameter type: ' + typeof host); } this.services = (services) ? services : null; this.lastSeen = 0; }; Peer.IPV6_IPV4_PADDING = new Buffer([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255]); Peer.prototype.createConnection = function() { this.connection = Net.createConnection(this.port, this.host); return this.connection; }; Peer.prototype.getHostAsBuffer = function() { return new Buffer(this.host.split('.')); }; Peer.prototype.toString = function() { return this.host + ":" + this.port; }; Peer.prototype.toBuffer = function() { var put = Binary.put(); put.word32le(this.lastSeen); put.word64le(this.services); put.put(this.getHostAsBuffer()); put.word16be(this.port); return put.buffer(); }; module.exports = Peer; }).call(this,require("buffer").Buffer) },{"binary":79,"buffer":91,"buffertools":"fugeBw","net":87}],"./lib/PeerManager":[function(require,module,exports){ module.exports=require('nsqKeP'); },{}],"nsqKeP":[function(require,module,exports){ var log = require('../util/log'); var bitcoreDefaults = require('../config'); var Connection = require('./Connection'); var Peer = require('./Peer'); var async = require('async'); var dns = require('dns'); var networks = require('../networks'); var util = require('util'); GetAdjustedTime = function() { // TODO: Implement actual adjustment return Math.floor(new Date().getTime() / 1000); }; function PeerManager(config) { // extend defaults with config this.config = config || {}; for (var i in bitcoreDefaults) if (bitcoreDefaults.hasOwnProperty(i) && this.config[i] === undefined) this.config[i] = bitcoreDefaults[i]; this.active = false; this.timer = null; this.peers = []; this.pool = []; this.connections = []; this.isConnected = false; this.peerDiscovery = false; // Move these to the Node's settings object this.interval = 5000; this.minConnections = 8; this.minKnownPeers = 10; // keep track of tried seeds and results this.seeds = { resolved: [], failed: [] }; } var EventEmitter = require('events').EventEmitter; util.inherits(PeerManager, EventEmitter); PeerManager.Connection = Connection; PeerManager.prototype.start = function() { this.active = true; if (!this.timer) { this.timer = setInterval(this.checkStatus.bind(this), this.interval); } }; PeerManager.prototype.stop = function() { this.active = false; if (this.timer) { clearInterval(this.timer); this.timer = null; } for (var i = 0; i < this.connections.length; i++) { this.connections[i].socket.end(); }; }; PeerManager.prototype.addPeer = function(peer, port) { if (peer instanceof Peer) { this.peers.push(peer); } else if ("string" == typeof peer) { this.addPeer(new Peer(peer, port)); } else { log.err('Node.addPeer(): Invalid value provided for peer', { val: peer }); throw 'Node.addPeer(): Invalid value provided for peer.'; } }; PeerManager.prototype.removePeer = function(peer) { var index = this.peers.indexOf(peer); var exists = !!~index; if (exists) this.peers.splice(index, 1); return exists; }; PeerManager.prototype.checkStatus = function checkStatus() { // Make sure we are connected to all forcePeers if (this.peers.length) { var peerIndex = {}; this.peers.forEach(function(peer) { peerIndex[peer.toString()] = peer; }); // Ignore the ones we're already connected to this.connections.forEach(function(conn) { var peerName = conn.peer.toString(); if ("undefined" !== peerIndex[peerName]) { delete peerIndex[peerName]; } }); // for debug purposes, print how many of our peers are actually connected var connected = 0 this.peers.forEach(function(p) { if (p.connection && !p.connection._connecting) connected++ }); log.debug(connected + ' of ' + this.peers.length + ' peers connected'); Object.keys(peerIndex).forEach(function(i) { this.connectTo(peerIndex[i]); }.bind(this)); } }; PeerManager.prototype.connectTo = function(peer) { log.info('connecting to ' + peer); try { return this.addConnection(peer.createConnection(), peer); } catch (e) { log.err('creating connection', e); return null; } }; PeerManager.prototype.addConnection = function(socketConn, peer) { var conn = new Connection(socketConn, peer, this.config); this.connections.push(conn); this.emit('connection', conn); conn.addListener('version', this.handleVersion.bind(this)); conn.addListener('verack', this.handleReady.bind(this)); conn.addListener('addr', this.handleAddr.bind(this)); conn.addListener('getaddr', this.handleGetAddr.bind(this)); conn.addListener('error', this.handleError.bind(this)); conn.addListener('disconnect', this.handleDisconnect.bind(this)); return conn; }; PeerManager.prototype.handleVersion = function(e) { e.peer.version = e.message.version; e.peer.start_height = e.message.start_height; if (!e.conn.inbound) { // TODO: Advertise our address (if listening) } // Get recent addresses if (this.peerDiscovery && (e.message.version >= 31402 || this.peers.length < 1000)) { e.conn.sendGetAddr(); e.conn.getaddr = true; } }; PeerManager.prototype.handleReady = function(e) { log.info('connected to ' + e.conn.peer.host + ':' + e.conn.peer.port); this.emit('connect', { pm: this, conn: e.conn, socket: e.socket, peer: e.peer }); if (this.isConnected == false) { this.emit('netConnected', e); this.isConnected = true; } }; PeerManager.prototype.handleAddr = function(e) { if (!this.peerDiscovery) return; var now = GetAdjustedTime(); e.message.addrs.forEach(function(addr) { try { // In case of an invalid time, assume "5 days ago" if (addr.time <= 100000000 || addr.time > (now + 10 * 60)) { addr.time = now - 5 * 24 * 60 * 60; } var peer = new Peer(addr.ip, addr.port, addr.services); peer.lastSeen = addr.time; // TODO: Handle duplicate peers this.peers.push(peer); // TODO: Handle addr relay } catch (e) { log.warn("Invalid addr received: " + e.message); } }.bind(this)); if (e.message.addrs.length < 1000) { e.conn.getaddr = false; } }; PeerManager.prototype.handleGetAddr = function(e) { // TODO: Reply with addr message. }; PeerManager.prototype.handleError = function(e) { log.err('unkown error with peer ' + e.peer + ' (disconnecting): ' + e.err); this.handleDisconnect.apply(this, [].slice.call(arguments)); }; PeerManager.prototype.handleDisconnect = function(e) { log.info('disconnected from peer ' + e.peer); var i = this.connections.indexOf(e.conn); if (i != -1) this.connections.splice(i, 1); this.removePeer(e.peer); if (this.pool.length) { log.info('replacing peer using the pool of ' + this.pool.length + ' seeds'); this.addPeer(this.pool.pop()); } if (!this.connections.length) { this.emit('netDisconnected'); this.isConnected = false; } }; PeerManager.prototype.getActiveConnection = function() { var activeConnections = this.connections.filter(function(conn) { return conn.active; }); if (activeConnections.length) { var randomIndex = Math.floor(Math.random() * activeConnections.length); var candidate = activeConnections[randomIndex]; if (candidate.socket.writable) { return candidate; } else { // Socket is not writable, remove it from active connections activeConnections.splice(randomIndex, 1); // Then try again // TODO: This causes an infinite recursion when all connections are dead, // although it shouldn't. return this.getActiveConnection(); } } else { return null; } }; PeerManager.prototype.getActiveConnections = function() { return this.connections.slice(0); }; PeerManager.prototype.discover = function(options, callback) { var self = this; var seeds = networks[self.config.network].dnsSeeds; self.limit = options.limit || 12; var dnsExecutor = seeds.map(function(seed) { return function(done) { // have we already resolved this seed? if (~self.seeds.resolved.indexOf(seed)) { // if so, just pass back cached peer list return done(null, self.seeds.results[seed]); } // has this seed failed to resolve? if (~self.seeds.failed.indexOf(seed)) { // if so, pass back empty results return done(null, []); } log.info('resolving dns seed ' + seed); dns.resolve(seed, function(err, peers) { if (err) { log.err('failed to resolve dns seed ' + seed, err); self.seeds.failed.push(seed); return done(null, []); } log.info('found ' + peers.length + ' peers from ' + seed); self.seeds.resolved.push(seed); // transform that list into a list of Peer instances peers = peers.map(function(ip) { return new Peer(ip, networks[self.config.network].defaultClientPort); }); peers.forEach(function(p) { if (self.peers.length < self.limit) self.addPeer(p); else self.pool.push(p); }); self.emit('peers', peers); return done(null, peers); }); }; }); // try resolving all seeds async.parallel(dnsExecutor, function(err, results) { var peers = []; // consolidate all resolved peers into one list results.forEach(function(peerlist) { peers = peers.concat(peerlist); }); if (typeof callback === 'function') callback(null, peers); }); return self; }; module.exports = PeerManager; },{"../config":"4itQ50","../networks":"ULNIu2","../util/log":"AdF7pF","./Connection":"DB/p3X","./Peer":"oolY81","async":78,"dns":87,"events":100,"util":123}],"izTl9z":[function(require,module,exports){ (function (Buffer){ var VersionedData = require('../util/VersionedData'); var EncodedData = require('../util/EncodedData'); var networks = require('../networks'); var util = require('util'); //compressed is true if public key is compressed; false otherwise function PrivateKey(version, buf, compressed) { PrivateKey.super_.call(this, version, buf); if (compressed !== undefined) this.compressed(compressed); }; util.inherits(PrivateKey, VersionedData); EncodedData.applyEncodingsTo(PrivateKey); PrivateKey.prototype.validate = function() { this.doAsBinary(function() { PrivateKey.super_.prototype.validate.call(this); 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'); }); if (typeof this.network() === 'undefined') throw new Error('invalid network'); }; // get or set the payload data (as a Buffer object) // overloaded from VersionedData PrivateKey.prototype.payload = function(data) { if (data) { this.doAsBinary(function() { data.copy(this.data, 1); }); return data; } var buf = this.as('binary'); if (buf.length == 1 + 32 + 1) return buf.slice(1, 1 + 32); else if (buf.length == 1 + 32) return buf.slice(1); }; // get or set whether the corresponding public key is compressed PrivateKey.prototype.compressed = function(compressed) { if (compressed !== undefined) { this.doAsBinary(function() { var len = 1 + 32 + 1; if (compressed) { var data = new Buffer(len); this.data.copy(data); this.data = data; this.data[len - 1] = 1; } else { this.data = this.data.slice(0, len - 1); } }); } else { var len = 1 + 32 + 1; var data = this.as('binary'); if (data.length == len && data[len - 1] == 1) return true; else if (data.length == len - 1) return false; else throw new Error('invalid private key'); } }; PrivateKey.prototype.network = function() { var version = this.version(); var livenet = networks.livenet; var testnet = networks.testnet; var answer; if (version === livenet.privKeyVersion) answer = livenet; else if (version === testnet.privKeyVersion) answer = testnet; return answer; }; module.exports = PrivateKey; }).call(this,require("buffer").Buffer) },{"../networks":"ULNIu2","../util/EncodedData":"eLfUFE","../util/VersionedData":"QLzNQg","buffer":91,"util":123}],"./lib/PrivateKey":[function(require,module,exports){ module.exports=require('izTl9z'); },{}],"./lib/RpcClient":[function(require,module,exports){ module.exports=require('7siE1N'); },{}],"7siE1N":[function(require,module,exports){ (function (Buffer){ // RpcClient.js // MIT/X11-like license. See LICENSE.txt. // Copyright 2013 BitPay, Inc. // var http = require('http'); var https = require('https'); var log = require('../util/log'); function RpcClient(opts) { opts = opts || {}; this.host = opts.host || '127.0.0.1'; this.port = opts.port || 8332; this.user = opts.user || 'user'; this.pass = opts.pass || 'pass'; this.protocol = (opts.protocol == 'http') ? http : https; this.batchedCalls = null; this.disableAgent = opts.disableAgent || false; } RpcClient.prototype.batch = function(batchCallback, resultCallback) { this.batchedCalls = []; batchCallback(); rpc.call(this, this.batchedCalls, resultCallback); this.batchedCalls = null; } var callspec = { addMultiSigAddress: '', addNode: '', backupWallet: '', createMultiSig: '', createRawTransaction: '', decodeRawTransaction: '', dumpPrivKey: '', encryptWallet: '', getAccount: '', getAccountAddress: 'str', getAddedNodeInfo: '', getAddressesByAccount: '', getBalance: 'str int', getBestBlockHash: '', getBlock: '', getBlockCount: '', getBlockHash: 'int', getBlockNumber: '', getBlockTemplate: '', getConnectionCount: '', getDifficulty: '', getGenerate: '', getHashesPerSec: '', getInfo: '', getMemoryPool: '', getMiningInfo: '', getNewAddress: '', getPeerInfo: '', getRawMemPool: '', getRawTransaction: 'str int', getReceivedByAccount: 'str int', getReceivedByAddress: 'str int', getTransaction: '', getTxOut: 'str int bool', getTxOutSetInfo: '', getWork: '', help: '', importAddress: 'str str bool', importPrivKey: 'str str bool', keyPoolRefill: '', listAccounts: 'int', listAddressGroupings: '', listReceivedByAccount: 'int bool', listReceivedByAddress: 'int bool', listSinceBlock: 'str int', listTransactions: 'str int int', listUnspent: 'int int', listLockUnspent: 'bool', lockUnspent: '', move: 'str str float int str', sendFrom: 'str str float int str str', sendMany: 'str str int str', //not sure this is will work sendRawTransaction: '', sendToAddress: 'str float str str', setAccount: '', setGenerate: 'bool int', setTxFee: 'float', signMessage: '', signRawTransaction: '', stop: '', submitBlock: '', validateAddress: '', verifyMessage: '', walletLock: '', walletPassPhrase: 'string int', walletPassphraseChange: '', }; var slice = function(arr, start, end) { return Array.prototype.slice.call(arr, start, end); }; function generateRPCMethods(constructor, apiCalls, rpc) { function createRPCMethod(methodName, argMap) { return function() { var limit = arguments.length - 1; if (this.batchedCalls) var limit = arguments.length; for (var i = 0; i < limit; i++) { if (argMap[i]) arguments[i] = argMap[i](arguments[i]); }; if (this.batchedCalls) { this.batchedCalls.push({ jsonrpc: '2.0', method: methodName, params: slice(arguments) }); } else { rpc.call(this, { method: methodName, params: slice(arguments, 0, arguments.length - 1) }, arguments[arguments.length - 1]); } }; }; var types = { str: function(arg) { return arg.toString(); }, int: function(arg) { return parseFloat(arg); }, float: function(arg) { return parseFloat(arg); }, bool: function(arg) { return (arg === true || arg == '1' || arg == 'true' || arg.toString().toLowerCase() == 'true'); }, }; for (var k in apiCalls) { if (apiCalls.hasOwnProperty(k)) { var spec = apiCalls[k].split(' '); for (var i = 0; i < spec.length; i++) { if (types[spec[i]]) { spec[i] = types[spec[i]]; } else { spec[i] = types.string; } } var methodName = k.toLowerCase(); constructor.prototype[k] = createRPCMethod(methodName, spec); constructor.prototype[methodName] = constructor.prototype[k]; } } } function rpc(request, callback) { var self = this; var request; request = JSON.stringify(request); var auth = Buffer(self.user + ':' + self.pass).toString('base64'); var options = { host: self.host, path: '/', method: 'POST', port: self.port, agent: self.disableAgent ? false : undefined, }; if (self.httpOptions) { for (var k in self.httpOptions) { options[k] = self.httpOptions[k]; } } var err = null; var req = this.protocol.request(options, function(res) { var buf = ''; res.on('data', function(data) { buf += data; }); res.on('end', function() { if (res.statusCode == 401) { callback(new Error('bitcoin JSON-RPC connection rejected: 401 unauthorized')); return; } if (res.statusCode == 403) { callback(new Error('bitcoin JSON-RPC connection rejected: 403 forbidden')); return; } if (err) { callback(err); return; } try { var parsedBuf = JSON.parse(buf); } catch (e) { log.err(e.stack); log.err(buf); log.err('HTTP Status code:' + res.statusCode); callback(e); return; } callback(parsedBuf.error, parsedBuf); }); }); req.on('error', function(e) { var err = new Error('Could not connect to bitcoin via RPC: ' + e.message); log.err(err); callback(err); }); req.setHeader('Content-Length', request.length); req.setHeader('Content-Type', 'application/json'); req.setHeader('Authorization', 'Basic ' + auth); req.write(request); req.end(); }; generateRPCMethods(RpcClient, callspec, rpc); module.exports = RpcClient; }).call(this,require("buffer").Buffer) },{"../util/log":"AdF7pF","buffer":91,"http":101,"https":105}],"./lib/SIN":[function(require,module,exports){ module.exports=require('tBM27q'); },{}],"tBM27q":[function(require,module,exports){ (function (Buffer){ 'use strict'; var VersionedData = require('../util/VersionedData'); var EncodedData = require('../util/EncodedData'); var util = require('util'); var coinUtil = require('../util'); function SIN(type, payload) { if (typeof type != 'number') { SIN.super_.call(this, type, payload); return; } this.data = new Buffer(1 + 1 + payload.length); this.converters = this.encodings['binary'].converters; this._encoding = this.encodings['binary']._encoding; this.encoding('binary'); this.prefix(0x0F); // SIN magic number, in numberspace this.type(type); this.payload(payload); }; util.inherits(SIN, VersionedData); EncodedData.applyEncodingsTo(SIN); SIN.SIN_PERSIST_MAINNET = 0x01; // associated with sacrifice TX SIN.SIN_PERSIST_TESTNET = 0x11; // associated with sacrifice TX SIN.SIN_EPHEM = 0x02; // generate off-net at any time // get or set the prefix data (the first byte of the address) SIN.prototype.prefix = function(num) { if (num || (num === 0)) { this.doAsBinary(function() { this.data.writeUInt8(num, 0); }); return num; } return this.as('binary').readUInt8(0); }; // get or set the SIN-type data (the second byte of the address) SIN.prototype.type = function(num) { if (num || (num === 0)) { this.doAsBinary(function() { this.data.writeUInt8(num, 1); }); return num; } return this.as('binary').readUInt8(1); }; // get or set the payload data (as a Buffer object) SIN.prototype.payload = function(data) { if (data) { this.doAsBinary(function() { data.copy(this.data, 2); }); return data; } return this.as('binary').slice(1); }; SIN.prototype.validate = function() { this.doAsBinary(function() { SIN.super_.prototype.validate.call(this); if (this.data.length != 22) throw new Error('invalid data length'); }); }; // create a SIN from a public key SIN.fromPubKey = function(pubKey, type) { if (!type) type = SIN.SIN_EPHEM; if (!Buffer.isBuffer(pubKey) || (pubKey.length !== 33 && pubKey.length != 65)) throw new Error('Invalid public key'); var hash = coinUtil.sha256ripe160(pubKey); return new SIN(hash, type); }; module.exports = SIN; }).call(this,require("buffer").Buffer) },{"../util":181,"../util/EncodedData":"eLfUFE","../util/VersionedData":"QLzNQg","buffer":91,"util":123}],"EyghZQ":[function(require,module,exports){ var coinUtil = require('../util'); var timeUtil = require('../util/time'); var Key = require('./Key'); var SIN = require('./SIN'); function SINKey(cfg) { if (typeof cfg != 'object') cfg = {}; this.created = cfg.created; this.privKey = cfg.privKey; }; SINKey.prototype.generate = function() { this.privKey = Key.generateSync(); this.created = timeUtil.curtime(); }; SINKey.prototype.pubkeyHash = function() { return coinUtil.sha256ripe160(this.privKey.public); }; SINKey.prototype.storeObj = function() { var pubKey = this.privKey.public.toString('hex'); var pubKeyHash = this.pubkeyHash(); var sin = new SIN(SIN.SIN_EPHEM, pubKeyHash); var obj = { created: this.created, priv: this.privKey.private.toString('hex'), pub: pubKey, sin: sin.toString(), }; return obj; }; module.exports = SINKey; },{"../util":181,"../util/time":184,"./Key":"ALJ4PS","./SIN":"tBM27q"}],"./lib/SINKey":[function(require,module,exports){ module.exports=require('EyghZQ'); },{}],"hQ0t76":[function(require,module,exports){ (function (Buffer){ var config = require('../config'); var log = require('../util/log'); var Opcode = require('./Opcode'); var buffertools = require('buffertools'); var util = require('../util/util'); var Parser = require('../util/BinaryParser'); var Put = require('bufferput'); var TX_UNKNOWN = 0; var TX_PUBKEY = 1; var TX_PUBKEYHASH = 2; var TX_MULTISIG = 3; var TX_SCRIPTHASH = 4; var TX_TYPES = [ 'unknown', 'pubkey', 'pubkeyhash', 'multisig', 'scripthash' ]; function Script(buffer) { if (buffer) { this.buffer = buffer; } else { this.buffer = util.EMPTY_BUFFER; } this.chunks = []; this.parse(); } Script.TX_UNKNOWN = TX_UNKNOWN; Script.TX_PUBKEY = TX_PUBKEY; Script.TX_PUBKEYHASH = TX_PUBKEYHASH; Script.TX_MULTISIG = TX_MULTISIG; Script.TX_SCRIPTHASH = TX_SCRIPTHASH; Script.prototype.parse = function() { this.chunks = []; var parser = new Parser(this.buffer); while (!parser.eof()) { var opcode = parser.word8(); var len, chunk; if (opcode > 0 && opcode < Opcode.map.OP_PUSHDATA1) { // Read some bytes of data, opcode value is the length of data this.chunks.push(parser.buffer(opcode)); } else if (opcode === Opcode.map.OP_PUSHDATA1) { len = parser.word8(); chunk = parser.buffer(len); this.chunks.push(chunk); } else if (opcode === Opcode.map.OP_PUSHDATA2) { len = parser.word16le(); chunk = parser.buffer(len); this.chunks.push(chunk); } else if (opcode === Opcode.map.OP_PUSHDATA4) { len = parser.word32le(); chunk = parser.buffer(len); this.chunks.push(chunk); } else { this.chunks.push(opcode); } } }; Script.prototype.isPushOnly = function() { for (var i = 0; i < this.chunks.length; i++) { var op = this.chunks[i]; if (!Buffer.isBuffer(op) && op > Opcode.map.OP_16) { return false; } } return true; }; Script.prototype.isP2SH = function() { return (this.chunks.length == 3 && this.chunks[0] == Opcode.map.OP_HASH160 && Buffer.isBuffer(this.chunks[1]) && this.chunks[1].length == 20 && this.chunks[2] == Opcode.map.OP_EQUAL); }; Script.prototype.isPubkey = function() { return (this.chunks.length == 2 && Buffer.isBuffer(this.chunks[0]) && this.chunks[1] == Opcode.map.OP_CHECKSIG); }; Script.prototype.isPubkeyHash = function() { return (this.chunks.length == 5 && this.chunks[0] == Opcode.map.OP_DUP && this.chunks[1] == Opcode.map.OP_HASH160 && Buffer.isBuffer(this.chunks[2]) && this.chunks[2].length == 20 && this.chunks[3] == Opcode.map.OP_EQUALVERIFY && this.chunks[4] == Opcode.map.OP_CHECKSIG); }; function isSmallIntOp(opcode) { return ((opcode == Opcode.map.OP_0) || ((opcode >= Opcode.map.OP_1) && (opcode <= Opcode.map.OP_16))); }; Script.prototype.isMultiSig = function() { return (this.chunks.length > 3 && isSmallIntOp(this.chunks[0]) && this.chunks.slice(1, this.chunks.length - 2).every(function(i) { return Buffer.isBuffer(i); }) && isSmallIntOp(this.chunks[this.chunks.length - 2]) && this.chunks[this.chunks.length - 1] == Opcode.map.OP_CHECKMULTISIG); }; Script.prototype.isP2shScriptSig = function() { if (!isSmallIntOp(this.chunks[0]) || this.chunks[0] !== 0) return false; var redeemScript = new Script(this.chunks[this.chunks.length - 1]); var type = redeemScript.classify(); return type !== TX_UNKNOWN; }; Script.prototype.isMultiSigScriptSig = function() { if (!isSmallIntOp(this.chunks[0]) || this.chunks[0] !== 0) return false; return !this.isP2shScriptSig(); }; Script.prototype.countSignatures = function() { var ret = 0; var l = this.chunks.length; // Multisig? if (this.isMultiSigScriptSig()) { ret = l - 1; } else if (this.isP2shScriptSig()) { ret = l - 2; } // p2pubkey or p2pubkeyhash else { ret = buffertools.compare(this.getBuffer(), util.EMPTY_BUFFER) === 0 ? 0 : 1; } return ret; }; Script.prototype.countMissingSignatures = function() { if (this.isMultiSig()) { log.debug("Can not count missing signatures on normal Multisig script"); return null; } var ret = 0; var l = this.chunks.length; // P2SH? if (isSmallIntOp(this.chunks[0]) && this.chunks[0] === 0) { var redeemScript = new Script(this.chunks[l - 1]); if (!isSmallIntOp(redeemScript.chunks[0])) { log.debug("Unrecognized script type"); } else { var nreq = redeemScript.chunks[0] - 80; //see OP_2-OP_16 ret = nreq - (l - 2); // 2-> marked 0 + redeemScript } } // p2pubkey or p2pubkeyhash else { if (buffertools.compare(this.getBuffer(), util.EMPTY_BUFFER) === 0) { ret = 1; } } return ret; }; Script.prototype.finishedMultiSig = function() { var missing = this.countMissingSignatures(); if (missing === null) return null; return missing === 0; }; Script.prototype.getMultiSigInfo = function() { if (!this.isMultiSig()) { throw new Error("Script.getMultiSigInfo(): Not a multiSig script."); } var nsigs = this.chunks[0] - 80; //see OP_2-OP_16; var npubkeys = this.chunks[this.chunks.length - 2] - 80; //see OP_2-OP_16; var pubkeys = []; for (var i = 1; i < this.chunks.length - 2; i++) { pubkeys.push(this.chunks[i]); } if (pubkeys.length != npubkeys) { throw new Error("Script.getMultiSigInfo(): Amount of PKs does not match what the script specifies."); } return { nsigs: nsigs, npubkeys: npubkeys, pubkeys: pubkeys } }; Script.prototype.prependOp0 = function() { var chunks = [0]; for (i in this.chunks) { if (this.chunks.hasOwnProperty(i)) { chunks.push(this.chunks[i]); } } this.chunks = chunks; this.updateBuffer(); return this; }; // is this a script form we know? Script.prototype.classify = function() { if (this.isPubkeyHash()) return TX_PUBKEYHASH; if (this.isP2SH()) return TX_SCRIPTHASH; if (this.isMultiSig()) return TX_MULTISIG; if (this.isPubkey()) return TX_PUBKEY; return TX_UNKNOWN; }; // extract useful data items from known scripts Script.prototype.capture = function() { var txType = this.classify(); var res = []; switch (txType) { case TX_PUBKEY: res.push(this.chunks[0]); break; case TX_PUBKEYHASH: res.push(this.chunks[2]); break; case TX_MULTISIG: for (var i = 1; i < (this.chunks.length - 2); i++) res.push(this.chunks[i]); break; case TX_SCRIPTHASH: res.push(this.chunks[1]); break; case TX_UNKNOWN: default: // do nothing break; } return res; }; // return first extracted data item from script Script.prototype.captureOne = function() { var arr = this.capture(); return arr[0]; }; Script.prototype.getOutType = function() { var txType = this.classify(); switch (txType) { case TX_PUBKEY: return 'Pubkey'; case TX_PUBKEYHASH: return 'Address'; default: return 'Strange'; } }; Script.prototype.getRawOutType = function() { return TX_TYPES[this.classify()]; }; Script.prototype.simpleOutHash = function() { switch (this.getOutType()) { case 'Address': return this.chunks[2]; case 'Pubkey': return util.sha256ripe160(this.chunks[0]); default: log.debug("Encountered non-standard scriptPubKey"); log.debug("Strange script was: " + this.toString()); return null; } }; Script.prototype.getInType = function() { if (this.chunks.length == 1) { // Direct IP to IP transactions only have the public key in their scriptSig. return 'Pubkey'; } else if (this.chunks.length == 2 && Buffer.isBuffer(this.chunks[0]) && Buffer.isBuffer(this.chunks[1])) { return 'Address'; } else { return 'Strange'; } }; Script.prototype.simpleInPubKey = function() { switch (this.getInType()) { case 'Address': return this.chunks[1]; case 'Pubkey': return null; default: log.debug("Encountered non-standard scriptSig"); log.debug("Strange script was: " + this.toString()); return null; } }; Script.prototype.getBuffer = function() { return this.buffer; }; Script.prototype.serialize = Script.prototype.getBuffer; Script.prototype.getStringContent = function(truncate, maxEl) { if (truncate === null) { truncate = true; } if ('undefined' === typeof maxEl) { maxEl = 15; } var s = ''; for (var i = 0, l = this.chunks.length; i < l; i++) { var chunk = this.chunks[i]; if (i > 0) { s += ' '; } if (Buffer.isBuffer(chunk)) { s += '0x' + util.formatBuffer(chunk, truncate ? null : 0); } else { s += Opcode.reverseMap[chunk]; } if (maxEl && i > maxEl) { s += ' ...'; break; } } return s; }; Script.prototype.toString = function(truncate, maxEl) { var script = "