diff --git a/lib/bcoin.js b/lib/bcoin.js index ea3dcd73..419f9fd8 100644 --- a/lib/bcoin.js +++ b/lib/bcoin.js @@ -6,6 +6,9 @@ var bcoin = exports; var elliptic = require('elliptic'); +var bn = require('bn.js'); +var hash = require('hash.js'); +var async = require('async'); bcoin.ecdsa = elliptic.ec('secp256k1'); bcoin.utils = require('./bcoin/utils'); @@ -24,3 +27,8 @@ bcoin.pool = require('./bcoin/pool'); bcoin.hd = require('./bcoin/hd'); bcoin.protocol.network.set(process.env.BCOIN_NETWORK || 'main'); + +bcoin.bn = bn; +bcoin.elliptic = elliptic; +bcoin.hash = hash; +bcoin.async = async; diff --git a/lib/bcoin/block.js b/lib/bcoin/block.js index 63be46c5..ae6dfcfe 100644 --- a/lib/bcoin/block.js +++ b/lib/bcoin/block.js @@ -288,6 +288,17 @@ Block.prototype.__defineGetter__('rhash', function() { return utils.revHex(this.hash('hex')); }); +Block.prototype.inspect = function inspect() { + var copy = bcoin.block(this, this.subtype); + copy.__proto__ = null; + delete copy._raw; + copy.hash = this.hash('hex'); + copy.rhash = this.rhash; + copy.height = this.height; + copy.nextBlock = this.nextBlock; + return copy; +}; + Block.prototype.toJSON = function toJSON() { return { v: '1', diff --git a/lib/bcoin/input.js b/lib/bcoin/input.js index 6380db32..95aa46b2 100644 --- a/lib/bcoin/input.js +++ b/lib/bcoin/input.js @@ -36,7 +36,7 @@ function Input(options) { if (this.output) { lock = this.lock; - if (lock >= 0) { + if (lock > 0) { if (tx._lock === 0) tx.lock = Math.max(lock, tx.lock); if (!bcoin.script.spendable(this.output.script, tx.lock)) @@ -74,7 +74,7 @@ Input.prototype.__defineGetter__('type', function() { Input.prototype.__defineGetter__('lock', function() { if (!this.output) - return; + return 0; return this.output.lock; }); @@ -99,13 +99,24 @@ Input.getData = function getData(input) { return; var s = input.script; + var sub = bcoin.script.subscript(input.script); var sig, pub, hash, addr, redeem, data, output; + if (bcoin.script.lockTime(sub)) + sub = sub.slice(3); + if (!input.out) { return { type: 'unknown', - addr: '[unknown]', + side: 'input', + sig: null, + pub: null, hash: '[unknown]', + addr: '[unknown]', + multisig: null, + redeem: null, + data: null, + text: null, value: new bn(0), script: s, seq: input.seq, @@ -116,8 +127,15 @@ Input.getData = function getData(input) { if (+input.out.hash === 0) { return { type: 'coinbase', - addr: '[coinbase]', + side: 'input', + sig: null, + pub: null, hash: '[coinbase]', + addr: '[coinbase]', + multisig: null, + redeem: null, + data: null, + text: null, value: new bn(0), script: s, seq: input.seq, @@ -127,28 +145,67 @@ Input.getData = function getData(input) { if (input.out.tx) { output = input.out.tx.outputs[input.out.index]; - return bcoin.output.getData(output); + data = bcoin.output.getData(output); + data.seq = input.seq; + if (data.type === 'pubkey' || data.type === 'pubkeyhash') { + data.sig = sub[0]; + } else if (data.type === 'multisig') { + data.multisig.sigs = sub.slice(1); + data.sig = data.multisig.sigs[0]; + } else if (data.type === 'scripthash') { + data.multisig.sigs = sub.slice(1, -1); + data.sig = data.multisig.sigs[0]; + } + data.hash = input.out.hash; + data.index = input.out.index; + data._script = s; + return data; + } + + if (bcoin.script.isPubkeyInput(s)) { + return { + type: 'pubkey', + side: 'input', + sig: sub[0], + pub: null, + hash: '[unknown]', + addr: '[unknown]', + multisig: null, + redeem: null, + data: null, + text: null, + value: new bn(0), + script: s, + seq: input.seq, + none: true + }; } if (bcoin.script.isPubkeyhashInput(s)) { - sig = utils.toHex(s[0]); - pub = s[1]; + pub = sub[1]; hash = utils.ripesha(pub); addr = bcoin.wallet.hash2addr(hash); return { type: 'pubkeyhash', - sig: sig, + side: 'input', + sig: sub[0], pub: pub, hash: hash, addr: addr, + multisig: null, + redeem: null, + data: null, + text: null, value: new bn(0), script: s, - seq: input.seq + seq: input.seq, + none: false }; } if (bcoin.script.isScripthashInput(s)) { - pub = s[s.length - 1]; + sig = sub.slice(1, -1); + pub = sub[sub.length - 1]; hash = utils.ripesha(pub); addr = bcoin.wallet.hash2addr(hash, 'scripthash'); redeem = bcoin.script.decode(pub); @@ -157,30 +214,53 @@ Input.getData = function getData(input) { value: new bn(0) }); data.type = 'scripthash'; - data.pub = pub; + data.side = 'input'; + data.sig = sig[0]; data.hash = hash; data.addr = addr; - data.scripthash = { - redeem: redeem, - pub: pub, - hash: hash, - addr: addr, - m: data.multisig.m, - n: data.multisig.n, - keys: data.multisig.keys, - hashes: data.multisig.hashes, - addrs: data.multisig.addrs, - script: redeem - }; + data.multisig.sig = sig; + data.redeem = redeem; data.script = s; data.seq = input.seq; return data; } + if (bcoin.script.isMultisigInput(s)) { + sig = sub.slice(1); + return { + type: 'multisig', + side: 'input', + sig: sub[0], + pub: null, + hash: '[unknown]', + addr: '[unknown]', + multisig: { + m: sig.length, + n: null, + sigs: sig, + pubs: null, + hashes: null, + addrs: null + }, + redeem: null, + value: new bn(0), + script: s, + seq: input.seq, + none: true + }; + } + return { type: 'unknown', - addr: '[unknown]', + side: 'input', + sig: null, + pub: null, hash: '[unknown]', + addr: '[unknown]', + multisig: null, + redeem: null, + data: null, + text: null, value: new bn(0), script: s, seq: input.seq, @@ -188,6 +268,27 @@ Input.getData = function getData(input) { }; }; +Input.prototype.inspect = function() { + var data = this.data; + var output = this.output + ? this.output.inspect() + : { type: 'unknown', value: '0.0' }; + + output.hash = this.out.hash; + output.rhash = utils.revHex(this.out.hash); + output.index = this.out.index; + + return { + type: this.type, + addr: this.addr, + lock: this.lock, + script: bcoin.script.format(this.script)[0], + value: bcoin.utils.btc(output.value), + seq: this.seq, + output: output + }; +}; + /** * Expose */ diff --git a/lib/bcoin/output.js b/lib/bcoin/output.js index 83a4174a..b04d0968 100644 --- a/lib/bcoin/output.js +++ b/lib/bcoin/output.js @@ -59,45 +59,62 @@ Output.prototype.__defineGetter__('type', function() { Output.prototype.__defineGetter__('lock', function() { var lock = bcoin.script.lockTime(this.script); if (!lock) - return; + return 0; return lock.toNumber(); }); Output.getData = function getData(output) { - if (!output || !output.script) return; + if (!output || !output.script) + return; var s = output.script; + var sub = bcoin.script.subscript(output.script); var lock = bcoin.script.lockTime(s); var pub, hash, addr, pubs, ret; + if (lock) + sub = sub.slice(3); + if (bcoin.script.isPubkey(s)) { - pub = s[0]; + pub = sub[0]; hash = utils.ripesha(pub); addr = bcoin.wallet.hash2addr(hash); return { type: 'pubkey', + side: 'output', sig: null, pub: pub, hash: hash, addr: addr, + multisig: null, + redeem: null, + data: null, + text: null, value: output.value, script: s, - lock: lock + lock: lock, + none: false }; } if (bcoin.script.isPubkeyhash(s)) { - hash = s[2]; + hash = sub[2]; addr = bcoin.wallet.hash2addr(hash); return { type: 'pubkeyhash', + side: 'output', sig: null, pub: null, hash: hash, addr: addr, + multisig: null, + redeem: null, + data: null, + text: null, value: output.value, script: s, - lock: lock + lock: lock, + none: false }; } @@ -107,15 +124,16 @@ Output.getData = function getData(output) { addr = bcoin.wallet.hash2addr(hash); return { type: 'multisig', + side: 'output', sig: null, pub: pubs[0], hash: hash, addr: addr, - keys: pubs, multisig: { - m: new bn(s[0]).toNumber(), - n: new bn(s[s.length - 2]).toNumber(), - keys: pubs, + m: new bn(sub[0]).toNumber(), + n: new bn(sub[sub.length - 2]).toNumber(), + sigs: null, + pubs: pubs, hashes: pubs.map(function(key) { return utils.ripesha(key); }), @@ -124,30 +142,41 @@ Output.getData = function getData(output) { return bcoin.wallet.hash2addr(hash); }) }, + redeem: null, + data: null, + text: null, value: output.value, script: s, - lock: lock + lock: lock, + none: false }; } if (bcoin.script.isScripthash(s)) { - hash = utils.toHex(s[1]); + hash = utils.toHex(sub[1]); addr = bcoin.wallet.hash2addr(hash, 'scripthash'); return { type: 'scripthash', + side: 'output', sig: null, pub: null, hash: hash, addr: addr, - scripthash: { - redeem: null, - pub: null, - hash: hash, - addr: addr + multisig: { + m: null, + n: null, + sigs: null, + pubs: null, + hashes: null, + addrs: null }, + redeem: null, + data: null, + text: null, value: output.value, script: s, - lock: lock + lock: lock, + none: false }; } @@ -155,10 +184,15 @@ Output.getData = function getData(output) { ret = bcoin.script.colored(s); return { type: 'colored', - addr: '[colored]', + side: 'output', + sig: null, + pub: null, hash: '[colored]', + addr: '[colored]', + multisig: null, + redeem: null, data: ret, - text: utils.array2ascii(ret), + text: utils.array2utf8(ret), value: output.value, script: s, lock: lock, @@ -168,8 +202,15 @@ Output.getData = function getData(output) { return { type: 'unknown', - addr: '[unknown]', + side: 'output', + sig: null, + pub: null, hash: '[unknown]', + addr: '[unknown]', + multisig: null, + redeem: null, + data: null, + text: null, value: new bn(0), script: s, lock: lock, @@ -177,6 +218,34 @@ Output.getData = function getData(output) { }; }; +Output.prototype.inspect = function inspect() { + var multisig = this.data.multisig || null; + var redeem = this.type === 'scripthash' + ? bcoin.script.format(this.data.redeem)[0] + : null; + + if (multisig) { + multisig = { + m: multisig.m, + n: multisig.n, + sigs: multisig.sigs.map(utils.toHex), + pubs: multisig.pubs.map(utils.toHex), + hashes: multisig.hashes, + addrs: multisig.addrs + }; + } + + return { + type: this.type, + addr: this.addr, + lock: this.lock, + script: bcoin.script.format(this.script)[0], + value: bcoin.utils.btc(this.value), + multisig: multisig, + redeem: redeem + }; +}; + /** * Expose */ diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index ca3e2c30..7e9bf29d 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -1033,7 +1033,7 @@ script.colored = function colored(s) { if (!script.isColored(s)) return false; - return s[1]; + return script.subscript(s)[1]; }; script.standardInput = function standardInput(s) { diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 023bb41e..025fbe5c 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -884,6 +884,20 @@ TX.prototype.__defineGetter__('rhash', function() { return utils.revHex(this.hash('hex')); }); +TX.prototype.inspect = function inspect() { + var copy = bcoin.tx(this); + copy.__proto__ = null; + if (this.block) + copy.block = this.block; + delete copy._raw; + copy.hash = this.hash('hex'); + copy.rhash = this.rhash; + copy.rblock = this.rblock; + copy.height = this.height; + copy.confirmations = this.confirmations; + return copy; +}; + TX.prototype.toJSON = function toJSON() { // Compact representation return { diff --git a/lib/bcoin/utils.js b/lib/bcoin/utils.js index 46b737da..6e7beba8 100644 --- a/lib/bcoin/utils.js +++ b/lib/bcoin/utils.js @@ -332,6 +332,10 @@ utils.array2ascii = function array2ascii(arr) { return utils.readAscii(arr, 0, arr.length); }; +utils.array2utf8 = function array2utf8(arr) { + return new Buffer(arr).toString('utf8'); +}; + utils.copy = function copy(src, dst, off, force) { var len = src.length; var i = 0; @@ -690,7 +694,7 @@ utils.toKeyArray = function toKeyArray(msg) { throw new Error('Cannot ensure array'); }; -utils.inspect = function inspect(obj) { +utils._inspect = function inspect(obj) { return typeof obj !== 'string' ? util.inspect(obj, null, 20, true) : obj; @@ -698,7 +702,7 @@ utils.inspect = function inspect(obj) { utils.print = function print(msg) { return typeof msg === 'object' - ? process.stdout.write(utils.inspect(msg) + '\n') + ? process.stdout.write(utils._inspect(msg) + '\n') : console.log.apply(console, arguments); };