Transaction: mass rename from SPK/SS to Input/Output
I think it is important we maintain some reasoning that an Input script is actually a script signature, but in the end, these names are more coherent and understandable when reasoning with our code. So I think its OK we break tradition with bitcoind.
This commit is contained in:
parent
5a96df1ec1
commit
7e5af52cd1
8 changed files with 39 additions and 41 deletions
src
test
|
@ -35,7 +35,7 @@ Address.fromBase58Check = function(string) {
|
||||||
return new Address(hash, version)
|
return new Address(hash, version)
|
||||||
}
|
}
|
||||||
|
|
||||||
Address.fromScriptPubKey = function(script, network) {
|
Address.fromOutputScript = function(script, network) {
|
||||||
network = network || networks.bitcoin
|
network = network || networks.bitcoin
|
||||||
|
|
||||||
var type = scripts.classifyOutput(script)
|
var type = scripts.classifyOutput(script)
|
||||||
|
@ -59,7 +59,7 @@ Address.prototype.toBase58Check = function () {
|
||||||
return base58check.encode(payload)
|
return base58check.encode(payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
Address.prototype.toScriptPubKey = function() {
|
Address.prototype.toOutputScript = function() {
|
||||||
var scriptType = findScriptTypeByVersion(this.version)
|
var scriptType = findScriptTypeByVersion(this.version)
|
||||||
|
|
||||||
if (scriptType === 'pubkeyhash') {
|
if (scriptType === 'pubkeyhash') {
|
||||||
|
|
|
@ -110,7 +110,7 @@ Transaction.prototype.addOutput = function (address, value) {
|
||||||
|
|
||||||
this.outs.push(new TransactionOut({
|
this.outs.push(new TransactionOut({
|
||||||
value: value,
|
value: value,
|
||||||
script: address.toScriptPubKey(),
|
script: address.toOutputScript(),
|
||||||
address: address // TODO: Remove me
|
address: address // TODO: Remove me
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
@ -196,13 +196,13 @@ var SIGHASH_ANYONECANPAY = 0x80
|
||||||
* hashType, serializes and finally hashes the result. This hash can then be
|
* hashType, serializes and finally hashes the result. This hash can then be
|
||||||
* used to sign the transaction input in question.
|
* used to sign the transaction input in question.
|
||||||
*/
|
*/
|
||||||
Transaction.prototype.hashForSignature = function(scriptPubKey, inIndex, hashType) {
|
Transaction.prototype.hashForSignature = function(prevOutScript, inIndex, hashType) {
|
||||||
assert(inIndex >= 0, 'Invalid vin index')
|
assert(inIndex >= 0, 'Invalid vin index')
|
||||||
assert(inIndex < this.ins.length, 'Invalid vin index')
|
assert(inIndex < this.ins.length, 'Invalid vin index')
|
||||||
assert(scriptPubKey instanceof Script, 'Invalid Script object')
|
assert(prevOutScript instanceof Script, 'Invalid Script object')
|
||||||
|
|
||||||
var txTmp = this.clone()
|
var txTmp = this.clone()
|
||||||
var hashScript = scriptPubKey.without(opcodes.OP_CODESEPARATOR)
|
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR)
|
||||||
|
|
||||||
// Blank out other inputs' signatures
|
// Blank out other inputs' signatures
|
||||||
txTmp.ins.forEach(function(txin) {
|
txTmp.ins.forEach(function(txin) {
|
||||||
|
@ -239,8 +239,7 @@ Transaction.prototype.getHash = function () {
|
||||||
return buffer.toString('hex')
|
return buffer.toString('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
Transaction.prototype.clone = function ()
|
Transaction.prototype.clone = function () {
|
||||||
{
|
|
||||||
var newTx = new Transaction()
|
var newTx = new Transaction()
|
||||||
newTx.version = this.version
|
newTx.version = this.version
|
||||||
newTx.locktime = this.locktime
|
newTx.locktime = this.locktime
|
||||||
|
@ -337,24 +336,22 @@ Transaction.fromHex = function(hex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signs a standard output at some index with the given key
|
* Signs a pubKeyHash output at some index with the given key
|
||||||
*/
|
*/
|
||||||
Transaction.prototype.sign = function(index, key, type) {
|
Transaction.prototype.sign = function(index, key, type) {
|
||||||
assert(key instanceof ECKey)
|
var prevOutScript = key.pub.getAddress().toOutputScript()
|
||||||
|
var signature = this.signInput(index, prevOutScript, key, type)
|
||||||
var script = key.pub.getAddress().toScriptPubKey()
|
|
||||||
var signature = this.signScriptSig(index, script, key, type)
|
|
||||||
|
|
||||||
// FIXME: Assumed prior TX was pay-to-pubkey-hash
|
// FIXME: Assumed prior TX was pay-to-pubkey-hash
|
||||||
var scriptSig = scripts.pubKeyHashInput(signature, key.pub)
|
var scriptSig = scripts.pubKeyHashInput(signature, key.pub)
|
||||||
this.setScriptSig(index, scriptSig)
|
this.setInputScript(index, scriptSig)
|
||||||
}
|
}
|
||||||
|
|
||||||
Transaction.prototype.signScriptSig = function(index, scriptPubKey, key, type) {
|
Transaction.prototype.signInput = function(index, prevOutScript, key, type) {
|
||||||
type = type || SIGHASH_ALL
|
type = type || SIGHASH_ALL
|
||||||
assert(key instanceof ECKey, 'Invalid private key')
|
assert(key instanceof ECKey, 'Invalid private key')
|
||||||
|
|
||||||
var hash = this.hashForSignature(scriptPubKey, index, type)
|
var hash = this.hashForSignature(prevOutScript, index, type)
|
||||||
var signature = key.sign(hash)
|
var signature = key.sign(hash)
|
||||||
var DERencoded = ecdsa.serializeSig(signature)
|
var DERencoded = ecdsa.serializeSig(signature)
|
||||||
|
|
||||||
|
@ -364,11 +361,12 @@ Transaction.prototype.signScriptSig = function(index, scriptPubKey, key, type) {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
Transaction.prototype.setScriptSig = function(index, script) {
|
Transaction.prototype.setInputScript = function(index, script) {
|
||||||
this.ins[index].script = script
|
this.ins[index].script = script
|
||||||
}
|
}
|
||||||
|
|
||||||
Transaction.prototype.validateSig = function(index, script, pub, DERsig) {
|
// FIXME: should probably be validateInput(index, pub)
|
||||||
|
Transaction.prototype.validateInput = function(index, script, pub, DERsig) {
|
||||||
var type = DERsig.readUInt8(DERsig.length - 1)
|
var type = DERsig.readUInt8(DERsig.length - 1)
|
||||||
DERsig = DERsig.slice(0, -1)
|
DERsig = DERsig.slice(0, -1)
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ function Wallet(seed, network) {
|
||||||
var address
|
var address
|
||||||
|
|
||||||
try {
|
try {
|
||||||
address = Address.fromScriptPubKey(txOut.script, network).toString()
|
address = Address.fromOutputScript(txOut.script, network).toString()
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (!(e.message.match(/has no matching Address/))) throw e
|
if (!(e.message.match(/has no matching Address/))) throw e
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,23 +38,23 @@ describe('Address', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('fromScriptPubKey', function() {
|
describe('fromOutputScript', function() {
|
||||||
fixtures.valid.forEach(function(f) {
|
fixtures.valid.forEach(function(f) {
|
||||||
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||||
var script = Script.fromHex(f.script)
|
var script = Script.fromHex(f.script)
|
||||||
var addr = Address.fromScriptPubKey(script, networks[f.network])
|
var addr = Address.fromOutputScript(script, networks[f.network])
|
||||||
|
|
||||||
assert.equal(addr.version, f.version)
|
assert.equal(addr.version, f.version)
|
||||||
assert.equal(addr.hash.toString('hex'), f.hex)
|
assert.equal(addr.hash.toString('hex'), f.hex)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
fixtures.invalid.fromScriptPubKey.forEach(function(f) {
|
fixtures.invalid.fromOutputScript.forEach(function(f) {
|
||||||
it('throws when ' + f.description, function() {
|
it('throws when ' + f.description, function() {
|
||||||
var script = Script.fromHex(f.hex)
|
var script = Script.fromHex(f.hex)
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
Address.fromScriptPubKey(script)
|
Address.fromOutputScript(script)
|
||||||
}, new RegExp(f.description))
|
}, new RegExp(f.description))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -71,22 +71,22 @@ describe('Address', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('toScriptPubKey', function() {
|
describe('toOutputScript', function() {
|
||||||
fixtures.valid.forEach(function(f) {
|
fixtures.valid.forEach(function(f) {
|
||||||
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
it('imports ' + f.description + '(' + f.network + ') correctly', function() {
|
||||||
var addr = Address.fromBase58Check(f.base58check)
|
var addr = Address.fromBase58Check(f.base58check)
|
||||||
var script = addr.toScriptPubKey()
|
var script = addr.toOutputScript()
|
||||||
|
|
||||||
assert.equal(script.toHex(), f.script)
|
assert.equal(script.toHex(), f.script)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
fixtures.invalid.toScriptPubKey.forEach(function(f) {
|
fixtures.invalid.toOutputScript.forEach(function(f) {
|
||||||
it('throws when ' + f.description, function() {
|
it('throws when ' + f.description, function() {
|
||||||
var addr = new Address(new Buffer(f.hex, 'hex'), f.version)
|
var addr = new Address(new Buffer(f.hex, 'hex'), f.version)
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
addr.toScriptPubKey()
|
addr.toOutputScript()
|
||||||
}, new RegExp(f.description))
|
}, new RegExp(f.description))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
4
test/fixtures/address.json
vendored
4
test/fixtures/address.json
vendored
|
@ -46,7 +46,7 @@
|
||||||
"exception": "Invalid hash length"
|
"exception": "Invalid hash length"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"fromScriptPubKey": [
|
"fromOutputScript": [
|
||||||
{
|
{
|
||||||
"description": "pubkey has no matching Address",
|
"description": "pubkey has no matching Address",
|
||||||
"hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac"
|
"hex": "21031f1e68f82112b373f0fe980b3a89d212d2b5c01fb51eb25acb8b4c4b4299ce95ac"
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
"hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
|
"hex": "6a2606deadbeef03f895a2ad89fb6d696497af486cb7c644a27aa568c7a18dd06113401115185474"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"toScriptPubKey": [
|
"toOutputScript": [
|
||||||
{
|
{
|
||||||
"description": "24kPZCmVgzfkpGdXExy56234MRHrsqQxNWE has no matching Script",
|
"description": "24kPZCmVgzfkpGdXExy56234MRHrsqQxNWE has no matching Script",
|
||||||
"hex": "751e76e8199196d454941c45d1b3a323f1433bd6",
|
"hex": "751e76e8199196d454941c45d1b3a323f1433bd6",
|
||||||
|
|
|
@ -32,7 +32,7 @@ describe('Bitcoin-js', function() {
|
||||||
var redeemScript = scripts.multisigOutput(2, pubKeys)
|
var redeemScript = scripts.multisigOutput(2, pubKeys)
|
||||||
var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
|
var scriptPubKey = scripts.scriptHashOutput(redeemScript.getHash())
|
||||||
|
|
||||||
var multisigAddress = Address.fromScriptPubKey(scriptPubKey, networks.testnet).toString()
|
var multisigAddress = Address.fromOutputScript(scriptPubKey, networks.testnet).toString()
|
||||||
|
|
||||||
// Attempt to send funds to the source address, providing some unspents for later
|
// Attempt to send funds to the source address, providing some unspents for later
|
||||||
helloblock.faucet.withdraw(multisigAddress, coldAmount, function(err) {
|
helloblock.faucet.withdraw(multisigAddress, coldAmount, function(err) {
|
||||||
|
@ -55,12 +55,12 @@ describe('Bitcoin-js', function() {
|
||||||
tx.addOutput(targetAddress, spendAmount)
|
tx.addOutput(targetAddress, spendAmount)
|
||||||
|
|
||||||
var signatures = privKeys.map(function(privKey) {
|
var signatures = privKeys.map(function(privKey) {
|
||||||
return tx.signScriptSig(0, redeemScript, privKey)
|
return tx.signInput(0, redeemScript, privKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
var redeemScriptSig = scripts.multisigInput(signatures)
|
var redeemScriptSig = scripts.multisigInput(signatures)
|
||||||
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
|
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
|
||||||
tx.setScriptSig(0, scriptSig)
|
tx.setInputScript(0, scriptSig)
|
||||||
|
|
||||||
// broadcast our transaction
|
// broadcast our transaction
|
||||||
helloblock.transactions.propagate(tx.toHex(), function(err, resp, resource) {
|
helloblock.transactions.propagate(tx.toHex(), function(err, resp, resource) {
|
||||||
|
|
|
@ -71,7 +71,7 @@ describe('Transaction', function() {
|
||||||
var output = tx.outs[0]
|
var output = tx.outs[0]
|
||||||
|
|
||||||
assert.equal(output.value, 5000000000)
|
assert.equal(output.value, 5000000000)
|
||||||
assert.deepEqual(output.script, Address.fromBase58Check('n1gqLjZbRH1biT5o4qiVMiNig8wcCPQeB9').toScriptPubKey())
|
assert.deepEqual(output.script, Address.fromBase58Check('n1gqLjZbRH1biT5o4qiVMiNig8wcCPQeB9').toOutputScript())
|
||||||
})
|
})
|
||||||
|
|
||||||
it('assigns hash to deserialized object', function(){
|
it('assigns hash to deserialized object', function(){
|
||||||
|
@ -200,11 +200,11 @@ describe('Transaction', function() {
|
||||||
var script = prevTx.outs[0].script
|
var script = prevTx.outs[0].script
|
||||||
var sig = new Buffer(tx.ins[0].script.chunks[0])
|
var sig = new Buffer(tx.ins[0].script.chunks[0])
|
||||||
|
|
||||||
assert.equal(tx.validateSig(0, script, key.pub, sig), true)
|
assert.equal(tx.validateInput(0, script, key.pub, sig), true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('validateSig', function(){
|
describe('validateInput', function(){
|
||||||
var validTx
|
var validTx
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
@ -216,7 +216,7 @@ describe('Transaction', function() {
|
||||||
var script = prevTx.outs[0].script
|
var script = prevTx.outs[0].script
|
||||||
var sig = new Buffer(validTx.ins[0].script.chunks[0])
|
var sig = new Buffer(validTx.ins[0].script.chunks[0])
|
||||||
|
|
||||||
assert.equal(validTx.validateSig(0, script, key.pub, sig), true)
|
assert.equal(validTx.validateInput(0, script, key.pub, sig), true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -243,7 +243,7 @@ describe('Transaction', function() {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('signScriptSig', function() {
|
describe('signInput', function() {
|
||||||
it('works for multi-sig redeem script', function() {
|
it('works for multi-sig redeem script', function() {
|
||||||
var tx = new Transaction()
|
var tx = new Transaction()
|
||||||
tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0)
|
tx.addInput('d6f72aab8ff86ff6289842a0424319bf2ddba85dc7c52757912297f948286389', 0)
|
||||||
|
@ -259,15 +259,15 @@ describe('Transaction', function() {
|
||||||
var redeemScript = scripts.multisigOutput(2, pubKeys)
|
var redeemScript = scripts.multisigOutput(2, pubKeys)
|
||||||
|
|
||||||
var signatures = privKeys.map(function(privKey) {
|
var signatures = privKeys.map(function(privKey) {
|
||||||
return tx.signScriptSig(0, redeemScript, privKey)
|
return tx.signInput(0, redeemScript, privKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
var redeemScriptSig = scripts.multisigInput(signatures)
|
var redeemScriptSig = scripts.multisigInput(signatures)
|
||||||
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
|
var scriptSig = scripts.scriptHashInput(redeemScriptSig, redeemScript)
|
||||||
tx.setScriptSig(0, scriptSig)
|
tx.setInputScript(0, scriptSig)
|
||||||
|
|
||||||
signatures.forEach(function(sig, i){
|
signatures.forEach(function(sig, i){
|
||||||
assert(tx.validateSig(0, redeemScript, privKeys[i].pub, sig))
|
assert(tx.validateInput(0, redeemScript, privKeys[i].pub, sig))
|
||||||
})
|
})
|
||||||
|
|
||||||
var expected = '010000000189632848f99722915727c5c75da8db2dbf194342a0429828f66ff88fab2af7d600000000fd1b0100483045022100e5be20d440b2bbbc886161f9095fa6d0bca749a4e41d30064f30eb97adc7a1f5022061af132890d8e4e90fedff5e9365aeeb77021afd8ef1d5c114d575512e9a130a0147304402205054e38e9d7b5c10481b6b4991fde5704cd94d49e344406e3c2ce4d18a43bf8e022051d7ba8479865b53a48bee0cce86e89a25633af5b2918aa276859489e232f51c014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0101000000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000'
|
var expected = '010000000189632848f99722915727c5c75da8db2dbf194342a0429828f66ff88fab2af7d600000000fd1b0100483045022100e5be20d440b2bbbc886161f9095fa6d0bca749a4e41d30064f30eb97adc7a1f5022061af132890d8e4e90fedff5e9365aeeb77021afd8ef1d5c114d575512e9a130a0147304402205054e38e9d7b5c10481b6b4991fde5704cd94d49e344406e3c2ce4d18a43bf8e022051d7ba8479865b53a48bee0cce86e89a25633af5b2918aa276859489e232f51c014c8752410479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b84104c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a52aeffffffff0101000000000000001976a914751e76e8199196d454941c45d1b3a323f1433bd688ac00000000'
|
||||||
|
|
|
@ -313,7 +313,7 @@ describe('Wallet', function() {
|
||||||
assert.equal(output.receive, key)
|
assert.equal(output.receive, key)
|
||||||
assert.equal(output.value, txOut.value)
|
assert.equal(output.value, txOut.value)
|
||||||
|
|
||||||
var txOutAddress = Address.fromScriptPubKey(txOut.script).toString()
|
var txOutAddress = Address.fromOutputScript(txOut.script).toString()
|
||||||
assert.equal(output.address, txOutAddress)
|
assert.equal(output.address, txOutAddress)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Reference in a new issue