2017-07-30 16:49:24 -07:00
|
|
|
/* eslint-env mocha */
|
2017-07-31 00:34:42 -07:00
|
|
|
/* eslint prefer-arrow-callback: "off" */
|
2017-07-30 16:49:24 -07:00
|
|
|
|
2016-06-13 01:06:01 -07:00
|
|
|
'use strict';
|
|
|
|
|
|
2017-08-10 11:17:10 -07:00
|
|
|
const assert = require('./util/assert');
|
2017-06-29 20:54:07 -07:00
|
|
|
const Script = require('../lib/script/script');
|
|
|
|
|
const Witness = require('../lib/script/witness');
|
|
|
|
|
const Stack = require('../lib/script/stack');
|
2017-08-21 04:32:06 -07:00
|
|
|
const Opcode = require('../lib/script/opcode');
|
2017-06-29 20:54:07 -07:00
|
|
|
const TX = require('../lib/primitives/tx');
|
2017-12-05 03:14:34 -08:00
|
|
|
const consensus = require('../lib/protocol/consensus');
|
2017-10-26 04:07:36 -07:00
|
|
|
const {fromFloat} = require('../lib/utils/fixed');
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const scripts = require('./data/script-tests.json');
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-10 09:41:01 -07:00
|
|
|
function isSuccess(stack) {
|
2016-12-10 07:43:54 -08:00
|
|
|
if (stack.length === 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2017-08-21 04:32:06 -07:00
|
|
|
if (!stack.getBool(-1))
|
2016-12-10 07:43:54 -08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-05-04 23:24:32 +04:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
function parseScriptTest(data) {
|
2017-08-09 15:28:03 -07:00
|
|
|
const witArr = Array.isArray(data[0]) ? data.shift() : [];
|
2017-08-11 00:06:33 -07:00
|
|
|
const inpHex = data[0];
|
|
|
|
|
const outHex = data[1];
|
|
|
|
|
const names = data[2] || 'NONE';
|
|
|
|
|
const expected = data[3];
|
|
|
|
|
let comments = data[4];
|
2017-08-01 17:46:53 -07:00
|
|
|
|
|
|
|
|
if (!comments)
|
|
|
|
|
comments = outHex.slice(0, 60);
|
|
|
|
|
|
|
|
|
|
comments += ` (${expected})`;
|
|
|
|
|
|
2017-08-09 17:45:10 -07:00
|
|
|
let value = 0;
|
|
|
|
|
if (witArr.length > 0)
|
2017-10-26 04:07:36 -07:00
|
|
|
value = fromFloat(witArr.pop(), 8);
|
2017-08-01 17:46:53 -07:00
|
|
|
|
2017-08-09 15:28:03 -07:00
|
|
|
const witness = Witness.fromString(witArr);
|
2017-08-01 17:46:53 -07:00
|
|
|
const input = Script.fromString(inpHex);
|
|
|
|
|
const output = Script.fromString(outHex);
|
|
|
|
|
|
|
|
|
|
let flags = 0;
|
2017-08-11 00:06:33 -07:00
|
|
|
for (const name of names.split(',')) {
|
|
|
|
|
const flag = Script.flags[`VERIFY_${name}`];
|
|
|
|
|
|
|
|
|
|
if (flag == null)
|
|
|
|
|
throw new Error(`Unknown flag: ${name}.`);
|
|
|
|
|
|
|
|
|
|
flags |= flag;
|
2017-08-01 17:46:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
witness: witness,
|
|
|
|
|
input: input,
|
|
|
|
|
output: output,
|
2017-08-09 17:45:10 -07:00
|
|
|
value: value,
|
2017-08-01 17:46:53 -07:00
|
|
|
flags: flags,
|
|
|
|
|
expected: expected,
|
|
|
|
|
comments: comments
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-04 23:24:32 +04:00
|
|
|
describe('Script', function() {
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should recognize a P2SH output', () => {
|
2017-07-27 09:27:00 -07:00
|
|
|
const hex = 'a91419a7d869032368fd1f1e26e5e73a4ad0e474960e87';
|
|
|
|
|
const decoded = Script.fromRaw(hex, 'hex');
|
2016-05-15 21:47:39 -07:00
|
|
|
assert(decoded.isScripthash());
|
2016-03-14 20:33:15 -07:00
|
|
|
});
|
2014-12-18 14:16:39 +01:00
|
|
|
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should recognize a Null Data output', () => {
|
2017-07-27 09:27:00 -07:00
|
|
|
const hex = '6a28590c080112220a1b353930632e6f7267282a5f'
|
2016-05-15 21:47:39 -07:00
|
|
|
+ '5e294f7665726c6179404f7261636c65103b1a010c';
|
2017-07-27 09:27:00 -07:00
|
|
|
const decoded = Script.fromRaw(hex, 'hex');
|
2016-05-15 21:47:39 -07:00
|
|
|
assert(decoded.isNulldata());
|
2016-03-14 20:33:15 -07:00
|
|
|
});
|
2015-12-09 14:35:23 -08:00
|
|
|
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should handle if statements correctly', () => {
|
2017-08-01 17:46:53 -07:00
|
|
|
{
|
2017-08-21 04:32:06 -07:00
|
|
|
const input = new Script([
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromInt(2)
|
|
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(2),
|
|
|
|
|
Opcode.fromSymbol('equal'),
|
|
|
|
|
Opcode.fromSymbol('if'),
|
|
|
|
|
Opcode.fromInt(3),
|
|
|
|
|
Opcode.fromSymbol('else'),
|
|
|
|
|
Opcode.fromInt(4),
|
|
|
|
|
Opcode.fromSymbol('endif'),
|
|
|
|
|
Opcode.fromInt(5)
|
2017-08-01 17:46:53 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const stack = new Stack();
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
input.execute(stack);
|
2017-08-10 09:41:01 -07:00
|
|
|
output.execute(stack);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
assert.deepEqual(stack.items, [[1], [3], [5]]);
|
|
|
|
|
}
|
2015-12-09 14:35:23 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
{
|
2017-08-21 04:32:06 -07:00
|
|
|
const input = new Script([
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromInt(2)
|
|
|
|
|
]);
|
2017-08-10 11:17:10 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(9),
|
|
|
|
|
Opcode.fromSymbol('equal'),
|
|
|
|
|
Opcode.fromSymbol('if'),
|
|
|
|
|
Opcode.fromInt(3),
|
|
|
|
|
Opcode.fromSymbol('else'),
|
|
|
|
|
Opcode.fromInt(4),
|
|
|
|
|
Opcode.fromSymbol('endif'),
|
|
|
|
|
Opcode.fromInt(5)
|
2017-08-01 17:46:53 -07:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const stack = new Stack();
|
2017-08-10 09:41:01 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
input.execute(stack);
|
2017-08-10 09:41:01 -07:00
|
|
|
output.execute(stack);
|
2017-08-01 17:46:53 -07:00
|
|
|
|
|
|
|
|
assert.deepEqual(stack.items, [[1], [4], [5]]);
|
|
|
|
|
}
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
{
|
2017-08-21 04:32:06 -07:00
|
|
|
const input = new Script([
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromInt(2)
|
|
|
|
|
]);
|
2017-08-10 11:17:10 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(2),
|
|
|
|
|
Opcode.fromSymbol('equal'),
|
|
|
|
|
Opcode.fromSymbol('if'),
|
|
|
|
|
Opcode.fromInt(3),
|
|
|
|
|
Opcode.fromSymbol('endif'),
|
|
|
|
|
Opcode.fromInt(5)
|
2017-08-01 17:46:53 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const stack = new Stack();
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
input.execute(stack);
|
2017-08-10 09:41:01 -07:00
|
|
|
output.execute(stack);
|
2015-12-09 14:35:23 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
assert.deepEqual(stack.items, [[1], [3], [5]]);
|
|
|
|
|
}
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
{
|
2017-08-21 04:32:06 -07:00
|
|
|
const input = new Script([
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromInt(2)
|
|
|
|
|
]);
|
2017-08-10 11:17:10 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(9),
|
|
|
|
|
Opcode.fromSymbol('equal'),
|
|
|
|
|
Opcode.fromSymbol('if'),
|
|
|
|
|
Opcode.fromInt(3),
|
|
|
|
|
Opcode.fromSymbol('endif'),
|
|
|
|
|
Opcode.fromInt(5)
|
2017-08-01 17:46:53 -07:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const stack = new Stack();
|
2017-08-10 09:41:01 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
input.execute(stack);
|
2017-08-10 09:41:01 -07:00
|
|
|
output.execute(stack);
|
2017-08-01 17:46:53 -07:00
|
|
|
|
|
|
|
|
assert.deepEqual(stack.items, [[1], [5]]);
|
|
|
|
|
}
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
{
|
2017-08-21 04:32:06 -07:00
|
|
|
const input = new Script([
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromInt(2)
|
|
|
|
|
]);
|
2017-08-10 11:17:10 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(9),
|
|
|
|
|
Opcode.fromSymbol('equal'),
|
|
|
|
|
Opcode.fromSymbol('notif'),
|
|
|
|
|
Opcode.fromInt(3),
|
|
|
|
|
Opcode.fromSymbol('endif'),
|
|
|
|
|
Opcode.fromInt(5)
|
2017-08-01 17:46:53 -07:00
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
const stack = new Stack();
|
2017-08-10 09:41:01 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
input.execute(stack);
|
2017-08-10 09:41:01 -07:00
|
|
|
output.execute(stack);
|
2017-08-01 17:46:53 -07:00
|
|
|
|
|
|
|
|
assert.deepEqual(stack.items, [[1], [3], [5]]);
|
|
|
|
|
}
|
2016-03-14 20:33:15 -07:00
|
|
|
});
|
2016-04-19 01:30:12 -07:00
|
|
|
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should handle CScriptNums correctly', () => {
|
2017-07-27 14:51:55 -07:00
|
|
|
const input = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromString('ffffff7f', 'hex'),
|
|
|
|
|
Opcode.fromSymbol('negate'),
|
|
|
|
|
Opcode.fromSymbol('dup'),
|
|
|
|
|
Opcode.fromSymbol('add')
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromString('feffffff80', 'hex'),
|
|
|
|
|
Opcode.fromSymbol('equal')
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const stack = new Stack();
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-10 09:41:01 -07:00
|
|
|
input.execute(stack);
|
|
|
|
|
output.execute(stack);
|
|
|
|
|
|
|
|
|
|
assert(isSuccess(stack));
|
2016-04-19 04:25:28 -07:00
|
|
|
});
|
|
|
|
|
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should handle CScriptNums correctly', () => {
|
2017-07-27 14:51:55 -07:00
|
|
|
const input = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(11),
|
|
|
|
|
Opcode.fromInt(10),
|
|
|
|
|
Opcode.fromInt(1),
|
|
|
|
|
Opcode.fromSymbol('add')
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromSymbol('numnotequal'),
|
|
|
|
|
Opcode.fromSymbol('not')
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const stack = new Stack();
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-10 09:41:01 -07:00
|
|
|
input.execute(stack);
|
|
|
|
|
output.execute(stack);
|
|
|
|
|
|
|
|
|
|
assert(isSuccess(stack));
|
2016-04-19 04:25:28 -07:00
|
|
|
});
|
|
|
|
|
|
2017-06-29 20:54:07 -07:00
|
|
|
it('should handle OP_ROLL correctly', () => {
|
2017-07-27 14:51:55 -07:00
|
|
|
const input = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(0x16),
|
|
|
|
|
Opcode.fromInt(0x15),
|
|
|
|
|
Opcode.fromInt(0x14)
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const output = new Script([
|
2017-08-21 04:32:06 -07:00
|
|
|
Opcode.fromInt(0),
|
|
|
|
|
Opcode.fromSymbol('roll'),
|
|
|
|
|
Opcode.fromInt(0x14),
|
|
|
|
|
Opcode.fromSymbol('equalverify'),
|
|
|
|
|
Opcode.fromSymbol('depth'),
|
|
|
|
|
Opcode.fromInt(2),
|
|
|
|
|
Opcode.fromSymbol('equal')
|
2016-04-19 04:25:28 -07:00
|
|
|
]);
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-07-27 14:51:55 -07:00
|
|
|
const stack = new Stack();
|
2016-12-10 07:43:54 -08:00
|
|
|
|
2017-08-10 09:41:01 -07:00
|
|
|
input.execute(stack);
|
|
|
|
|
output.execute(stack);
|
|
|
|
|
|
|
|
|
|
assert(isSuccess(stack));
|
2016-04-19 04:25:28 -07:00
|
|
|
});
|
2016-04-19 01:30:12 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
for (const data of scripts) {
|
2016-04-19 01:30:12 -07:00
|
|
|
if (data.length === 1)
|
2017-08-01 17:46:53 -07:00
|
|
|
continue;
|
2016-04-19 01:30:12 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
const test = parseScriptTest(data);
|
|
|
|
|
const {witness, input, output} = test;
|
2017-08-09 17:45:10 -07:00
|
|
|
const {value, flags} = test;
|
2017-08-01 17:46:53 -07:00
|
|
|
const {expected, comments} = test;
|
2016-06-09 03:38:31 -07:00
|
|
|
|
2017-08-01 17:46:53 -07:00
|
|
|
for (const noCache of [false, true]) {
|
2017-07-27 09:27:00 -07:00
|
|
|
const suffix = noCache ? 'without cache' : 'with cache';
|
2017-08-01 17:46:53 -07:00
|
|
|
|
2017-07-01 06:21:15 -07:00
|
|
|
it(`should handle script test ${suffix}:${comments}`, () => {
|
2016-12-09 03:52:36 -08:00
|
|
|
// Funding transaction.
|
2017-07-27 14:51:55 -07:00
|
|
|
const prev = new TX({
|
2016-04-19 06:45:10 -07:00
|
|
|
version: 1,
|
|
|
|
|
inputs: [{
|
|
|
|
|
prevout: {
|
2017-12-05 03:14:34 -08:00
|
|
|
hash: consensus.NULL_HASH,
|
2016-04-19 06:45:10 -07:00
|
|
|
index: 0xffffffff
|
|
|
|
|
},
|
2017-08-21 04:32:06 -07:00
|
|
|
script: [
|
2017-08-25 15:06:12 -07:00
|
|
|
Opcode.fromInt(0),
|
|
|
|
|
Opcode.fromInt(0)
|
2017-08-21 04:32:06 -07:00
|
|
|
],
|
2017-01-09 22:36:10 -08:00
|
|
|
witness: [],
|
2016-04-19 06:45:10 -07:00
|
|
|
sequence: 0xffffffff
|
|
|
|
|
}],
|
|
|
|
|
outputs: [{
|
|
|
|
|
script: output,
|
2017-08-09 17:45:10 -07:00
|
|
|
value: value
|
2016-04-19 06:45:10 -07:00
|
|
|
}],
|
|
|
|
|
locktime: 0
|
|
|
|
|
});
|
2016-12-09 03:52:36 -08:00
|
|
|
|
|
|
|
|
// Spending transaction.
|
2017-07-27 14:51:55 -07:00
|
|
|
const tx = new TX({
|
2016-04-19 06:45:10 -07:00
|
|
|
version: 1,
|
|
|
|
|
inputs: [{
|
|
|
|
|
prevout: {
|
2016-12-09 03:52:36 -08:00
|
|
|
hash: prev.hash('hex'),
|
2016-04-19 06:45:10 -07:00
|
|
|
index: 0
|
|
|
|
|
},
|
|
|
|
|
script: input,
|
|
|
|
|
witness: witness,
|
|
|
|
|
sequence: 0xffffffff
|
|
|
|
|
}],
|
|
|
|
|
outputs: [{
|
2017-01-09 22:36:10 -08:00
|
|
|
script: [],
|
2017-08-09 17:45:10 -07:00
|
|
|
value: value
|
2016-04-19 06:45:10 -07:00
|
|
|
}],
|
|
|
|
|
locktime: 0
|
|
|
|
|
});
|
2016-12-09 03:52:36 -08:00
|
|
|
|
2016-12-10 14:25:02 -08:00
|
|
|
if (noCache) {
|
2016-12-16 22:02:05 -08:00
|
|
|
prev.refresh();
|
|
|
|
|
tx.refresh();
|
2016-04-19 06:45:10 -07:00
|
|
|
}
|
2016-12-09 03:52:36 -08:00
|
|
|
|
2017-08-10 09:41:01 -07:00
|
|
|
let err;
|
2016-04-19 22:44:54 -07:00
|
|
|
try {
|
2017-08-10 09:41:01 -07:00
|
|
|
Script.verify(input, witness, output, tx, 0, value, flags);
|
2016-04-19 22:44:54 -07:00
|
|
|
} catch (e) {
|
|
|
|
|
err = e;
|
|
|
|
|
}
|
2016-12-09 03:52:36 -08:00
|
|
|
|
2016-04-19 22:44:54 -07:00
|
|
|
if (expected !== 'OK') {
|
2017-08-11 18:25:54 -07:00
|
|
|
assert.typeOf(err, 'error');
|
2017-08-09 15:28:03 -07:00
|
|
|
assert.strictEqual(err.code, expected);
|
2016-04-19 22:44:54 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2016-12-09 03:52:36 -08:00
|
|
|
|
2016-10-02 01:01:16 -07:00
|
|
|
assert.ifError(err);
|
2016-04-19 01:30:12 -07:00
|
|
|
});
|
2017-08-01 17:46:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
2014-05-04 23:24:32 +04:00
|
|
|
});
|