get bitcoind script tests passing.

This commit is contained in:
Christopher Jeffrey 2016-04-19 01:30:12 -07:00
parent 397e1f7d0b
commit 59704b63c7
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
4 changed files with 2159 additions and 13 deletions

View File

@ -116,6 +116,9 @@ ec.verify = function verify(msg, sig, key, historical) {
if (key.getPublicKey)
key = key.getPublicKey();
if (key.length === 0)
return false;
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!

View File

@ -209,7 +209,15 @@ Witness.prototype.indexOf = function indexOf(data) {
Witness.fromString = function fromString(items) {
var i, op, symbol;
items = items.trim().split(/\s+/);
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();
@ -228,10 +236,22 @@ Witness.fromString = function fromString(items) {
} 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.substring(2);
op = op.slice(2);
assert(utils.isHex(op), 'Non-stack item in witness string.');
op = new Buffer(op, 'hex');
} else {
@ -245,6 +265,37 @@ Witness.fromString = function fromString(items) {
return new Witness(items);
};
/**
* Parse a test script/array
* string into a witness object. _Must_
* contain only stack items (no non-push
* opcodes).
* @param {String|String[]} items - Script string.
* @returns {Witness}
* @throws Parse error.
*/
Witness.fromTestString = function fromTestString(items) {
var result;
if (!Array.isArray(items)) {
if (typeof items !== 'string')
return new Witness();
items = items.trim();
}
if (items.length === 0)
return new Witness();
result = new Array(items.length);
for (i = 0; i < items.length; i++)
result[i] = new Buffer(items[i], 'hex');
return new Witness(result);
};
/**
* Parse an array of opcodes and pushdatas (Buffers) with the
* opcodes as strings representing their symbolic name.
@ -754,6 +805,9 @@ Stack.prototype.rot2 = function rot2() {
*/
Stack.prototype.swap2 = function swap2() {
if (this.length < 4)
throw new ScriptError('Stack too small.', opcodes.OP_2SWAP);
this._swap(-4, -2);
this._swap(-3, -1);
};
@ -1067,6 +1121,7 @@ Script.prototype.interpret = function interpret(stack, flags, tx, index, version
switch (op) {
case opcodes.OP_NOP:
break;
case opcodes.OP_NOP1:
case opcodes.OP_NOP4:
case opcodes.OP_NOP5:
@ -2011,9 +2066,6 @@ Script.checkMinimal = function checkMinimal(value, flags) {
if (!pushdata)
return true;
if (value.length === 1 && value[0] === 0)
return false;
if (value.length === 1 && value[0] >= 1 && value[0] <= 16)
return false;
@ -3486,23 +3538,40 @@ Script.prototype.getArgs = function getArgs() {
Script.fromString = function fromString(code) {
var i, op, symbol;
code = code.trim().split(/\s+/);
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];
if (op === '-1')
op = '1negate';
symbol = (op + '').toUpperCase();
symbol = op.toUpperCase();
if (symbol.indexOf('OP_') !== 0)
symbol = 'OP_' + op;
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 (op[0] === '[')
op = op.slice(1, -1);
if (/^-?\d+$/.test(op)) {
op = new bn(op, 10);
op = Script.array(op);
code[i] = op;
continue;
}
if (op.indexOf('0x') === 0)
op = op.substring(2);
op = op.slice(2);
assert(utils.isHex(op), 'Unknown opcode.');
op = new Buffer(op, 'hex');
code[i] = op;
@ -3515,6 +3584,61 @@ Script.fromString = function fromString(code) {
return new Script(code);
};
/**
* Parse a bitcoind test script
* string into a script object.
* @param {String} items - Script string.
* @returns {Script}
* @throws Parse error.
*/
Script.fromTestString = function fromTestString(code) {
var i, op, symbol, p;
if (typeof code !== 'string')
return new Script();
code = code.trim();
if (code.length === 0)
return new Script();
code = code.split(/\s+/);
p = new BufferWriter();
for (i = 0; i < code.length; i++) {
op = code[i];
symbol = 'OP_' + op.toUpperCase();
if (opcodes[symbol] == null) {
if (op[0] === '\'' || op[0] === '"') {
op = op.slice(1, -1);
p.writeBytes(Script.encode([new Buffer(op, 'ascii')]));
continue;
}
if (/^-?\d+$/.test(op)) {
op = new bn(op, 10);
op = Script.array(op);
p.writeBytes(Script.encode([op]));
continue;
}
assert(op.indexOf('0x') === 0)
op = op.slice(2);
assert(utils.isHex(op), 'Unknown opcode.');
if (op.length % 2 !== 0)
op = op + '0';
op = new Buffer(op, 'hex');
p.writeBytes(op);
continue;
}
p.writeU8(opcodes[symbol]);
}
return new Script(p.render());
};
/**
* Get a small integer from an opcode (OP_0-OP_16).
* @param {Number} index
@ -3622,7 +3746,10 @@ Script.verify = function verify(input, witness, output, tx, i, flags) {
}
// Execute the input script
input.execute(stack, flags, tx, i, 0);
res = input.execute(stack, flags, tx, i, 0);
if (!res)
return false;
// Copy the stack for P2SH
if (flags & constants.flags.VERIFY_P2SH)

1918
test/data/script_tests.json Normal file

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,11 @@ var assert = require('assert');
var bcoin = require('../')();
var Script = bcoin.script;
var Stack = bcoin.script.stack;
var utils = bcoin.utils;
var constants = bcoin.protocol.constants;
var opcodes = bcoin.protocol.constants.opcodes;
var scripts = require('./data/script_tests');
var bn = require('bn.js');
describe('Script', function() {
it('should encode/decode script', function() {
@ -129,4 +133,98 @@ describe('Script', function() {
assert(res);
assert.deepEqual(stack.slice(), [[1], [3], [5]]);
});
var dummyInput = {
prevout: {
hash: constants.NULL_HASH,
index: 0
},
coin: {
version: 1,
height: 0,
value: constants.MAX_MONEY.clone(),
script: new bcoin.script([]),
coinbase: false,
hash: constants.NULL_HASH,
index: 0
},
script: new bcoin.script([]),
witness: new bcoin.script.witness([]),
sequence: 0xffffffff
};
scripts.forEach(function(data) {
// ["Format is: [[wit...]?, scriptSig, scriptPubKey, flags, expected_scripterror, ... comments]"],
var witness = Array.isArray(data[0]) ? data.shift() : null;
var input = data[0] ? data[0].trim() : data[0] || '';
var output = data[1] ? data[1].trim() : data[1] || '';
var flags = data[2] ? data[2].trim().split(/,\s*/) : [];
var expected = data[3] || '';
var comments = Array.isArray(data[4]) ? data[4].join('. ') : data[4] || '';
if (data.length === 1)
return;
if (!comments)
comments = output.slice(0, 60);
comments += ' (' + expected + ')';
if (witness)
witness = bcoin.witness.fromTestString(witness);
else
witness = new bcoin.witness();
input = bcoin.script.fromTestString(input);
output = bcoin.script.fromTestString(output);
var flag = 0;
for (var i = 0; i < flags.length; i++) {
flag |= constants.flags['VERIFY_' + flags[i]];
}
flags = flag;
it('should handle script test: ' + comments, function () {
var coin = bcoin.tx({
version: 1,
inputs: [{
prevout: {
hash: constants.NULL_HASH,
index: 0xffffffff
},
coin: null,
script: [bcoin.script.array(0), bcoin.script.array(0)],
witness: new bcoin.script.witness(),
sequence: 0xffffffff
}],
outputs: [{
script: output,
value: new bn(0)
}],
locktime: 0
});
var tx = bcoin.tx({
version: 1,
inputs: [{
prevout: {
hash: coin.hash('hex'),
index: 0
},
coin: bcoin.coin(coin, 0),
script: input,
witness: witness,
sequence: 0xffffffff
}],
outputs: [{
script: new bcoin.script(),
value: new bn(0)
}],
locktime: 0
});
var res = Script.verify(input, witness, output, tx, 0, flags);
if (expected === 'OK')
assert.ok(res);
else
assert.ok(!res);
});
});
});