diff --git a/src/transaction.js b/src/transaction.js index b7c6f7f..fa1b18a 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -4,7 +4,6 @@ var crypto = require('./crypto') var typeForce = require('typeforce') var opcodes = require('./opcodes') -var Address = require('./address') var Script = require('./script') function Transaction () { @@ -104,16 +103,6 @@ Transaction.isCoinbaseHash = function (buffer) { }) } -/** - * Create a new txIn. - * - * Can be called with any of: - * - * - A transaction and an index - * - A transaction hash and an index - * - * Note that this method does not sign the created input. - */ Transaction.prototype.addInput = function (hash, index, sequence, script) { if (sequence === undefined || sequence === null) { sequence = Transaction.DEFAULT_SEQUENCE @@ -121,13 +110,6 @@ Transaction.prototype.addInput = function (hash, index, sequence, script) { script = script || Script.EMPTY - if (typeof hash === 'string') { - // TxId hex is big-endian, we need little-endian - hash = bufferutils.reverse(new Buffer(hash, 'hex')) - } else if (hash instanceof Transaction) { - hash = hash.getHash() - } - typeForce('Buffer', hash) typeForce('Number', index) typeForce('Number', sequence) @@ -144,26 +126,7 @@ Transaction.prototype.addInput = function (hash, index, sequence, script) { }) - 1) } -/** - * Create a new txOut. - * - * Can be called with: - * - * - A base58 address string and a value - * - An Address object and a value - * - A scriptPubKey Script and a value - */ Transaction.prototype.addOutput = function (scriptPubKey, value) { - // Attempt to get a valid address if it's a base58 address string - if (typeof scriptPubKey === 'string') { - scriptPubKey = Address.fromBase58Check(scriptPubKey) - } - - // Attempt to get a valid script if it's an Address object - if (scriptPubKey instanceof Address) { - scriptPubKey = scriptPubKey.toOutputScript() - } - typeForce('Script', scriptPubKey) typeForce('Number', value) @@ -201,10 +164,10 @@ Transaction.prototype.clone = function () { /** * Hash transaction for signing a specific input. * - * Bitcoin uses a different hash for each signed transaction input. This - * method copies the transaction, makes the necessary changes based on the - * hashType, serializes and finally hashes the result. This hash can then be - * used to sign the transaction input in question. + * Bitcoin uses a different hash for each signed transaction input. + * This method copies the transaction, makes the necessary changes based on the + * hashType, and then hashes the result. + * This hash can then be used to sign the provided transaction input. */ Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashType) { typeForce('Number', inIndex) diff --git a/src/transaction_builder.js b/src/transaction_builder.js index 8a58e9a..fb8b852 100644 --- a/src/transaction_builder.js +++ b/src/transaction_builder.js @@ -2,6 +2,7 @@ var assert = require('assert') var ops = require('./opcodes') var scripts = require('./scripts') +var Address = require('./address') var ECPubKey = require('./ecpubkey') var ECSignature = require('./ecsignature') var Script = require('./script') @@ -188,6 +189,16 @@ TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) { return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE }), 'No, this would invalidate signatures') + // Attempt to get a valid address if it's a base58 address string + if (typeof scriptPubKey === 'string') { + scriptPubKey = Address.fromBase58Check(scriptPubKey) + } + + // Attempt to get a valid script if it's an Address object + if (scriptPubKey instanceof Address) { + scriptPubKey = scriptPubKey.toOutputScript() + } + return this.tx.addOutput(scriptPubKey, value) } diff --git a/test/transaction.js b/test/transaction.js index c9a6aa4..4a64493 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -2,7 +2,6 @@ var assert = require('assert') -var Address = require('../src/address') var Transaction = require('../src/transaction') var Script = require('../src/script') @@ -63,21 +62,10 @@ describe('Transaction', function () { }) describe('addInput', function () { - // FIXME: not as pretty as could be - // Probably a bit representative of the API - var prevTxHash, prevTxId, prevTx + var prevTxHash beforeEach(function () { var f = fixtures.valid[0] - prevTx = Transaction.fromHex(f.hex) - prevTxHash = prevTx.getHash() - prevTxId = prevTx.getId() - }) - - it('accepts a transaction id', function () { - var tx = new Transaction() - tx.addInput(prevTxId, 0) - - assert.deepEqual(tx.ins[0].hash, prevTxHash) + prevTxHash = new Buffer(f.hash, 'hex') }) it('accepts a transaction hash', function () { @@ -87,13 +75,6 @@ describe('Transaction', function () { assert.deepEqual(tx.ins[0].hash, prevTxHash) }) - it('accepts a Transaction object', function () { - var tx = new Transaction() - tx.addInput(prevTx, 0) - - assert.deepEqual(tx.ins[0].hash, prevTxHash) - }) - it('returns an index', function () { var tx = new Transaction() assert.equal(tx.addInput(prevTxHash, 0), 0) @@ -127,43 +108,19 @@ describe('Transaction', function () { }) describe('addOutput', function () { - // FIXME: not as pretty as could be - // Probably a bit representative of the API - var destAddressB58, destAddress, destScript - beforeEach(function () { - destAddressB58 = '15mMHKL96tWAUtqF3tbVf99Z8arcmnJrr3' - destAddress = Address.fromBase58Check(destAddressB58) - destScript = destAddress.toOutputScript() - }) - - it('accepts an address string', function () { - var tx = new Transaction() - tx.addOutput(destAddressB58, 40000) - - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) - - it('accepts an Address', function () { - var tx = new Transaction() - tx.addOutput(destAddress, 40000) - - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) - - it('accepts a scriptPubKey', function () { - var tx = new Transaction() - tx.addOutput(destScript, 40000) + fixtures.valid.forEach(function (f) { + it('should add the outputs for ' + f.id + ' correctly', function () { + var tx = new Transaction() - assert.deepEqual(tx.outs[0].script, destScript) - assert.equal(tx.outs[0].value, 40000) - }) + f.raw.outs.forEach(function (txOut, i) { + var scriptPubKey = Script.fromASM(txOut.script) + var j = tx.addOutput(scriptPubKey, txOut.value) - it('returns an index', function () { - var tx = new Transaction() - assert.equal(tx.addOutput(destScript, 40000), 0) - assert.equal(tx.addOutput(destScript, 40000), 1) + assert.equal(i, j) + assert.equal(tx.outs[i].script, scriptPubKey) + assert.equal(tx.outs[i].value, txOut.value) + }) + }) }) }) @@ -190,9 +147,8 @@ describe('Transaction', function () { fixtures.valid.forEach(function (f) { it('should return the id for ' + f.id, function () { var tx = Transaction.fromHex(f.hex) - var actual = tx.getId() - assert.equal(actual, f.id) + assert.equal(tx.getId(), f.id) }) }) }) @@ -201,9 +157,8 @@ describe('Transaction', function () { fixtures.valid.forEach(function (f) { it('should return the hash for ' + f.id, function () { var tx = Transaction.fromHex(f.hex) - var actual = tx.getHash().toString('hex') - assert.equal(actual, f.hash) + assert.deepEqual(tx.getHash().toString('hex'), f.hash) }) }) }) diff --git a/test/transaction_builder.js b/test/transaction_builder.js index 11172e5..350011b 100644 --- a/test/transaction_builder.js +++ b/test/transaction_builder.js @@ -2,6 +2,7 @@ var assert = require('assert') +var Address = require('../src/address') var BigInteger = require('bigi') var ECKey = require('../src/eckey') var Script = require('../src/script') @@ -62,8 +63,8 @@ describe('TransactionBuilder', function () { txb = new TransactionBuilder() prevTx = new Transaction() - prevTx.addOutput('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH', 0) - prevTx.addOutput('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP', 1) + prevTx.addOutput(Address.fromBase58Check('1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH').toOutputScript(), 0) + prevTx.addOutput(Address.fromBase58Check('1cMh228HTCiwS8ZsaakH8A8wze1JR5ZsP').toOutputScript(), 1) prevTxHash = prevTx.getHash() privKey = new ECKey(BigInteger.ONE, false) @@ -121,6 +122,33 @@ describe('TransactionBuilder', function () { }) describe('addOutput', function () { + it('accepts an address string and value', function () { + var vout = txb.addOutput(privAddress.toBase58Check(), 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + + it('accepts an Address object and value', function () { + var vout = txb.addOutput(privAddress, 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + + it('accepts a ScriptPubKey and value', function () { + var vout = txb.addOutput(privScript, 1000) + assert.equal(vout, 0) + + var txout = txb.tx.outs[0] + assert.deepEqual(txout.script, privScript) + assert.equal(txout.value, 1000) + }) + it('throws if SIGHASH_ALL has been used to sign any existing scriptSigs', function () { txb.addInput(prevTxHash, 0) txb.addOutput(privScript, 2000)