Skip to content

Commit

Permalink
feat(scenarios): support "pushed" and "invalid" properties
Browse files Browse the repository at this point in the history
  • Loading branch information
bitjson committed Jul 21, 2020
1 parent bdc1d67 commit a38544a
Show file tree
Hide file tree
Showing 14 changed files with 408 additions and 169 deletions.
2 changes: 2 additions & 0 deletions .cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@
"plusplus",
"privkey",
"preauthorize",
"preimage",
"preimages",
"prevouts",
"pubkey",
"PUBKEYS",
Expand Down
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"cSpell.userWords": [], // only use words from .cspell.json
// "debug.javascript.usePreview": true
"debug.javascript.usePreview": false,
"deno.enable": false,
"editor.formatOnSave": true,
"editor.semanticHighlighting.enabled": true,
Expand Down
43 changes: 27 additions & 16 deletions src/lib/template/bitauth-authentication-template.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,10 @@
},
"transaction": {
"additionalProperties": false,
"description": "The transaction within which this scenario should be evaluated. This is\nused for script testing and validation.\n\nIf undefined, inherits the default value for each property:\n```json\n{\n \"inputs\": [{ \"unlockingBytecode\": true }],\n \"locktime\": 0,\n \"outputs\": [{ \"lockingBytecode\": \"\" }],\n \"version\": 2\n}\n```\n\nAny `transaction` property which is not set will be inherited from the\nscenario specified by `extends`. when specifying the `inputs` and `outputs`\nproperties, each input and output extends the default values for inputs and\noutputs, respectively.\n\nFor example, an input of `{}` is interpreted as:\n```json\n{\n \"outpointIndex\": 0,\n \"outpointTransactionHash\":\n \"0000000000000000000000000000000000000000000000000000000000000000\",\n \"sequenceNumber\": 0\n}\n```\nAnd an output of `{}` is interpreted as:\n```json\n{\n \"lockingBytecode\": {\n \"script\": true,\n \"overrides\": { \"hdKeys\": { \"addressIndex\": 1 } }\n },\n \"satoshis\": 0\n}\n```",
"description": "The transaction within which this scenario should be evaluated. This is\nused for script testing and validation.\n\nIf undefined, inherits the default value for each property:\n```json\n{\n \"inputs\": [{ \"unlockingBytecode\": null }],\n \"locktime\": 0,\n \"outputs\": [{ \"lockingBytecode\": \"\" }],\n \"version\": 2\n}\n```\n\nAny `transaction` property which is not set will be inherited from the\nscenario specified by `extends`. when specifying the `inputs` and `outputs`\nproperties, each input and output extends the default values for inputs and\noutputs, respectively.\n\nFor example, an input of `{}` is interpreted as:\n```json\n{\n \"outpointIndex\": 0,\n \"outpointTransactionHash\":\n \"0000000000000000000000000000000000000000000000000000000000000000\",\n \"sequenceNumber\": 0\n}\n```\nAnd an output of `{}` is interpreted as:\n```json\n{\n \"lockingBytecode\": {\n \"script\": null,\n \"overrides\": { \"hdKeys\": { \"addressIndex\": 1 } }\n },\n \"satoshis\": 0\n}\n```",
"properties": {
"inputs": {
"description": "The list of inputs to use when generating the transaction context for\nthis scenario.\n\nTo be valid the `inputs` property must have exactly one input with\n`unlockingBytecode` set to `true`. This is the input in which the\nunlocking script under test will be placed. No other inputs may define\n`unlockingBytecode`.\n\nIf undefined, inherits the default scenario `inputs` value:\n`[{ \"unlockingBytecode\": true }]`.",
"description": "The list of inputs to use when generating the transaction context for\nthis scenario.\n\nTo be valid the `inputs` property must have exactly one input with\n`unlockingBytecode` set to `null`. This is the input in which the\nunlocking script under test will be placed.\n\nIf undefined, inherits the default scenario `inputs` value:\n`[{ \"unlockingBytecode\": null }]`.",
"items": {
"$ref": "#/definitions/AuthenticationTemplateScenarioInput"
},
Expand Down Expand Up @@ -329,9 +329,9 @@
"type": "number"
},
"unlockingBytecode": {
"description": "The `unlockingBytecode` value of this input for this scenario. May be\neither a boolean value indicating that this input contains the\n`unlockingBytecode` under test by the scenario, or a hexadecimal-encoded\nbytecode value.\n\nThis defaults to `false`. For a scenario to be valid, this property must be\n`true` for exactly one input in the scenario. If this property is\n`undefined` or `false`, the resulting `unlockingBytecode` is a bytecode\nof length `0` (`0x`).",
"description": "The `unlockingBytecode` value of this input for this scenario. This must be\neither a `null` value indicating that this input contains the\n`unlockingBytecode` under test by the scenarioor a hexadecimal-encoded\nbytecode value.\n\nDefaults to an empty string (`''`). For a scenario to be valid,\n`unlockingBytecode` must be `null` for exactly one input in the scenario.",
"type": [
"boolean",
"null",
"string"
]
}
Expand All @@ -355,18 +355,11 @@
"description": "Scenario data which extends this scenario's top-level data during\nscript compilation.\n\nEach property is extended individually – to modify a property set by\nthe top-level scenario data, the new value must be listed here.\n\nIf undefined, defaults to `{ \"hdKeys\": { \"addressIndex\": 1 } }`."
},
"script": {
"anyOf": [
{
"type": "string"
},
{
"enum": [
true
],
"type": "boolean"
}
],
"description": "The identifier of the script to compile when generating this\n`lockingBytecode`. May also be set to `true`, which represents the\nidentifier of the locking script unlocked by the unlocking script\nunder test.\n\nIf undefined, defaults to `true`."
"description": "The identifier of the script to compile when generating this\n`lockingBytecode`. May also be set to `null`, which represents the\nidentifier of the locking script unlocked by the unlocking script\nunder test.\n\nIf undefined, defaults to `null`.",
"type": [
"string",
"null"
]
}
},
"type": "object"
Expand Down Expand Up @@ -442,6 +435,13 @@
},
"type": "array"
},
"invalid": {
"description": "A list of the scenario identifiers which – when used to compile this\ntest and the script it tests – result in a compilation error. The `setup`\nscript is used in place of an unlocking script, and the concatenation of\nthe script under test and the `check` script are used in place of a locking\nscript.\n\nThese scenarios can be used to test this script in development and review.",
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"description": "A single-line, Title Case, human-readable name for this test (for use in\nuser interfaces).",
"type": "string"
Expand Down Expand Up @@ -470,6 +470,10 @@
"description": "A single-line, human-readable name for this script (for use in user\ninterfaces).",
"type": "string"
},
"pushed": {
"description": "If set to `true`, indicates that this script should be wrapped in a push\nstatement for testing.\n\nThis is useful for scripts which serve as \"bytecode templates\" – e.g.\nformatted messages or signature preimages. These scripts are typically not\nevaluated as bytecode but appear within push statements elsewhere in the\ntemplate.\n\nDefaults to `false`.",
"type": "boolean"
},
"script": {
"description": "The script definition in BTL (Bitauth Templating Language).",
"type": "string"
Expand Down Expand Up @@ -506,6 +510,13 @@
},
"type": "array"
},
"invalid": {
"description": "A list of the scenario identifiers which – when used to compile this\nunlocking script and the script it unlocks – result in a compilation error.\n\nThese scenarios can be used to test this script in development and review.",
"items": {
"type": "string"
},
"type": "array"
},
"name": {
"description": "A single-line, human-readable name for this script (for use in user\ninterfaces).",
"type": "string"
Expand Down
5 changes: 1 addition & 4 deletions src/lib/template/compiler-defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ export enum CompilerDefaults {
*/
defaultScenarioInputSequenceNumber = 0,
/**
* The default `unlockingBytecode` of inputs in scenarios. This is also the
* value used in the `Scenario.program.spendingTransaction` for the
* `unlockingBytecode` of the input under test (also identified by
* `Scenario.program.inputIndex`).
* The default `unlockingBytecode` of untested inputs in scenarios.
*/
defaultScenarioInputUnlockingBytecodeHex = '',
/**
Expand Down
12 changes: 12 additions & 0 deletions src/lib/template/compiler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,11 @@ test('authenticationTemplateToCompilationEnvironmentVirtualizedTests', (t) => {
{ check: '<4> OP_EQUAL', setup: '<2>' },
],
},
message: {
pushed: true,
script: '"abc"',
tests: [{ check: '<"abc"> OP_EQUAL' }],
},
push_three: {
script: '<3>',
tests: [{ check: '<3> OP_EQUAL' }],
Expand All @@ -136,17 +141,22 @@ test('authenticationTemplateToCompilationEnvironmentVirtualizedTests', (t) => {
scripts: {
__virtualized_test_check_add_two_0: '<3> OP_EQUAL',
__virtualized_test_check_add_two_1: '<4> OP_EQUAL',
__virtualized_test_check_message_0: '<"abc"> OP_EQUAL',
__virtualized_test_check_push_three_0: '<3> OP_EQUAL',
__virtualized_test_lock_add_two_0:
'add_two __virtualized_test_check_add_two_0',
__virtualized_test_lock_add_two_1:
'add_two __virtualized_test_check_add_two_1',
__virtualized_test_lock_message_0:
'<message> __virtualized_test_check_message_0',
__virtualized_test_lock_push_three_0:
'push_three __virtualized_test_check_push_three_0',
__virtualized_test_unlock_add_two_0: '<1>',
__virtualized_test_unlock_add_two_1: '<2>',
__virtualized_test_unlock_message_0: '',
__virtualized_test_unlock_push_three_0: '',
add_two: '<2> OP_ADD',
message: '"abc"',
push_three: '<3>',
unrelated: '<1>',
},
Expand All @@ -156,6 +166,8 @@ test('authenticationTemplateToCompilationEnvironmentVirtualizedTests', (t) => {
'__virtualized_test_lock_add_two_0',
__virtualized_test_unlock_add_two_1:
'__virtualized_test_lock_add_two_1',
__virtualized_test_unlock_message_0:
'__virtualized_test_lock_message_0',
__virtualized_test_unlock_push_three_0:
'__virtualized_test_lock_push_three_0',
},
Expand Down
5 changes: 4 additions & 1 deletion src/lib/template/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,17 @@ export const authenticationTemplateToCompilationEnvironmentVirtualizedTests = (
...all,
...script.tests.reduce<typeof template.scripts>(
(tests, test, index) => {
const pushTestedScript = script.pushed === true;
const checkScriptId = `${CompilerDefaults.virtualizedTestCheckScriptPrefix}${scriptId}_${index}`;
const virtualizedLockingScriptId = `${CompilerDefaults.virtualizedTestLockingScriptPrefix}${scriptId}_${index}`;
const virtualizedUnlockingScriptId = `${CompilerDefaults.virtualizedTestUnlockingScriptPrefix}${scriptId}_${index}`;
return {
...tests,
[checkScriptId]: { script: test.check },
[virtualizedLockingScriptId]: {
script: `${scriptId} ${checkScriptId}`,
script: pushTestedScript
? `<${scriptId}> ${checkScriptId}`
: `${scriptId} ${checkScriptId}`,
},
[virtualizedUnlockingScriptId]: {
script: test.setup ?? '',
Expand Down
37 changes: 20 additions & 17 deletions src/lib/template/scenarios.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ test('generateDefaultScenarioDefinition: empty', (t) => {
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand Down Expand Up @@ -146,7 +146,7 @@ test('extendScenarioDefinition: default', (t) => {
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand All @@ -169,7 +169,7 @@ test('extendScenarioDefinition: complex extend', (t) => {
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand Down Expand Up @@ -230,7 +230,7 @@ test('extendScenarioDefinition: complex extend', (t) => {
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand Down Expand Up @@ -354,7 +354,7 @@ test('generateDefaultScenarioDefinition: authenticationTemplateP2pkhNonHd', (t)
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand Down Expand Up @@ -399,7 +399,7 @@ test('generateDefaultScenarioDefinition: authenticationTemplateP2pkh', async (t)
transaction: {
inputs: [
{
unlockingBytecode: true,
unlockingBytecode: null,
},
],
locktime: 0,
Expand Down Expand Up @@ -564,7 +564,7 @@ test(
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 0,
Expand Down Expand Up @@ -670,7 +670,7 @@ test(
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 0,
Expand Down Expand Up @@ -724,7 +724,7 @@ test(
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 0,
Expand All @@ -750,7 +750,7 @@ test(
a: { transaction: { inputs: [{}, {}] } },
},
},
'Cannot generate scenario "a": the specific input under test in this scenario is ambiguous – "transaction.inputs" must include exactly one input which has "unlockingBytecode" set to "true".'
'Cannot generate scenario "a": the specific input under test in this scenario is ambiguous – "transaction.inputs" must include exactly one input which has "unlockingBytecode" set to "null".'
);

test(
Expand Down Expand Up @@ -882,7 +882,7 @@ test(
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 0,
Expand Down Expand Up @@ -920,7 +920,7 @@ test(
sequenceNumber: 1,
unlockingBytecode: 'beef',
},
{ unlockingBytecode: true },
{ unlockingBytecode: null },
],
locktime: 4294967295,
outputs: [
Expand Down Expand Up @@ -968,7 +968,7 @@ test(
},
},
program: {
inputIndex: 0,
inputIndex: 1,
sourceOutput: {
satoshis: hexToBin('0000000000000000'),
},
Expand All @@ -988,7 +988,7 @@ test(
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 4294967295,
Expand Down Expand Up @@ -1058,6 +1058,9 @@ test('generateScenario: cash-channels – after_payment_time', async (t) => {
},
currentBlockHeight: 2,
currentBlockTime: 1231469665,
hdKeys: {
addressIndex: 0,
},
keys: {
privateKeys: {
owner: hexToBin(
Expand Down Expand Up @@ -1085,16 +1088,16 @@ test('generateScenario: cash-channels – after_payment_time', async (t) => {
'0000000000000000000000000000000000000000000000000000000000000000'
),
sequenceNumber: 0,
unlockingBytecode: hexToBin(''),
unlockingBytecode: undefined,
},
],
locktime: 1580515200,
outputs: [
{
lockingBytecode: hexToBin(
'210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817987c63766b56795f795779765c79a26958805779588057795880577958807e7e766b7e7e7e7cbbb16d6d5879020200886c537958807e7c6c2102e493dbf1c10d80f3581e4904930b1404cc6c13900ee0758474fa94abe8c4cd13766b7ea9882102f9308a019258c31049344f85f89d5229b531c845836f99b08601f113bce036f9bb57795779815193528057797e7ea9011702a9147b01877e7e7e5579817b9458807c7e7c7eaa7c7e7e7e7e7e7e7ea86c7653797bad7b01407f757b7bba67ac68'
'a9149a97dc2531b9b9af6319aab57ea369284289998987'
),
satoshis: hexToBin('0000000000000000'),
satoshis: hexToBin('1027000000000000'),
},
],
version: 2,
Expand Down
Loading

0 comments on commit a38544a

Please sign in to comment.