2019-09-07 06:42:03 +02:00
|
|
|
import * as assert from 'assert';
|
|
|
|
import { describe, it } from 'mocha';
|
|
|
|
import * as bscript from '../src/script';
|
|
|
|
import * as fixtures from './fixtures/script.json';
|
|
|
|
import * as fixtures2 from './fixtures/templates.json';
|
|
|
|
const minimalData = require('minimaldata');
|
2014-06-12 13:14:22 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('script', () => {
|
2014-11-28 03:49:43 +01:00
|
|
|
// TODO
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('isCanonicalPubKey', () => {
|
|
|
|
it('rejects if not provided a Buffer', () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(false, bscript.isCanonicalPubKey(0 as any));
|
|
|
|
});
|
2019-04-09 08:09:50 +02:00
|
|
|
it('rejects smaller than 33', () => {
|
2019-09-12 10:35:08 +02:00
|
|
|
for (let i = 0; i < 33; i++) {
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(
|
|
|
|
false,
|
|
|
|
bscript.isCanonicalPubKey(Buffer.allocUnsafe(i)),
|
|
|
|
);
|
2016-11-01 16:06:01 +01:00
|
|
|
}
|
2019-09-07 06:42:03 +02:00
|
|
|
});
|
|
|
|
});
|
2019-09-12 10:35:08 +02:00
|
|
|
describe.skip('isCanonicalScriptSignature', () => {
|
|
|
|
assert.ok(true);
|
|
|
|
});
|
2014-11-28 03:49:43 +01:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('fromASM/toASM', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
|
|
|
it('encodes/decodes ' + f.asm, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
const script = bscript.fromASM(f.asm);
|
|
|
|
assert.strictEqual(bscript.toASM(script), f.asm);
|
|
|
|
});
|
|
|
|
});
|
2016-12-17 04:29:42 +01:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
fixtures.invalid.fromASM.forEach(f => {
|
|
|
|
it('throws ' + f.description, () => {
|
|
|
|
assert.throws(() => {
|
2019-09-07 06:42:03 +02:00
|
|
|
bscript.fromASM(f.script);
|
|
|
|
}, new RegExp(f.description));
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('fromASM/toASM (templates)', () => {
|
|
|
|
fixtures2.valid.forEach(f => {
|
2017-09-22 03:33:32 +02:00
|
|
|
if (f.inputHex) {
|
2019-09-07 06:42:03 +02:00
|
|
|
const ih = bscript.toASM(Buffer.from(f.inputHex, 'hex'));
|
2017-09-22 03:33:32 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
it('encodes/decodes ' + ih, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
const script = bscript.fromASM(f.input);
|
|
|
|
assert.strictEqual(script.toString('hex'), f.inputHex);
|
|
|
|
assert.strictEqual(bscript.toASM(script), f.input);
|
|
|
|
});
|
2017-09-22 03:33:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (f.outputHex) {
|
2019-04-09 08:09:50 +02:00
|
|
|
it('encodes/decodes ' + f.output, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
const script = bscript.fromASM(f.output);
|
|
|
|
assert.strictEqual(script.toString('hex'), f.outputHex);
|
|
|
|
assert.strictEqual(bscript.toASM(script), f.output);
|
|
|
|
});
|
2017-09-22 03:33:32 +02:00
|
|
|
}
|
2019-09-07 06:42:03 +02:00
|
|
|
});
|
|
|
|
});
|
2017-09-22 03:33:32 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('isPushOnly', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
|
|
|
it('returns ' + !!f.stack + ' for ' + f.asm, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
const script = bscript.fromASM(f.asm);
|
|
|
|
const chunks = bscript.decompile(script);
|
2016-12-14 05:52:15 +01:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(bscript.isPushOnly(chunks!), !!f.stack);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2016-11-14 01:17:27 +01:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('toStack', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
|
|
|
it('returns ' + !!f.stack + ' for ' + f.asm, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
if (!f.stack || !f.asm) return;
|
|
|
|
|
|
|
|
const script = bscript.fromASM(f.asm);
|
|
|
|
|
|
|
|
const stack = bscript.toStack(script);
|
|
|
|
assert.deepStrictEqual(
|
|
|
|
stack.map(x => {
|
|
|
|
return x.toString('hex');
|
|
|
|
}),
|
|
|
|
f.stack,
|
|
|
|
);
|
|
|
|
|
|
|
|
assert.strictEqual(
|
|
|
|
bscript.toASM(bscript.compile(stack)),
|
|
|
|
f.asm,
|
|
|
|
'should rebuild same script from stack',
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2016-12-15 00:57:53 +01:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('compile (via fromASM)', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
2019-09-07 06:42:03 +02:00
|
|
|
it('compiles ' + f.asm, () => {
|
|
|
|
const scriptSig = bscript.fromASM(f.asm);
|
2016-09-29 05:48:17 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(scriptSig.toString('hex'), f.script);
|
2016-09-29 05:48:17 +02:00
|
|
|
|
2016-12-15 01:12:26 +01:00
|
|
|
if (f.nonstandard) {
|
2019-09-07 06:42:03 +02:00
|
|
|
const scriptSigNS = bscript.fromASM(f.nonstandard.scriptSig);
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(scriptSigNS.toString('hex'), f.script);
|
2016-12-15 01:12:26 +01:00
|
|
|
}
|
2019-09-07 06:42:03 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('decompile', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
|
|
|
it('decompiles ' + f.asm, () => {
|
2019-09-07 06:42:03 +02:00
|
|
|
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(bscript.compile(chunks!).toString('hex'), f.script);
|
|
|
|
assert.strictEqual(bscript.toASM(chunks!), f.asm);
|
2016-09-29 05:48:17 +02:00
|
|
|
|
2016-12-15 01:12:26 +01:00
|
|
|
if (f.nonstandard) {
|
2019-09-07 06:42:03 +02:00
|
|
|
const chunksNS = bscript.decompile(
|
|
|
|
Buffer.from(f.nonstandard.scriptSigHex, 'hex'),
|
|
|
|
);
|
2016-09-29 05:48:17 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(
|
|
|
|
bscript.compile(chunksNS!).toString('hex'),
|
|
|
|
f.script,
|
|
|
|
);
|
2016-09-29 05:48:17 +02:00
|
|
|
|
2016-12-15 01:12:26 +01:00
|
|
|
// toASM converts verbatim, only `compile` transforms the script to a minimalpush compliant script
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(bscript.toASM(chunksNS!), f.nonstandard.scriptSig);
|
2016-12-15 01:12:26 +01:00
|
|
|
}
|
2019-09-07 06:42:03 +02:00
|
|
|
});
|
|
|
|
});
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
fixtures.invalid.decompile.forEach(f => {
|
2019-09-07 06:42:03 +02:00
|
|
|
it(
|
|
|
|
'fails to decompile ' + f.script + ', because "' + f.description + '"',
|
|
|
|
() => {
|
|
|
|
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert.strictEqual(chunks, null);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
});
|
|
|
|
});
|
2015-08-14 03:16:17 +02:00
|
|
|
|
2019-04-09 08:09:50 +02:00
|
|
|
describe('SCRIPT_VERIFY_MINIMALDATA policy', () => {
|
|
|
|
fixtures.valid.forEach(f => {
|
2019-09-07 06:42:03 +02:00
|
|
|
it('compliant for scriptSig ' + f.asm, () => {
|
|
|
|
const script = Buffer.from(f.script, 'hex');
|
2016-08-31 07:21:36 +02:00
|
|
|
|
2019-09-07 06:42:03 +02:00
|
|
|
assert(minimalData(script));
|
|
|
|
});
|
|
|
|
});
|
2016-08-31 07:21:36 +02:00
|
|
|
|
2019-09-12 10:35:08 +02:00
|
|
|
function testEncodingForSize(num: number): void {
|
|
|
|
it('compliant for data PUSH of length ' + num, () => {
|
|
|
|
const buffer = Buffer.alloc(num);
|
2019-09-07 06:42:03 +02:00
|
|
|
const script = bscript.compile([buffer]);
|
|
|
|
|
|
|
|
assert(
|
|
|
|
minimalData(script),
|
2019-09-12 10:35:08 +02:00
|
|
|
'Failed for ' + num + ' length script: ' + script.toString('hex'),
|
2019-09-07 06:42:03 +02:00
|
|
|
);
|
|
|
|
});
|
2016-08-31 07:21:36 +02:00
|
|
|
}
|
|
|
|
|
2019-09-12 10:35:08 +02:00
|
|
|
for (let i = 0; i < 520; ++i) {
|
2019-09-07 06:42:03 +02:00
|
|
|
testEncodingForSize(i);
|
2016-08-31 07:21:36 +02:00
|
|
|
}
|
2019-09-07 06:42:03 +02:00
|
|
|
});
|
|
|
|
});
|