diff --git a/lib/bcoin/script.js b/lib/bcoin/script.js index 166dad63..ecd21535 100644 --- a/lib/bcoin/script.js +++ b/lib/bcoin/script.js @@ -110,6 +110,24 @@ script.subscript = function subscript(s) { return res; }; +script.verify = function verify(hash, sig, pub) { + var k = bcoin.ecdsa.keyFromPublic(pub); + + // Points at Infinity make verify() throw. + // This specifically throws on wallet-test.js + // where [1] is concatted to the pubkey. + if (k.getPublic().isInfinity()) + return false; + + // Use a try catch in case there are + // any uncaught errors for bad inputs in verify(). + try { + return bcoin.ecdsa.verify(hash, sig, pub); + } catch (e) { + return false; + } +}; + script.execute = function execute(s, stack, tx) { if (s.length > 10000) { return false; @@ -155,7 +173,7 @@ script.execute = function execute(s, stack, tx) { // if (typeof tx === 'function') // tx = tx(constants.rhashType[type]); - var res = bcoin.ecdsa.verify(tx, sig.slice(0, -1), pub); + var res = script.verify(tx, sig.slice(0, -1), pub); if (o === 'checksigverify') { if (!res) return false; @@ -205,7 +223,7 @@ script.execute = function execute(s, stack, tx) { var res = false; for (; !res && j < n; j++) - res = bcoin.ecdsa.verify(tx, sig.slice(0, -1), keys[j]); + res = script.verify(tx, sig.slice(0, -1), keys[j]); if (res) succ++; } diff --git a/lib/bcoin/tx.js b/lib/bcoin/tx.js index 2d77ca7e..e1f879dd 100644 --- a/lib/bcoin/tx.js +++ b/lib/bcoin/tx.js @@ -42,8 +42,8 @@ function TX(data, block) { // ps = Pending Since this.ps = this.ts === 0 ? +new Date() / 1000 : 0; - this.m = data.m; - this.n = data.n; + this.m = data.m || null; + this.n = data.n || null; this.change = data.change || null; this.fee = data.fee || 10000; this.dust = 5460; @@ -146,7 +146,8 @@ TX.prototype.scriptInput = function(input, pub, nsigs) { // P2PKH and simple tx if (bcoin.script.isPubkeyhash(s) || bcoin.script.isSimplePubkeyhash(s)) { - input.script = [ constants.opcodes['0'], pub ]; + //input.script = [ constants.opcodes['0'], pub ]; + input.script = [ [], pub ]; return; } @@ -156,19 +157,23 @@ TX.prototype.scriptInput = function(input, pub, nsigs) { nsigs = nsigs || this.m; if (!nsigs) throw new Error('`nsigs` is required for multisig'); - input.script = [ constants.opcodes['false'] ]; + //input.script = [ constants.opcodes['false'] ]; + input.script = [ [] ]; for (var i = 0; i < nsigs; i++) - input.script[i + 1] = constants.opcodes['0']; + //input.script[i + 1] = constants.opcodes['0']; + input.script[i + 1] = []; return; } // P2SH multisig // p2sh format: OP_FALSE [sig-1] [sig-2] ... [redeem-script] if (bcoin.script.isScripthash(s)) { - input.script = [ constants.opcodes['false'] ]; + //input.script = [ constants.opcodes['false'] ]; + input.script = [ [] ]; var m = pub[0] - constants.opcodes['1'] + 1; for (var i = 0; i < m; i++) - input.script[i + 1] = constants.opcodes['0']; + //input.script[i + 1] = constants.opcodes['0']; + input.script[i + 1] = []; // P2SH requires the redeem script after signatures input.script.push(pub); return; @@ -186,7 +191,7 @@ TX.prototype.signInput = function(input, key, type) { var s = input.out.tx.getSubscript(input.out.index); // Get the hash of the current tx, minus the other inputs, plus the sighash. - var hash = this.subscriptHash(tx.inputs.indexOf(input), s, type); + var hash = this.subscriptHash(this.inputs.indexOf(input), s, type); // Sign the transaction with our one input var signature = bcoin.ecdsa.sign(hash, key).toDER(); @@ -214,7 +219,8 @@ TX.prototype.signInput = function(input, key, type) { if (utils.isEqual(input.script[i], signature)) break; - if (input.script[i] === constants.opcodes['0']) { + //if (input.script[i] === constants.opcodes['0']) { + if (input.script[i].length === 0) { input.script[i] = signature; break; } @@ -228,10 +234,10 @@ TX.prototype.signInput = function(input, key, type) { // Build the scriptSig and sign it TX.prototype.scriptSig = function(input, key, pub, type, nsigs) { // Build script for input - tx.scriptInput(input, pub, nsigs); + this.scriptInput(input, pub, nsigs); // Sign input - tx.signInput(input, key, type); + this.signInput(input, key, type); return input.script; }; @@ -251,13 +257,15 @@ TX.prototype.output = function output(output, value) { value: new bn(output.value), script: this.scriptOutput(output) }); + + return this; }; // compat TX.prototype.out = TX.prototype.output; TX.prototype.scriptOutput = function(options) { - var script = []; + var script = options.script ? options.script.slice() : []; if (Array.isArray(options.keys || options.address)) { // Raw multisig transaction @@ -360,7 +368,6 @@ TX.prototype.verify = function verify(index, force) { if (!res) return false; - // XXX sighash_all here? return stack.length > 0 && utils.isEqual(stack.pop(), [ 1 ]); }, this); }; diff --git a/lib/bcoin/wallet.js b/lib/bcoin/wallet.js index d7adaa78..6781f5b7 100644 --- a/lib/bcoin/wallet.js +++ b/lib/bcoin/wallet.js @@ -316,7 +316,13 @@ Wallet.prototype.balance = function balance() { Wallet.prototype.fill = function fill(tx, cb) { cb = utils.asyncify(cb); - tx.fillUnspent(this.unspent(), this.getAddress()); + var result = tx.fillUnspent(this.unspent(), this.getAddress()); + if (!result) { + var err = new Error('Not enough funds'); + err.minBalance = tx.cost; + cb(err); + return null; + } this.sign(tx); cb(null, tx); return tx; diff --git a/test/wallet-test.js b/test/wallet-test.js index e244bba3..bf48ce63 100644 --- a/test/wallet-test.js +++ b/test/wallet-test.js @@ -52,7 +52,7 @@ describe('Wallet', function() { outputs: [{ value: 5460 * 2, minSignatures: 1, - address: [ w.getPublicKey(), w.getPublicKey().concat(1) ] + keys: [ w.getPublicKey(), w.getPublicKey().concat(1) ] }, { value: 5460 * 2, address: w.getAddress() + 'x'