Merge pull request #363 from bitcoinjs/coinbase
Coinbase Transaction parsing
This commit is contained in:
commit
1da8297f3c
5 changed files with 76 additions and 94 deletions
35
src/block.js
35
src/block.js
|
@ -39,46 +39,17 @@ Block.fromBuffer = function(buffer) {
|
|||
|
||||
if (buffer.length === 80) return block
|
||||
|
||||
function readUInt64() {
|
||||
var i = bufferutils.readUInt64LE(buffer, offset)
|
||||
offset += 8
|
||||
return i
|
||||
}
|
||||
|
||||
function readVarInt() {
|
||||
var vi = bufferutils.readVarInt(buffer, offset)
|
||||
offset += vi.size
|
||||
return vi.number
|
||||
}
|
||||
|
||||
function readScript() {
|
||||
return Script.fromBuffer(readSlice(readVarInt()))
|
||||
}
|
||||
|
||||
// FIXME: poor performance
|
||||
function readTransaction() {
|
||||
var tx = new Transaction()
|
||||
tx.version = readUInt32()
|
||||
|
||||
var vinLen = readVarInt()
|
||||
for (var i = 0; i < vinLen; ++i) {
|
||||
tx.ins.push({
|
||||
hash: readSlice(32),
|
||||
index: readUInt32(),
|
||||
script: readScript(),
|
||||
sequence: readUInt32()
|
||||
})
|
||||
}
|
||||
|
||||
var voutLen = readVarInt()
|
||||
for (i = 0; i < voutLen; ++i) {
|
||||
tx.outs.push({
|
||||
value: readUInt64(),
|
||||
script: readScript(),
|
||||
})
|
||||
}
|
||||
|
||||
tx.locktime = readUInt32()
|
||||
var tx = Transaction.fromBuffer(buffer.slice(offset), true)
|
||||
|
||||
offset += tx.toBuffer().length
|
||||
return tx
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Transaction.SIGHASH_NONE = 0x02
|
|||
Transaction.SIGHASH_SINGLE = 0x03
|
||||
Transaction.SIGHASH_ANYONECANPAY = 0x80
|
||||
|
||||
Transaction.fromBuffer = function(buffer) {
|
||||
Transaction.fromBuffer = function(buffer, __disableAssert) {
|
||||
var offset = 0
|
||||
function readSlice(n) {
|
||||
offset += n
|
||||
|
@ -51,29 +51,48 @@ Transaction.fromBuffer = function(buffer) {
|
|||
return Script.fromBuffer(readSlice(readVarInt()))
|
||||
}
|
||||
|
||||
function readGenerationScript() {
|
||||
return new Script(readSlice(readVarInt()), [])
|
||||
}
|
||||
|
||||
var tx = new Transaction()
|
||||
tx.version = readUInt32()
|
||||
|
||||
var vinLen = readVarInt()
|
||||
for (var i = 0; i < vinLen; ++i) {
|
||||
var hash = readSlice(32)
|
||||
|
||||
if (Transaction.isCoinbaseHash(hash)) {
|
||||
tx.ins.push({
|
||||
hash: readSlice(32),
|
||||
hash: hash,
|
||||
index: readUInt32(),
|
||||
script: readGenerationScript(),
|
||||
sequence: readUInt32()
|
||||
})
|
||||
|
||||
} else {
|
||||
tx.ins.push({
|
||||
hash: hash,
|
||||
index: readUInt32(),
|
||||
script: readScript(),
|
||||
sequence: readUInt32()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var voutLen = readVarInt()
|
||||
for (i = 0; i < voutLen; ++i) {
|
||||
tx.outs.push({
|
||||
value: readUInt64(),
|
||||
script: readScript(),
|
||||
script: readScript()
|
||||
})
|
||||
}
|
||||
|
||||
tx.locktime = readUInt32()
|
||||
|
||||
if (!__disableAssert) {
|
||||
assert.equal(offset, buffer.length, 'Transaction has unexpected data')
|
||||
}
|
||||
|
||||
return tx
|
||||
}
|
||||
|
@ -82,6 +101,12 @@ Transaction.fromHex = function(hex) {
|
|||
return Transaction.fromBuffer(new Buffer(hex, 'hex'))
|
||||
}
|
||||
|
||||
Transaction.isCoinbaseHash = function(buffer) {
|
||||
return Array.prototype.every.call(buffer, function(x) {
|
||||
return x === 0
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new txIn.
|
||||
*
|
||||
|
@ -243,20 +268,18 @@ Transaction.prototype.getId = function () {
|
|||
}
|
||||
|
||||
Transaction.prototype.toBuffer = function () {
|
||||
var txInSize = this.ins.reduce(function(a, x) {
|
||||
return a + (40 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
|
||||
}, 0)
|
||||
function scriptSize(script) {
|
||||
var length = script.buffer.length
|
||||
|
||||
var txOutSize = this.outs.reduce(function(a, x) {
|
||||
return a + (8 + bufferutils.varIntSize(x.script.buffer.length) + x.script.buffer.length)
|
||||
}, 0)
|
||||
return bufferutils.varIntSize(length) + length
|
||||
}
|
||||
|
||||
var buffer = new Buffer(
|
||||
8 +
|
||||
bufferutils.varIntSize(this.ins.length) +
|
||||
bufferutils.varIntSize(this.outs.length) +
|
||||
txInSize +
|
||||
txOutSize
|
||||
this.ins.reduce(function(sum, input) { return sum + 40 + scriptSize(input.script) }, 0) +
|
||||
this.outs.reduce(function(sum, output) { return sum + 8 + scriptSize(output.script) }, 0)
|
||||
)
|
||||
|
||||
var offset = 0
|
||||
|
|
|
@ -7,12 +7,6 @@ var ECSignature = require('./ecsignature')
|
|||
var Script = require('./script')
|
||||
var Transaction = require('./transaction')
|
||||
|
||||
function isCoinbase(txHash) {
|
||||
return Array.prototype.every.call(txHash, function(x) {
|
||||
return x === 0
|
||||
})
|
||||
}
|
||||
|
||||
function extractInput(txIn) {
|
||||
var redeemScript
|
||||
var scriptSig = txIn.script
|
||||
|
@ -116,7 +110,7 @@ TransactionBuilder.fromTransaction = function(transaction) {
|
|||
// Extract/add signatures
|
||||
txb.inputs = transaction.ins.map(function(txIn) {
|
||||
// TODO: remove me after testcase added
|
||||
assert(!isCoinbase(txIn.hash), 'coinbase inputs not supported')
|
||||
assert(!Transaction.isCoinbaseHash(txIn.hash), 'coinbase inputs not supported')
|
||||
|
||||
// Ignore empty scripts
|
||||
if (txIn.script.buffer.length === 0) return
|
||||
|
|
24
test/fixtures/transaction.json
vendored
24
test/fixtures/transaction.json
vendored
File diff suppressed because one or more lines are too long
|
@ -16,7 +16,14 @@ describe('Transaction', function() {
|
|||
|
||||
raw.ins.forEach(function(txIn) {
|
||||
var txHash = new Buffer(txIn.hash, 'hex')
|
||||
var script = txIn.script ? Script.fromASM(txIn.script) : undefined
|
||||
var script
|
||||
|
||||
if (txIn.data) {
|
||||
script = new Script(new Buffer(txIn.data, 'hex'), [])
|
||||
|
||||
} else if (txIn.script) {
|
||||
script = Script.fromASM(txIn.script)
|
||||
}
|
||||
|
||||
tx.addInput(txHash, txIn.index, txIn.sequence, script)
|
||||
})
|
||||
|
@ -108,28 +115,6 @@ describe('Transaction', function() {
|
|||
assert.equal(tx.ins[0].script, Script.EMPTY)
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('should add the inputs for ' + f.id + ' correctly', function() {
|
||||
var tx = new Transaction()
|
||||
|
||||
f.raw.ins.forEach(function(txIn, i) {
|
||||
var txHash = new Buffer(txIn.hash, 'hex')
|
||||
var script = txIn.script ? Script.fromASM(txIn.script) : undefined
|
||||
var j = tx.addInput(txHash, txIn.index, txIn.sequence, script)
|
||||
var sequence = txIn.sequence
|
||||
if (sequence === undefined || sequence === null ) {
|
||||
sequence = Transaction.DEFAULT_SEQUENCE
|
||||
}
|
||||
|
||||
assert.equal(i, j)
|
||||
assert.equal(tx.ins[i].hash.toString('hex'), txIn.hash)
|
||||
assert.equal(tx.ins[i].index, txIn.index)
|
||||
assert.equal(tx.ins[i].sequence, sequence)
|
||||
assert.deepEqual(tx.ins[i].script, script || Script.EMPTY)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fixtures.invalid.addInput.forEach(function(f) {
|
||||
it('throws on ' + f.exception, function() {
|
||||
var tx = new Transaction()
|
||||
|
@ -181,21 +166,6 @@ describe('Transaction', function() {
|
|||
assert.equal(tx.addOutput(destScript, 40000), 0)
|
||||
assert.equal(tx.addOutput(destScript, 40000), 1)
|
||||
})
|
||||
|
||||
fixtures.valid.forEach(function(f) {
|
||||
it('should add the outputs for ' + f.id + ' correctly', function() {
|
||||
var tx = new Transaction()
|
||||
|
||||
f.raw.outs.forEach(function(txOut, i) {
|
||||
var scriptPubKey = Script.fromASM(txOut.script)
|
||||
var j = tx.addOutput(scriptPubKey, txOut.value)
|
||||
|
||||
assert.equal(i, j)
|
||||
assert.equal(tx.outs[i].script, scriptPubKey)
|
||||
assert.equal(tx.outs[i].value, txOut.value)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('clone', function() {
|
||||
|
|
Loading…
Add table
Reference in a new issue