get bitcoind script tests passing.
This commit is contained in:
parent
397e1f7d0b
commit
59704b63c7
@ -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!
|
||||
|
||||
@ -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
1918
test/data/script_tests.json
Normal file
File diff suppressed because one or more lines are too long
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user