bitcoinjs-lib/src/script.js

148 lines
3.2 KiB
JavaScript
Raw Normal View History

2014-05-28 19:36:33 +10:00
var bufferutils = require('./bufferutils')
2014-04-08 22:00:28 +10:00
var crypto = require('./crypto')
2015-08-11 17:01:47 +10:00
var typeforce = require('typeforce')
var types = require('./types')
2014-05-13 23:14:07 +10:00
var opcodes = require('./opcodes')
2012-01-11 02:40:45 +01:00
2015-02-23 10:36:57 +11:00
function Script (buffer, chunks) {
2015-08-11 17:01:47 +10:00
typeforce(types.tuple(types.Buffer, types.Array), arguments)
2014-05-05 13:07:19 +10:00
this.buffer = buffer
this.chunks = chunks
2014-03-31 11:47:47 +08:00
}
2015-02-23 10:36:57 +11:00
Script.fromASM = function (asm) {
2014-06-25 15:44:15 +10:00
var strChunks = asm.split(' ')
2015-02-23 10:36:57 +11:00
var chunks = strChunks.map(function (strChunk) {
// opcode
2014-06-25 15:44:15 +10:00
if (strChunk in opcodes) {
return opcodes[strChunk]
2015-02-23 10:36:57 +11:00
// data chunk
2014-06-25 15:44:15 +10:00
} else {
return new Buffer(strChunk, 'hex')
}
})
return Script.fromChunks(chunks)
}
2015-02-23 10:36:57 +11:00
Script.fromBuffer = function (buffer) {
var chunks = []
2014-03-31 11:47:47 +08:00
var i = 0
2012-01-11 02:40:45 +01:00
while (i < buffer.length) {
var opcode = buffer.readUInt8(i)
2015-02-23 10:36:57 +11:00
// data chunk
if ((opcode > opcodes.OP_0) && (opcode <= opcodes.OP_PUSHDATA4)) {
var d = bufferutils.readPushDataInt(buffer, i)
// did reading a pushDataInt fail? return non-chunked script
if (d === null) return new Script(buffer, [])
i += d.size
// attempt to read too much data?
if (i + d.number > buffer.length) return new Script(buffer, [])
var data = buffer.slice(i, i + d.number)
i += d.number
chunks.push(data)
2012-01-11 02:40:45 +01:00
2015-02-23 10:36:57 +11:00
// opcode
2014-03-31 11:47:47 +08:00
} else {
chunks.push(opcode)
i += 1
2012-01-11 02:40:45 +01:00
}
2014-03-31 11:47:47 +08:00
}
return new Script(buffer, chunks)
}
2015-02-23 10:36:57 +11:00
Script.fromChunks = function (chunks) {
2015-08-11 17:01:47 +10:00
typeforce(types.Array, chunks)
2015-02-23 10:36:57 +11:00
var bufferSize = chunks.reduce(function (accum, chunk) {
// data chunk
if (Buffer.isBuffer(chunk)) {
2014-06-13 09:36:11 +10:00
return accum + bufferutils.pushDataSize(chunk.length) + chunk.length
}
2015-02-23 10:36:57 +11:00
// opcode
2014-06-13 09:36:11 +10:00
return accum + 1
}, 0.0)
var buffer = new Buffer(bufferSize)
var offset = 0
2015-02-23 10:36:57 +11:00
chunks.forEach(function (chunk) {
// data chunk
if (Buffer.isBuffer(chunk)) {
offset += bufferutils.writePushDataInt(buffer, chunk.length, offset)
chunk.copy(buffer, offset)
offset += chunk.length
2015-02-23 10:36:57 +11:00
// opcode
} else {
buffer.writeUInt8(chunk, offset)
offset += 1
}
})
2015-08-11 17:05:27 +10:00
if (offset !== buffer.length) throw new Error('Could not decode chunks')
return new Script(buffer, chunks)
}
2015-02-23 10:36:57 +11:00
Script.fromHex = function (hex) {
return Script.fromBuffer(new Buffer(hex, 'hex'))
}
Script.EMPTY = Script.fromChunks([])
Script.prototype.equals = function (script) {
return bufferutils.equal(this.buffer, script.buffer)
}
2015-02-23 10:36:57 +11:00
Script.prototype.getHash = function () {
return crypto.hash160(this.buffer)
}
// FIXME: doesn't work for data chunks, maybe time to use buffertools.compare...
2015-02-23 10:36:57 +11:00
Script.prototype.without = function (needle) {
return Script.fromChunks(this.chunks.filter(function (op) {
return op !== needle
}))
}
2014-06-25 15:44:15 +10:00
var reverseOps = []
for (var op in opcodes) {
var code = opcodes[op]
reverseOps[code] = op
}
2015-02-23 10:36:57 +11:00
Script.prototype.toASM = function () {
return this.chunks.map(function (chunk) {
// data chunk
2014-06-25 15:44:15 +10:00
if (Buffer.isBuffer(chunk)) {
return chunk.toString('hex')
2015-02-23 10:36:57 +11:00
// opcode
2014-06-25 15:44:15 +10:00
} else {
return reverseOps[chunk]
}
}).join(' ')
}
2015-02-23 10:36:57 +11:00
Script.prototype.toBuffer = function () {
return this.buffer
}
2015-02-23 10:36:57 +11:00
Script.prototype.toHex = function () {
return this.toBuffer().toString('hex')
2014-03-31 11:47:47 +08:00
}
2012-01-11 02:40:45 +01:00
2014-03-31 11:47:47 +08:00
module.exports = Script