better script inspection.

This commit is contained in:
Christopher Jeffrey 2016-04-20 14:12:40 -07:00
parent c1fd8bb285
commit 64b92ab073
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
3 changed files with 73 additions and 165 deletions

View File

@ -70,11 +70,13 @@ function Witness(items, mutable) {
/**
* Inspect a Witness object.
* @method
* @returns {String} Human-readable script.
*/
Witness.prototype.toString =
Witness.prototype.inspect = function inspect() {
return Script.format(this.items);
return Witness.format(this.items);
};
/**
@ -237,75 +239,6 @@ Witness.fromRaw = function fromRaw(data, enc) {
return new Witness(Witness.parseRaw(data, enc));
};
/**
* Parse a formatted script
* string into a witness object. _Must_
* contain only stack items (no non-push
* opcodes).
* @param {String} items - Script string.
* @returns {Witness}
* @throws Parse error.
*/
Witness.fromString = function fromString(items) {
var i, op, symbol;
if (typeof items !== 'string')
return new Witness();
items = items.trim();
if (items.length === 0)
return new Witness();
items = items.split(/\s+/);
for (i = 0; i < items.length; i++) {
op = items[i].toLowerCase();
if (op.indexOf('op_') === 0)
op = op.slice(3);
if (op === '-1' || op === '1negate') {
op = STACK_NEGATE;
} else if (op === '0' || op === 'false') {
op = STACK_FALSE;
} else if (op === 'true') {
op = STACK_TRUE;
} else if (+op >= 1 && +op <= 16) {
op = new Buffer([+op]);
} else {
symbol = 'OP_' + op.toUpperCase();
if (opcodes[symbol] == null) {
if (op[0] === '\'' || op[0] === '"') {
op = op.slice(1, -1);
op = new Buffer(op, 'ascii');
items[i] = op;
continue;
}
if (/^-?\d+$/.test(op)) {
op = new bn(op, 10);
op = Script.array(op);
items[i] = op;
continue;
}
if (op[0] === '[')
op = op.slice(1, -1);
if (op.indexOf('0x') === 0)
op = op.slice(2);
assert(utils.isHex(op), 'Non-stack item in witness string.');
op = new Buffer(op, 'hex');
} else {
assert(false, 'Non-stack item in witness string.');
}
}
items[i] = op;
}
return new Witness(items);
};
/**
* Parse a test script/array
* string into a witness object. _Must_
@ -316,14 +249,14 @@ Witness.fromString = function fromString(items) {
* @throws Parse error.
*/
Witness.fromTestString = function fromTestString(items) {
Witness.fromString = function fromString(items) {
var result;
if (!Array.isArray(items)) {
if (typeof items !== 'string')
return new Witness();
items = items.trim();
items = items.trim().split(/\s+/);
}
if (items.length === 0)
@ -381,6 +314,18 @@ Witness.fromSymbolic = function fromSymbolic(items) {
return new Witness(code);
};
/**
* Format script code into a human readable-string.
* @param {Array} code
* @returns {String} Human-readable string.
*/
Witness.format = function format(items) {
return items.map(function(chunk) {
return chunk.toString('hex');
}).join(' ');
};
/**
* Test an object to see if it is a Witness.
* @param {Object} obj
@ -414,11 +359,13 @@ function Stack(items) {
/**
* Inspect the stack.
* @method
* @returns {String} Human-readable stack.
*/
Stack.prototype.toString =
Stack.prototype.inspect = function inspect() {
return Script.format(this.items);
return Witness.format(this.items);
};
Stack.prototype.__defineGetter__('length', function() {
@ -939,9 +886,11 @@ Script.prototype.clone = function clone(mutable) {
/**
* Inspect the script.
* @method
* @returns {String} Human-readable script code.
*/
Script.prototype.toString =
Script.prototype.inspect = function inspect() {
return Script.format(this.code);
};
@ -3396,32 +3345,48 @@ Script.isLowDER = function isLowDER(sig) {
*/
Script.format = function format(code) {
var scripts = [];
return code.map(function(chunk) {
var op, size;
if (Array.isArray(code)) {
scripts.push({ code: code });
} else if (code instanceof Stack) {
scripts.push({ code: code.items });
} else if (code instanceof Witness) {
scripts.push({ code: code.items });
} else if (code instanceof Script) {
scripts.push(code);
} else if (code instanceof bcoin.input) {
scripts.push(code.script);
if (code.witness.length > 0)
scripts.push({ code: code.witness.items });
if (code.coin) {
scripts.push(code.coin.script);
if (code.coin.script.isScripthash())
scripts.push(code.coin.script.getRedeem());
if (Buffer.isBuffer(chunk)) {
op = chunk.op;
if (op == null) {
if (chunk.length === 0) {
op = opcodes.OP_0;
} else if (chunk.length <= 0x4b) {
if (chunk.length === 1) {
if (chunk[0] === 0) {
op = opcodes.OP_0;
return constants.opcodesByVal[op];
} else if (chunk[0] >= 1 && chunk[0] <= 16) {
op = chunk[0] + 0x50;
return constants.opcodesByVal[op];
} else if (chunk[0] === 0x81) {
op = opcodes.OP_1NEGATE;
return constants.opcodesByVal[op];
}
}
op = chunk.length;
} else if (chunk.length <= 0xff) {
op = opcodes.OP_PUSHDATA1;
} else if (chunk.length <= 0xffff) {
op = opcodes.OP_PUSHDATA2;
} else if (chunk.length <= 0xffffffff) {
op = opcodes.OP_PUSHDATA4;
}
}
size = chunk.length.toString(16);
if (size.length < 2)
size = '0' + size;
if (!constants.opcodesByVal[op]) {
op = op.toString(16);
if (op.length < 2)
op = '0' + op;
return '0x' + op + ' 0x' + chunk.toString('hex');
}
op = constants.opcodesByVal[op];
return op + ' 0x' + size + ' 0x' + chunk.toString('hex');
}
} else if (code instanceof bcoin.output) {
scripts.push(code.script);
}
return Script.concat(scripts).map(function(chunk) {
if (Buffer.isBuffer(chunk))
return '[' + chunk.toString('hex') + ']';
assert(typeof chunk === 'number');
@ -3432,7 +3397,7 @@ Script.format = function format(code) {
if (chunk.length < 2)
chunk = '0' + chunk;
return 'UNKNOWN(' + chunk + ')';
return '0x' + chunk;
}).join(' ');
};
@ -3531,63 +3496,6 @@ Script.prototype.getArgs = function getArgs() {
return -1;
};
/**
* Parse a formatted script
* string into a script object.
* @param {String} items - Script string.
* @returns {Script}
* @throws Parse error.
*/
Script.fromString = function fromString(code) {
var i, op, symbol;
if (typeof code !== 'string')
return new Script();
code = code.trim();
if (code.length === 0)
return new Script();
code = code.split(/\s+/);
for (i = 0; i < code.length; i++) {
op = code[i];
symbol = op.toUpperCase();
if (symbol.indexOf('OP_') !== 0)
symbol = 'OP_' + symbol;
if (opcodes[symbol] == null) {
if (op[0] === '\'' || op[0] === '"') {
op = op.slice(1, -1);
op = new Buffer(op, 'ascii');
code[i] = op;
continue;
}
if (/^-?\d+$/.test(op)) {
op = new bn(op, 10);
op = Script.array(op);
code[i] = op;
continue;
}
if (op[0] === '[')
op = op.slice(1, -1);
if (op.indexOf('0x') === 0)
op = op.slice(2);
assert(utils.isHex(op), 'Unknown opcode.');
op = new Buffer(op, 'hex');
code[i] = op;
continue;
}
code[i] = opcodes[symbol];
}
return new Script(code);
};
/**
* Parse a bitcoind test script
* string into a script object.
@ -3596,7 +3504,7 @@ Script.fromString = function fromString(code) {
* @throws Parse error.
*/
Script.fromTestString = function fromTestString(code) {
Script.fromString = function fromString(code) {
var i, op, symbol, p;
if (typeof code !== 'string')

View File

@ -143,7 +143,7 @@ describe('Script', function() {
it('should handle bad size pushes correctly.', function () {
var err;
var stack = new bcoin.script.stack();
var s = bcoin.script.fromTestString(
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1'
);
assert(utils.equals(s.raw, new Buffer('51764c', 'hex')));
@ -156,7 +156,7 @@ describe('Script', function() {
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromTestString(
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x01'
);
assert(utils.equals(s.raw, new Buffer('51764d01', 'hex')));
@ -170,7 +170,7 @@ describe('Script', function() {
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromTestString(
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA4 0x0001'
);
assert(utils.equals(s.raw, new Buffer('51764e0001', 'hex')));
@ -184,7 +184,7 @@ describe('Script', function() {
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromTestString(
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA1 0x02 0x01'
);
assert(utils.equals(s.raw, new Buffer('51764c0201', 'hex')));
@ -198,7 +198,7 @@ describe('Script', function() {
}
assert(err);
assert(err.code === 'BAD_OPCODE');
var s = bcoin.script.fromTestString(
var s = bcoin.script.fromString(
'OP_1 OP_DUP OP_PUSHDATA2 0x0200 0x01'
);
assert(utils.equals(s.raw, new Buffer('51764d020001', 'hex')));
@ -275,9 +275,9 @@ describe('Script', function() {
comments += ' (' + expected + ')';
witness = bcoin.witness.fromTestString(witness);
input = bcoin.script.fromTestString(input);
output = bcoin.script.fromTestString(output);
witness = bcoin.witness.fromString(witness);
input = bcoin.script.fromString(input);
output = bcoin.script.fromString(output);
var flag = 0;
for (var i = 0; i < flags.length; i++) {

View File

@ -152,7 +152,7 @@ describe('TX', function() {
coins.forEach(function(data) {
var hash = data[0];
var index = data[1];
var script = bcoin.script.fromTestString(data[2]);
var script = bcoin.script.fromString(data[2]);
var value = data[3];
var coin = new bcoin.coin({
version: 1,