diff --git a/src/lib/auth/templates/language/compile.spec.ts b/src/lib/auth/templates/language/compile.spec.ts index 81dafce7..69f02526 100644 --- a/src/lib/auth/templates/language/compile.spec.ts +++ b/src/lib/auth/templates/language/compile.spec.ts @@ -1,4 +1,4 @@ -// tslint:disable:no-expression-statement no-magic-numbers +// tslint:disable:no-expression-statement no-magic-numbers max-file-line-count import test from 'ava'; import { hexToBin } from '../../../utils/hex'; @@ -310,6 +310,7 @@ test('compileScript: 0x51', t => { }, resolve: [ { + literalType: 'HexLiteral', range: { endColumn: 5, endLineNumber: 1, @@ -437,6 +438,7 @@ test('compileScript: <1>', t => { type: 'push', value: [ { + literalType: 'BigIntLiteral', range: { endColumn: 3, endLineNumber: 1, @@ -566,6 +568,7 @@ test('compileScript: <0xabcdef>', t => { type: 'push', value: [ { + literalType: 'HexLiteral', range: { endColumn: 10, endLineNumber: 1, @@ -695,6 +698,7 @@ test('compileScript: <"abc 👍">', t => { type: 'push', value: [ { + literalType: 'UTF8Literal', range: { endColumn: 10, endLineNumber: 1, @@ -884,6 +888,7 @@ test('compileScript: OP_1 OP_2 OP_ADD', t => { }, resolve: [ { + opcode: 'OP_1', range: { endColumn: 5, endLineNumber: 1, @@ -894,6 +899,7 @@ test('compileScript: OP_1 OP_2 OP_ADD', t => { value: Uint8Array.of(0x51) }, { + opcode: 'OP_2', range: { endColumn: 10, endLineNumber: 1, @@ -904,6 +910,7 @@ test('compileScript: OP_1 OP_2 OP_ADD', t => { value: Uint8Array.of(0x52) }, { + opcode: 'OP_ADD', range: { endColumn: 17, endLineNumber: 1, @@ -918,3 +925,162 @@ test('compileScript: OP_1 OP_2 OP_ADD', t => { } ); }); + +test('compileScript: variable and script inclusion', t => { + const comp = compileScript( + 't', + { + addressData: { + var_OP_2: Uint8Array.of(0x52) + } + }, + { + opcodes: { + OP_1: Uint8Array.of(0x51), + OP_ADD: Uint8Array.of(0x93) + }, + scripts: { script_OP_1: 'OP_1', t: 'script_OP_1 var_OP_2 OP_ADD' }, + variables: { + var_OP_2: { + description: 'Gets added to OP_1', + name: 'OP_2 as a variable', + type: 'AddressData' + } + } + } + ); + t.deepEqual(comp, { + bytecode: Uint8Array.of(0x51, 0x52, 0x93), + parse: { + end: { + column: 28, + line: 1, + offset: 27 + }, + name: 'Script', + start: { + column: 1, + line: 1, + offset: 0 + }, + value: [ + { + end: { + column: 12, + line: 1, + offset: 11 + }, + name: 'Identifier', + start: { + column: 1, + line: 1, + offset: 0 + }, + value: 'script_OP_1' + }, + { + end: { + column: 21, + line: 1, + offset: 20 + }, + name: 'Identifier', + start: { + column: 13, + line: 1, + offset: 12 + }, + value: 'var_OP_2' + }, + { + end: { + column: 28, + line: 1, + offset: 27 + }, + name: 'Identifier', + start: { + column: 22, + line: 1, + offset: 21 + }, + value: 'OP_ADD' + } + ] + }, + reduce: { + bytecode: Uint8Array.of(0x51, 0x52, 0x93), + range: { + endColumn: 28, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + source: [ + { + bytecode: Uint8Array.of(0x51), + range: { + endColumn: 12, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + } + }, + { + bytecode: Uint8Array.of(0x52), + range: { + endColumn: 21, + endLineNumber: 1, + startColumn: 13, + startLineNumber: 1 + } + }, + { + bytecode: Uint8Array.of(0x93), + range: { + endColumn: 28, + endLineNumber: 1, + startColumn: 22, + startLineNumber: 1 + } + } + ] + }, + resolve: [ + { + range: { + endColumn: 12, + endLineNumber: 1, + startColumn: 1, + startLineNumber: 1 + }, + script: 'script_OP_1', + type: 'bytecode', + value: Uint8Array.of(0x51) + }, + { + range: { + endColumn: 21, + endLineNumber: 1, + startColumn: 13, + startLineNumber: 1 + }, + type: 'bytecode', + value: Uint8Array.of(0x52), + variable: 'var_OP_2' + }, + { + opcode: 'OP_ADD', + range: { + endColumn: 28, + endLineNumber: 1, + startColumn: 22, + startLineNumber: 1 + }, + type: 'bytecode', + value: Uint8Array.of(0x93) + } + ], + success: true + }); +}); diff --git a/src/lib/auth/templates/language/compiler.spec.ts b/src/lib/auth/templates/language/compiler.spec.ts index dea8a163..6f547408 100644 --- a/src/lib/auth/templates/language/compiler.spec.ts +++ b/src/lib/auth/templates/language/compiler.spec.ts @@ -1,4 +1,4 @@ -// tslint:disable:no-expression-statement no-magic-numbers +// tslint:disable:no-expression-statement no-magic-numbers max-file-line-count import test from 'ava'; import { hexToBin } from '../../../utils/utils'; @@ -495,6 +495,7 @@ test('createCompilerBCH: debug', async t => { }, resolve: [ { + opcode: 'OP_DUP', range: { endColumn: 7, endLineNumber: 1, @@ -505,6 +506,7 @@ test('createCompilerBCH: debug', async t => { value: Uint8Array.of(0x76) }, { + opcode: 'OP_HASH160', range: { endColumn: 18, endLineNumber: 1, @@ -557,6 +559,7 @@ test('createCompilerBCH: debug', async t => { ] }, { + opcode: 'OP_HASH160', range: { endColumn: 47, endLineNumber: 1, @@ -571,6 +574,7 @@ test('createCompilerBCH: debug', async t => { ] }, { + opcode: 'OP_EQUALVERIFY', range: { endColumn: 64, endLineNumber: 1, @@ -581,6 +585,7 @@ test('createCompilerBCH: debug', async t => { value: Uint8Array.of(0x88) }, { + opcode: 'OP_CHECKSIG', range: { endColumn: 76, endLineNumber: 1, diff --git a/src/lib/auth/templates/language/resolve.ts b/src/lib/auth/templates/language/resolve.ts index b041dded..2901201f 100644 --- a/src/lib/auth/templates/language/resolve.ts +++ b/src/lib/auth/templates/language/resolve.ts @@ -39,12 +39,36 @@ interface ResolvedSegmentEvaluation extends ResolvedSegmentBase { value: T; } -interface ResolvedSegmentBytecode extends ResolvedSegmentBase { +interface ResolvedSegmentVariableBytecode extends ResolvedSegmentBase { type: 'bytecode'; value: Uint8Array; - variable?: string; + variable: string; } +interface ResolvedSegmentScriptBytecode extends ResolvedSegmentBase { + script: string; + type: 'bytecode'; + value: Uint8Array; +} + +interface ResolvedSegmentOpcodeBytecode extends ResolvedSegmentBase { + opcode: string; + type: 'bytecode'; + value: Uint8Array; +} + +interface ResolvedSegmentLiteralBytecode extends ResolvedSegmentBase { + literalType: 'BigIntLiteral' | 'HexLiteral' | 'UTF8Literal'; + type: 'bytecode'; + value: Uint8Array; +} + +type ResolvedSegmentBytecode = + | ResolvedSegmentLiteralBytecode + | ResolvedSegmentOpcodeBytecode + | ResolvedSegmentScriptBytecode + | ResolvedSegmentVariableBytecode; + interface ResolvedSegmentComment extends ResolvedSegmentBase { type: 'comment'; value: string; @@ -67,8 +91,7 @@ export interface ResolvedScript extends Array {} export enum IdentifierResolutionType { opcode = 'opcode', variable = 'variable', - script = 'script', - unknown = 'unknown' + script = 'script' } export type IdentifierResolutionFunction = ( @@ -86,28 +109,33 @@ export const resolveScriptSegment = ( resolveIdentifiers: IdentifierResolutionFunction ): ResolvedScript => { // tslint:disable-next-line: cyclomatic-complexity - const resolved = segment.value.map(child => { + const resolved = segment.value.map(child => { const range = pluckRange(child); switch (child.name) { case 'Identifier': const identifier = child.value; const result = resolveIdentifiers(identifier); - return result.status + const ret = result.status ? { range, type: 'bytecode' as 'bytecode', value: result.bytecode, - ...(result.type === IdentifierResolutionType.variable + ...(result.type === IdentifierResolutionType.opcode + ? { + opcode: identifier + } + : result.type === IdentifierResolutionType.variable ? { variable: identifier } - : undefined) + : { script: identifier }) } : { range, type: 'error' as 'error', value: result.error }; + return ret; case 'Push': return { range, @@ -122,6 +150,7 @@ export const resolveScriptSegment = ( }; case 'BigIntLiteral': return { + literalType: 'BigIntLiteral' as 'BigIntLiteral', range, type: 'bytecode' as 'bytecode', value: bigIntToScriptNumber(child.value) @@ -129,6 +158,7 @@ export const resolveScriptSegment = ( case 'HexLiteral': return child.value.length % Constants.hexByte === 0 ? { + literalType: 'HexLiteral' as 'HexLiteral', range, type: 'bytecode' as 'bytecode', value: hexToBin(child.value) @@ -140,6 +170,7 @@ export const resolveScriptSegment = ( }; case 'UTF8Literal': return { + literalType: 'UTF8Literal' as 'UTF8Literal', range, type: 'bytecode' as 'bytecode', value: utf8ToBin(child.value)