diff --git a/src/script.js b/src/script.js index f12ac6f..a0c0997 100644 --- a/src/script.js +++ b/src/script.js @@ -1,8 +1,6 @@ -var assert = require('assert') var Address = require('./address') +var assert = require('assert') var crypto = require('./crypto') -var convert = require('./convert') -var networks = require('./networks') var Opcode = require('./opcode') function Script(data) { @@ -202,18 +200,6 @@ Script.prototype.toScriptHash = function() { return crypto.hash160(this.buffer) } -Script.prototype.getToAddress = function(network) { - network = network || networks.bitcoin - - return Address.fromScriptPubKey(this, network) -} - -Script.prototype.getFromAddress = function(version) { - version = version || networks.bitcoin.pubKeyHash - - return new Address(this.simpleInHash(), version) -} - /** * Compare the script to known templates of scriptSig. * @@ -259,58 +245,6 @@ Script.prototype.getInType = function() { } } -/** - * Returns the affected public key for this input. - * - * This currently only works with payToPubKeyHash transactions. It will also - * work in the future for standard payToScriptHash transactions that use a - * single public key. - * - * However for multi-key and other complex transactions, this will only return - * one of the keys or raise an error. Therefore, it is recommended for indexing - * purposes to use Script#simpleInHash or Script#simpleOutHash instead. - * - * @deprecated - */ -Script.prototype.simpleInPubKey = function() { - switch (this.getInType()) { - case 'pubkeyhash': - return this.chunks[1] - case 'pubkey': - // TODO: Theoretically, we could recover the pubkey from the sig here. - // See https://bitcointalk.org/?topic=6430.0 - throw new Error('Script does not contain pubkey') - default: - throw new Error('Encountered non-standard scriptSig') - } -} - -/** - * Returns the affected address hash for this input. - * - * For standard transactions, this will return the hash of the pubKey that - * can spend this output. - * - * In the future, for standard payToScriptHash inputs, this will return the - * scriptHash. - * - * Note: This function provided for convenience. If you have the corresponding - * scriptPubKey available, you are urged to use Script#simpleOutHash instead - * as it is more reliable for non-standard payToScriptHash transactions. - * - * This method is useful for indexing transactions. - */ -Script.prototype.simpleInHash = function() { - return crypto.hash160(this.simpleInPubKey()) -} - -/** - * Old name for Script#simpleInHash. - * - * @deprecated - */ -Script.prototype.simpleInPubKeyHash = Script.prototype.simpleInHash - /** * Add an op code to the script. */ @@ -347,22 +281,6 @@ Script.prototype.writeBytes = function(data) { this.chunks.push(data) } -/** - * Create an output for an address - */ -Script.createScriptPubKey = function(address, network) { - assert(address instanceof Address) - network = network || networks.bitcoin - - if (address.version === network.pubKeyHash) { - return Script.createPubKeyHashScriptPubKey(address.hash) - } - - assert.strictEqual(address.version, network.scriptHash, 'Unknown address type') - - return Script.createP2SHScriptPubKey(address.hash) -} - // OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG Script.createPubKeyHashScriptPubKey = function(hash) { var script = new Script() diff --git a/src/transaction.js b/src/transaction.js index 49b1a4a..a0d77d0 100644 --- a/src/transaction.js +++ b/src/transaction.js @@ -9,7 +9,6 @@ var convert = require('./convert') var crypto = require('./crypto') var ECKey = require('./eckey').ECKey var ecdsa = require('./ecdsa') -var networks = require('./networks') var Transaction = function (doc) { if (!(this instanceof Transaction)) { return new Transaction(doc) } @@ -90,11 +89,10 @@ Transaction.prototype.addInput = function (tx, outIndex) { * i) An existing TransactionOut object * ii) An address object or a string address, and a value * iii) An address:value string - * iv) Either ii), iii) with an optional network argument * * FIXME: This is a bit convoluted */ -Transaction.prototype.addOutput = function (address, value, network) { +Transaction.prototype.addOutput = function (address, value) { if (arguments[0] instanceof TransactionOut) { this.outs.push(arguments[0]) return @@ -105,19 +103,15 @@ Transaction.prototype.addOutput = function (address, value, network) { var args = arguments[0].split(':') address = args[0] value = parseInt(args[1]) - - network = arguments[1] } address = Address.fromBase58Check(address) } - network = network || networks.bitcoin - this.outs.push(new TransactionOut({ value: value, - script: Script.createScriptPubKey(address, network), - network: network + script: address.toScriptPubKey(), + address: address // TODO: Remove me })) } @@ -364,18 +358,14 @@ Transaction.deserialize = function(buffer) { /** * Signs a standard output at some index with the given key - * FIXME: network support is ugly */ -Transaction.prototype.sign = function(index, key, type, network) { +Transaction.prototype.sign = function(index, key, type) { assert(key instanceof ECKey) - network = network || networks.bitcoin - - var address = key.pub.getAddress(network.pubKeyHash) - // FIXME: Assumed prior TX was pay-to-pubkey-hash - var script = Script.createScriptPubKey(address, network) + var script = key.pub.getAddress().toScriptPubKey() var signature = this.signScriptSig(index, script, key, type) + // FIXME: Assumed prior TX was pay-to-pubkey-hash var scriptSig = Script.createPubKeyHashScriptSig(signature, key.pub) this.setScriptSig(index, scriptSig) } @@ -445,10 +435,7 @@ function TransactionOut(data) { this.value = data.value this.address = data.address - var network = data.network || networks.bitcoin - if (this.script.buffer.length > 0) { - this.address = this.script.getToAddress(network) - } + if (data.address) this.address = data.address } TransactionOut.prototype.clone = function() { diff --git a/src/wallet.js b/src/wallet.js index c6b7134..08333c3 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -1,8 +1,9 @@ +var Address = require('./address') var convert = require('./convert') -var Transaction = require('./transaction').Transaction var HDNode = require('./hdwallet.js') -var rng = require('secure-random') var networks = require('./networks') +var rng = require('secure-random') +var Transaction = require('./transaction').Transaction function Wallet(seed, options) { if (!(this instanceof Wallet)) { return new Wallet(seed, options); } @@ -42,7 +43,6 @@ function Wallet(seed, options) { } this.newMasterKey(seed, network) - this.generateAddress = function() { var key = externalAccount.derive(this.addresses.length) this.addresses.push(key.getAddress().toString()) @@ -150,9 +150,17 @@ function Wallet(seed, options) { var txhash = tx.getHash() tx.outs.forEach(function(txOut, i){ - var address = txOut.address.toString() + var address + + try { + address = Address.fromScriptPubKey(txOut.script, networks[network]).toString() + } catch(e) { + if (!(e instanceof Address.Error)) throw e + } + if (isMyAddress(address)) { - var output = txhash+':'+i + var output = txhash + ':' + i + me.outputs[output] = { receive: output, value: txOut.value, @@ -165,7 +173,7 @@ function Wallet(seed, options) { var op = txIn.outpoint var o = me.outputs[op.hash+':'+op.index] if (o) { - o.spend = txhash+':'+i + o.spend = txhash + ':' +i } }) } @@ -174,7 +182,7 @@ function Wallet(seed, options) { checkDust(value) var tx = new Transaction() - tx.addOutput(to, value, networks[network]) + tx.addOutput(to, value) var utxo = getCandidateOutputs(value) var totalInValue = 0 @@ -190,7 +198,7 @@ function Wallet(seed, options) { var change = totalInValue - value - fee if(change > 0 && !isDust(change)) { - tx.addOutput(changeAddress || getChangeAddress(), change, networks[network]) + tx.addOutput(changeAddress || getChangeAddress(), change) } break } @@ -246,7 +254,7 @@ function Wallet(seed, options) { function estimateFeePadChangeOutput(tx){ var tmpTx = tx.clone() - tmpTx.addOutput(getChangeAddress(), 0, networks[network]) + tmpTx.addOutput(getChangeAddress(), 0) return tmpTx.estimateFee() } @@ -266,7 +274,7 @@ function Wallet(seed, options) { tx.ins.forEach(function(inp,i) { var output = me.outputs[inp.outpoint.hash + ':' + inp.outpoint.index] if (output) { - tx.sign(i, me.getPrivateKeyForAddress(output.address), false, networks[network]) + tx.sign(i, me.getPrivateKeyForAddress(output.address), false) } }) return tx diff --git a/test/script.js b/test/script.js index 303d181..83b35ae 100644 --- a/test/script.js +++ b/test/script.js @@ -116,25 +116,6 @@ describe('Script', function() { }) }) - describe('getToAddress', function() { - it('works for p2sh type output', function() { - var script = Script.fromHex(p2shScriptPubKey) - assert.equal(script.getToAddress().toString(), '3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8') - }) - - it('works for pubkey type output', function() { - var script = Script.fromHex(pubKeyScriptPubKey) - assert.equal(script.getToAddress().toString(), '19E6FV3m3kEPoJD5Jz6dGKdKwTVvjsWUvu') - }) - }) - - describe('getFromAddress', function() { - it('works for address type input', function() { - var script = Script.fromHex(addressScriptSig) - assert.equal(script.getFromAddress().toString(), '1BBjuhF2jHxu7tPinyQGCuaNhEs6f5u59u') - }) - }) - describe('2-of-3 Multi-Signature', function() { var pubKeys diff --git a/test/transaction.js b/test/transaction.js index 5716a48..e1ca2f4 100644 --- a/test/transaction.js +++ b/test/transaction.js @@ -176,7 +176,7 @@ describe('Transaction', function() { it('supports alternative networks', function(){ var addr = 'mkHJaNR7uuwRG1JrmTZsV4MszaTKjCBvCR' - tx.addOutput(addr, 40000, networks.testnet) + tx.addOutput(addr, 40000) verifyTransactionOut() assert.equal(tx.outs[0].address.toString(), addr) @@ -250,7 +250,7 @@ describe('Transaction', function() { it('works for multi-sig redeem script', function() { var tx = new Transaction() tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0) - tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1, networks.testnet) + tx.addOutput('mrCDrCybB6J1vRfbwM5hemdJz73FwDBC8r', 1) var privKeys = [ '5HpHagT65TZzG1PH3CSu63k8DbpvD8s5ip4nEB3kEsreAnchuDf', diff --git a/test/wallet.js b/test/wallet.js index dd4d2ed..a7de4d1 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -1,12 +1,14 @@ -var Wallet = require('../src/wallet.js') +var assert = require('assert') +var crypto = require('../').crypto +var sinon = require('sinon') + +var Address = require('..').Address var HDNode = require('../src/hdwallet.js') var T = require('../src/transaction.js') var Transaction = T.Transaction var TransactionOut = T.TransactionOut var Script = require('../src/script.js') -var assert = require('assert') -var sinon = require('sinon') -var crypto = require('../').crypto +var Wallet = require('../src/wallet.js') var fixtureTxes = require('./fixtures/mainnet_tx') var fixtureTx1Hex = fixtureTxes.prevTx @@ -308,17 +310,24 @@ describe('Wallet', function() { }) describe('processTx', function(){ + var addresses var tx beforeEach(function(){ + addresses = [ + '115qa7iPZqn6as57hxLL8E9VUnhmGQxKWi', + '1Bu3bhwRmevHLAy1JrRB6AfcxfgDG2vXRd', + '1BBjuhF2jHxu7tPinyQGCuaNhEs6f5u59u' + ] + tx = Transaction.deserialize(fixtureTx1Hex) }) describe("when tx outs contains an address owned by the wallet, an 'output' gets added to wallet.outputs", function(){ it("works for receive address", function(){ var totalOuts = outputCount() - wallet.addresses = [tx.outs[0].address.toString()] + wallet.addresses = [addresses[0]] wallet.processTx(tx) assert.equal(outputCount(), totalOuts + 1) @@ -327,7 +336,7 @@ describe('Wallet', function() { it("works for change address", function(){ var totalOuts = outputCount() - wallet.changeAddresses = [tx.outs[1].address.toString()] + wallet.changeAddresses = [addresses[1]] wallet.processTx(tx) @@ -345,13 +354,15 @@ describe('Wallet', function() { var output = wallet.outputs[key] assert.equal(output.receive, key) assert.equal(output.value, txOut.value) - assert.equal(output.address, txOut.address) + + var txOutAddress = Address.fromScriptPubKey(txOut.script).toString() + assert.equal(output.address, txOutAddress) } }) describe("when tx ins outpoint contains a known txhash:i, the corresponding 'output' gets updated", function(){ beforeEach(function(){ - wallet.addresses = [tx.outs[0].address.toString()] // the address fixtureTx2 used as input + wallet.addresses = [addresses[0]] // the address fixtureTx2 used as input wallet.processTx(tx) tx = Transaction.deserialize(fixtureTx2Hex)