Browse Source

Merge pull request #1038 from bitcoinjs/__tx

Privatise TransactionBuilder internals
addLowRGrinding
Daniel Cousens 7 years ago
committed by GitHub
parent
commit
09c5ff1d6b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 52
      src/transaction_builder.js
  2. 31
      test/transaction_builder.js

52
src/transaction_builder.js

@ -468,14 +468,14 @@ function buildInput (input, allowIncomplete) {
}
function TransactionBuilder (network, maximumFeeRate) {
this.prevTxMap = {}
this.__prevTxSet = {}
this.network = network || networks.bitcoin
// WARNING: This is __NOT__ to be relied on, its just another potential safety mechanism (safety in-depth)
this.maximumFeeRate = maximumFeeRate || 2500
this.inputs = []
this.tx = new Transaction()
this.__inputs = []
this.__tx = new Transaction()
this.tx.version = 2
}
@ -483,7 +483,7 @@ TransactionBuilder.prototype.setLockTime = function (locktime) {
typeforce(types.UInt32, locktime)
// if any signatures exist, throw
if (this.inputs.some(function (input) {
if (this.__inputs.some(function (input) {
if (!input.signatures) return false
return input.signatures.some(function (s) { return s })
@ -491,14 +491,14 @@ TransactionBuilder.prototype.setLockTime = function (locktime) {
throw new Error('No, this would invalidate signatures')
}
this.tx.locktime = locktime
this.__tx.locktime = locktime
}
TransactionBuilder.prototype.setVersion = function (version) {
typeforce(types.UInt32, version)
// XXX: this might eventually become more complex depending on what the versions represent
this.tx.version = version
this.__tx.version = version
}
TransactionBuilder.fromTransaction = function (transaction, network) {
@ -523,7 +523,7 @@ TransactionBuilder.fromTransaction = function (transaction, network) {
})
// fix some things not possible through the public API
txb.inputs.forEach(function (input, i) {
txb.__inputs.forEach(function (input, i) {
fixMultisigOrder(input, transaction, i)
})
@ -564,7 +564,7 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options)
}
var prevTxOut = txHash.toString('hex') + ':' + vout
if (this.prevTxMap[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut)
if (this.__prevTxSet[prevTxOut] !== undefined) throw new Error('Duplicate TxOut: ' + prevTxOut)
var input = {}
@ -597,9 +597,9 @@ TransactionBuilder.prototype.__addInputUnsafe = function (txHash, vout, options)
input.prevOutType = prevOutType || btemplates.classifyOutput(options.prevOutScript)
}
var vin = this.tx.addInput(txHash, vout, options.sequence, options.scriptSig)
this.inputs[vin] = input
this.prevTxMap[prevTxOut] = vin
var vin = this.__tx.addInput(txHash, vout, options.sequence, options.scriptSig)
this.__inputs[vin] = input
this.__prevTxSet[prevTxOut] = true
return vin
}
@ -613,7 +613,7 @@ TransactionBuilder.prototype.addOutput = function (scriptPubKey, value) {
scriptPubKey = baddress.toOutputScript(scriptPubKey, this.network)
}
return this.tx.addOutput(scriptPubKey, value)
return this.__tx.addOutput(scriptPubKey, value)
}
TransactionBuilder.prototype.build = function () {
@ -625,13 +625,13 @@ TransactionBuilder.prototype.buildIncomplete = function () {
TransactionBuilder.prototype.__build = function (allowIncomplete) {
if (!allowIncomplete) {
if (!this.tx.ins.length) throw new Error('Transaction has no inputs')
if (!this.tx.outs.length) throw new Error('Transaction has no outputs')
if (!this.__tx.ins.length) throw new Error('Transaction has no inputs')
if (!this.__tx.outs.length) throw new Error('Transaction has no outputs')
}
var tx = this.tx.clone()
var tx = this.__tx.clone()
// Create script signatures from inputs
this.inputs.forEach(function (input, i) {
this.__inputs.forEach(function (input, i) {
var scriptType = input.witnessScriptType || input.redeemScriptType || input.prevOutType
if (!scriptType && !allowIncomplete) throw new Error('Transaction is not complete')
var result = buildInput(input, allowIncomplete)
@ -673,10 +673,10 @@ function canSign (input) {
TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashType, witnessValue, witnessScript) {
// TODO: remove keyPair.network matching in 4.0.0
if (keyPair.network && keyPair.network !== this.network) throw new TypeError('Inconsistent network')
if (!this.inputs[vin]) throw new Error('No input at index: ' + vin)
if (!this.__inputs[vin]) throw new Error('No input at index: ' + vin)
hashType = hashType || Transaction.SIGHASH_ALL
var input = this.inputs[vin]
var input = this.__inputs[vin]
// if redeemScript was previously provided, enforce consistency
if (input.redeemScript !== undefined &&
@ -700,9 +700,9 @@ TransactionBuilder.prototype.sign = function (vin, keyPair, redeemScript, hashTy
// ready to sign
var signatureHash
if (input.witness) {
signatureHash = this.tx.hashForWitnessV0(vin, input.signScript, input.value, hashType)
signatureHash = this.__tx.hashForWitnessV0(vin, input.signScript, input.value, hashType)
} else {
signatureHash = this.tx.hashForSignature(vin, input.signScript, hashType)
signatureHash = this.__tx.hashForSignature(vin, input.signScript, hashType)
}
// enforce in order signing of public keys
@ -731,7 +731,7 @@ function signatureHashType (buffer) {
}
TransactionBuilder.prototype.__canModifyInputs = function () {
return this.inputs.every(function (input) {
return this.__inputs.every(function (input) {
// any signatures?
if (input.signatures === undefined) return true
@ -747,10 +747,10 @@ TransactionBuilder.prototype.__canModifyInputs = function () {
}
TransactionBuilder.prototype.__canModifyOutputs = function () {
var nInputs = this.tx.ins.length
var nOutputs = this.tx.outs.length
var nInputs = this.__tx.ins.length
var nOutputs = this.__tx.outs.length
return this.inputs.every(function (input) {
return this.__inputs.every(function (input) {
if (input.signatures === undefined) return true
return input.signatures.every(function (signature) {
@ -771,11 +771,11 @@ TransactionBuilder.prototype.__canModifyOutputs = function () {
TransactionBuilder.prototype.__overMaximumFees = function (bytes) {
// not all inputs will have .value defined
var incoming = this.inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0)
var incoming = this.__inputs.reduce(function (a, x) { return a + (x.value >>> 0) }, 0)
// but all outputs do, and if we have any input value
// we can immediately determine if the outputs are too small
var outgoing = this.tx.outs.reduce(function (a, x) { return a + x.value }, 0)
var outgoing = this.__tx.outs.reduce(function (a, x) { return a + x.value }, 0)
var fee = incoming - outgoing
var feeRate = fee / bytes

31
test/transaction_builder.js

@ -133,10 +133,11 @@ describe('TransactionBuilder', function () {
})
})
it('correctly classifies transaction inputs', function () {
it('classifies transaction inputs', function () {
var tx = Transaction.fromHex(fixtures.valid.classification.hex)
var txb = TransactionBuilder.fromTransaction(tx)
txb.inputs.forEach(function (i) {
txb.__inputs.forEach(function (i) {
assert.strictEqual(i.prevOutType, 'scripthash')
assert.strictEqual(i.redeemScriptType, 'multisig')
assert.strictEqual(i.signType, 'multisig')
@ -164,22 +165,22 @@ describe('TransactionBuilder', function () {
var vin = txb.addInput(txHash, 1, 54)
assert.strictEqual(vin, 0)
var txIn = txb.tx.ins[0]
var txIn = txb.__tx.ins[0]
assert.strictEqual(txIn.hash, txHash)
assert.strictEqual(txIn.index, 1)
assert.strictEqual(txIn.sequence, 54)
assert.strictEqual(txb.inputs[0].prevOutScript, undefined)
assert.strictEqual(txb.__inputs[0].prevOutScript, undefined)
})
it('accepts a txHash, index [, sequence number and scriptPubKey]', function () {
var vin = txb.addInput(txHash, 1, 54, scripts[1])
assert.strictEqual(vin, 0)
var txIn = txb.tx.ins[0]
var txIn = txb.__tx.ins[0]
assert.strictEqual(txIn.hash, txHash)
assert.strictEqual(txIn.index, 1)
assert.strictEqual(txIn.sequence, 54)
assert.strictEqual(txb.inputs[0].prevOutScript, scripts[1])
assert.strictEqual(txb.__inputs[0].prevOutScript, scripts[1])
})
it('accepts a prevTx, index [and sequence number]', function () {
@ -190,11 +191,11 @@ describe('TransactionBuilder', function () {
var vin = txb.addInput(prevTx, 1, 54)
assert.strictEqual(vin, 0)
var txIn = txb.tx.ins[0]
var txIn = txb.__tx.ins[0]
assert.deepEqual(txIn.hash, prevTx.getHash())
assert.strictEqual(txIn.index, 1)
assert.strictEqual(txIn.sequence, 54)
assert.strictEqual(txb.inputs[0].prevOutScript, scripts[1])
assert.strictEqual(txb.__inputs[0].prevOutScript, scripts[1])
})
it('returns the input index', function () {
@ -222,7 +223,7 @@ describe('TransactionBuilder', function () {
var vout = txb.addOutput(keyPair.getAddress(), 1000)
assert.strictEqual(vout, 0)
var txout = txb.tx.outs[0]
var txout = txb.__tx.outs[0]
assert.deepEqual(txout.script, scripts[0])
assert.strictEqual(txout.value, 1000)
})
@ -231,7 +232,7 @@ describe('TransactionBuilder', function () {
var vout = txb.addOutput(scripts[0], 1000)
assert.strictEqual(vout, 0)
var txout = txb.tx.outs[0]
var txout = txb.__tx.outs[0]
assert.deepEqual(txout.script, scripts[0])
assert.strictEqual(txout.value, 1000)
})
@ -505,10 +506,10 @@ describe('TransactionBuilder', function () {
'194a565cd6aa4cc38b8eaffa343402201c5b4b61d73fa38e49c1ee68cc0e6dfd2f5dae453dd86eb142e87a' +
'0bafb1bc8401210283409659355b6d1cc3c32decd5d561abaac86c37a353b52895a5e6c196d6f44800000000'
var txb = TransactionBuilder.fromTransaction(Transaction.fromHex(rawtx))
txb.inputs[0].value = 241530
txb.inputs[1].value = 241530
txb.inputs[2].value = 248920
txb.inputs[3].value = 248920
txb.__inputs[0].value = 241530
txb.__inputs[1].value = 241530
txb.__inputs[2].value = 248920
txb.__inputs[3].value = 248920
assert.throws(function () {
txb.build()
@ -532,7 +533,7 @@ describe('TransactionBuilder', function () {
var txHex = tx.toHex()
var newTxb = TransactionBuilder.fromTransaction(Transaction.fromHex(txHex))
// input should have the key 'witness' set to true
assert.equal(newTxb.inputs[0].witness, true)
assert.equal(newTxb.__inputs[0].witness, true)
})
it('should handle badly pre-filled OP_0s', function () {

Loading…
Cancel
Save