Files
trezor-suite/packages/utxo-lib/tests/script.test.ts

156 lines
5.3 KiB
TypeScript

import minimalData from 'minimaldata';
import * as bscript from '../src/script';
import { fixtures } from './__fixtures__/script';
import { templates } from './__fixtures__/templates';
describe('script', () => {
// TODO
describe('isCanonicalPubKey', () => {
it('rejects if not provided a Buffer', () => {
// @ts-expect-error
expect(bscript.isCanonicalPubKey(0)).toBe(false);
});
// eslint-disable-next-line jest/no-commented-out-tests
// it('rejects smaller than 33', () => {
// for (let i = 0; i < 33; i++) {
// expect(bscript.isCanonicalPubKey(Buffer.from('', i))).toBe(false);
// }
// });
});
// eslint-disable-next-line jest/no-commented-out-tests
// describe.skip('isCanonicalSignature', () => {});
describe('fromASM/toASM', () => {
fixtures.valid.forEach(f => {
it(`encodes/decodes ${f.asm}`, () => {
const script = bscript.fromASM(f.asm);
expect(bscript.toASM(script)).toEqual(f.asm);
});
});
fixtures.invalid.fromASM.forEach(f => {
it(`throws ${f.description}`, () => {
expect(() => bscript.fromASM(f.script)).toThrow(f.description);
});
});
});
describe('fromASM/toASM (templates)', () => {
templates.valid.forEach(f => {
if (f.inputHex) {
const ih = bscript.toASM(Buffer.from(f.inputHex, 'hex'));
it(`encodes/decodes ${ih}`, () => {
const script = bscript.fromASM(f.input);
expect(script.toString('hex')).toEqual(f.inputHex);
expect(bscript.toASM(script)).toEqual(f.input);
});
}
if (f.outputHex) {
it(`encodes/decodes ${f.output}`, () => {
const script = bscript.fromASM(f.output);
expect(script.toString('hex')).toEqual(f.outputHex);
expect(bscript.toASM(script)).toEqual(f.output);
});
}
});
});
describe('isPushOnly', () => {
fixtures.valid.forEach(f => {
it(`returns ${!!f.stack} for ${f.asm}`, () => {
const script = bscript.fromASM(f.asm);
const chunks = bscript.decompile(script);
expect(bscript.isPushOnly(chunks)).toEqual(!!f.stack);
});
});
});
describe('toStack', () => {
fixtures.valid.forEach(f => {
it(`returns ${!!f.stack} for ${f.asm}`, () => {
if (!f.stack || !f.asm) return;
const script = bscript.fromASM(f.asm);
const stack = bscript.toStack(script);
expect(stack.map(x => x.toString('hex'))).toEqual(f.stack);
expect(bscript.toASM(bscript.compile(stack))).toEqual(f.asm);
});
});
});
describe('compile (via fromASM)', () => {
fixtures.valid.forEach(f => {
it(`compiles ${f.asm}`, () => {
const scriptSig = bscript.fromASM(f.asm);
expect(scriptSig.toString('hex')).toEqual(f.script);
if (f.nonstandard) {
const scriptSigNS = bscript.fromASM(f.nonstandard.scriptSig);
expect(scriptSigNS.toString('hex')).toEqual(f.script);
}
});
});
});
describe('decompile', () => {
fixtures.valid.forEach(f => {
it(`decompiles ${f.asm}`, () => {
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
expect(bscript.compile(chunks).toString('hex')).toEqual(f.script);
expect(bscript.toASM(chunks)).toEqual(f.asm);
if (f.nonstandard) {
const chunksNS = bscript.decompile(
Buffer.from(f.nonstandard.scriptSigHex, 'hex'),
);
expect(bscript.compile(chunksNS).toString('hex')).toEqual(f.script);
// toASM converts verbatim, only `compile` transforms the script to a minimalpush compliant script
expect(bscript.toASM(chunksNS)).toEqual(f.nonstandard.scriptSig);
}
});
});
fixtures.invalid.decompile.forEach(f => {
it(`decompiles ${f.script} to [] because of "${f.description}"`, () => {
const chunks = bscript.decompile(Buffer.from(f.script, 'hex'));
expect(chunks.length).toBe(0);
});
});
});
describe('SCRIPT_VERIFY_MINIMALDATA policy', () => {
fixtures.valid.forEach(f => {
it(`compliant for scriptSig ${f.asm}`, () => {
const script = Buffer.from(f.script, 'hex');
expect(minimalData(script)).toBe(true);
});
});
function testEncodingForSize(num: number) {
it(`compliant for data PUSH of length ${num}`, () => {
const buffer = Buffer.alloc(num);
const script = bscript.compile([buffer]);
expect(minimalData(script)).toBe(true);
});
}
for (let i = 0; i < 520; ++i) {
testEncodingForSize(i);
}
});
});