|
@ -177,6 +177,8 @@ Transaction.prototype.clone = function () { |
|
|
return newTx |
|
|
return newTx |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var one = new Buffer('0000000000000000000000000000000000000000000000000000000000000001', 'hex') |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Hash transaction for signing a specific input. |
|
|
* Hash transaction for signing a specific input. |
|
|
* |
|
|
* |
|
@ -191,33 +193,71 @@ Transaction.prototype.hashForSignature = function (inIndex, prevOutScript, hashT |
|
|
typeForce('Number', hashType) |
|
|
typeForce('Number', hashType) |
|
|
|
|
|
|
|
|
assert(inIndex >= 0, 'Invalid vin index') |
|
|
assert(inIndex >= 0, 'Invalid vin index') |
|
|
assert(inIndex < this.ins.length, 'Invalid vin index') |
|
|
|
|
|
|
|
|
// https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L29
|
|
|
|
|
|
if (inIndex >= this.ins.length) return one |
|
|
|
|
|
|
|
|
var txTmp = this.clone() |
|
|
var txTmp = this.clone() |
|
|
|
|
|
|
|
|
|
|
|
// in case concatenating two scripts ends up with two codeseparators,
|
|
|
|
|
|
// or an extra one at the end, this prevents all those possible incompatibilities.
|
|
|
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR) |
|
|
var hashScript = prevOutScript.without(opcodes.OP_CODESEPARATOR) |
|
|
|
|
|
var i |
|
|
|
|
|
|
|
|
// Blank out other inputs' signatures
|
|
|
// blank out other inputs' signatures
|
|
|
txTmp.ins.forEach(function (txIn) { |
|
|
txTmp.ins.forEach(function (input) { input.script = Script.EMPTY }) |
|
|
txIn.script = Script.EMPTY |
|
|
|
|
|
}) |
|
|
|
|
|
txTmp.ins[inIndex].script = hashScript |
|
|
txTmp.ins[inIndex].script = hashScript |
|
|
|
|
|
|
|
|
var hashTypeModifier = hashType & 0x1f |
|
|
// blank out some of the inputs
|
|
|
|
|
|
if ((hashType & 0x1f) === Transaction.SIGHASH_NONE) { |
|
|
|
|
|
// wildcard payee
|
|
|
|
|
|
txTmp.outs = [] |
|
|
|
|
|
|
|
|
|
|
|
// let the others update at will
|
|
|
|
|
|
txTmp.ins.forEach(function (input, i) { |
|
|
|
|
|
if (i !== inIndex) { |
|
|
|
|
|
input.sequence = 0 |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
|
|
} else if ((hashType & 0x1f) === Transaction.SIGHASH_SINGLE) { |
|
|
|
|
|
var nOut = inIndex |
|
|
|
|
|
|
|
|
|
|
|
// only lock-in the txout payee at same index as txIn
|
|
|
|
|
|
// https://github.com/bitcoin/bitcoin/blob/master/src/test/sighash_tests.cpp#L60
|
|
|
|
|
|
if (nOut >= this.outs.length) return one |
|
|
|
|
|
|
|
|
|
|
|
txTmp.outs = txTmp.outs.slice(0, nOut + 1) |
|
|
|
|
|
|
|
|
if (hashTypeModifier === Transaction.SIGHASH_NONE) { |
|
|
// blank all other outputs (clear scriptPubKey, value === -1)
|
|
|
assert(false, 'SIGHASH_NONE not yet supported') |
|
|
var stubOut = { |
|
|
} else if (hashTypeModifier === Transaction.SIGHASH_SINGLE) { |
|
|
script: Script.EMPTY, |
|
|
assert(false, 'SIGHASH_SINGLE not yet supported') |
|
|
valueBuffer: new Buffer('ffffffffffffffff', 'hex') |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < nOut; i++) { |
|
|
|
|
|
txTmp.outs[i] = stubOut |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// let the others update at will
|
|
|
|
|
|
txTmp.ins.forEach(function (input, i) { |
|
|
|
|
|
if (i !== inIndex) { |
|
|
|
|
|
input.sequence = 0 |
|
|
|
|
|
} |
|
|
|
|
|
}) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// blank out other inputs completely, not recommended for open transactions
|
|
|
if (hashType & Transaction.SIGHASH_ANYONECANPAY) { |
|
|
if (hashType & Transaction.SIGHASH_ANYONECANPAY) { |
|
|
assert(false, 'SIGHASH_ANYONECANPAY not yet supported') |
|
|
txTmp.ins[0] = txTmp.ins[inIndex] |
|
|
|
|
|
txTmp.ins = txTmp.ins.slice(0, 1) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var hashTypeBuffer = new Buffer(4) |
|
|
// serialize and hash
|
|
|
hashTypeBuffer.writeInt32LE(hashType, 0) |
|
|
var buffer = new Buffer(txTmp.byteLength() + 4) |
|
|
|
|
|
buffer.writeInt32LE(hashType, buffer.length - 4) |
|
|
|
|
|
txTmp.toBuffer().copy(buffer, 0) |
|
|
|
|
|
|
|
|
var buffer = Buffer.concat([txTmp.toBuffer(), hashTypeBuffer]) |
|
|
|
|
|
return crypto.hash256(buffer) |
|
|
return crypto.hash256(buffer) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -267,7 +307,12 @@ Transaction.prototype.toBuffer = function () { |
|
|
|
|
|
|
|
|
writeVarInt(this.outs.length) |
|
|
writeVarInt(this.outs.length) |
|
|
this.outs.forEach(function (txOut) { |
|
|
this.outs.forEach(function (txOut) { |
|
|
|
|
|
if (!txOut.valueBuffer) { |
|
|
writeUInt64(txOut.value) |
|
|
writeUInt64(txOut.value) |
|
|
|
|
|
} else { |
|
|
|
|
|
writeSlice(txOut.valueBuffer) |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
writeVarInt(txOut.script.buffer.length) |
|
|
writeVarInt(txOut.script.buffer.length) |
|
|
writeSlice(txOut.script.buffer) |
|
|
writeSlice(txOut.script.buffer) |
|
|
}) |
|
|
}) |
|
|