diff --git a/src/benchmarks/escrow/gas.json b/src/benchmarks/escrow/gas.json index 4ce0a66131..8e6e546bc8 100644 --- a/src/benchmarks/escrow/gas.json +++ b/src/benchmarks/escrow/gas.json @@ -269,6 +269,16 @@ "approveTon": "6608", "cancelTon": "4509" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "fundingTon": "3987", + "changeCode": "4112", + "approveTon": "6474", + "cancelTon": "4375" + } } ] } diff --git a/src/benchmarks/escrow/size.json b/src/benchmarks/escrow/size.json index b69dc1e81c..1f477bc738 100644 --- a/src/benchmarks/escrow/size.json +++ b/src/benchmarks/escrow/size.json @@ -111,6 +111,14 @@ "cells": "20", "bits": "10919" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "size": { + "cells": "19", + "bits": "10871" + } } ] } diff --git a/src/benchmarks/jetton/gas.json b/src/benchmarks/jetton/gas.json index ed089065f4..dfdb3f8906 100644 --- a/src/benchmarks/jetton/gas.json +++ b/src/benchmarks/jetton/gas.json @@ -395,6 +395,15 @@ "burn": "11602", "discovery": "6117" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "transfer": "14153", + "burn": "11488", + "discovery": "5955" + } } ] } diff --git a/src/benchmarks/jetton/size.json b/src/benchmarks/jetton/size.json index 58cb095539..ea05af3360 100644 --- a/src/benchmarks/jetton/size.json +++ b/src/benchmarks/jetton/size.json @@ -179,6 +179,16 @@ "wallet cells": "15", "wallet bits": "7772" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "size": { + "minter cells": "26", + "minter bits": "13913", + "wallet cells": "14", + "wallet bits": "7716" + } } ] } diff --git a/src/benchmarks/nft/gas.json b/src/benchmarks/nft/gas.json index f079f2c6bf..11259040a4 100644 --- a/src/benchmarks/nft/gas.json +++ b/src/benchmarks/nft/gas.json @@ -189,6 +189,16 @@ "deploy nft": "10335", "batch deploy nft": "654266" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "transfer": "6845", + "get static data": "4290", + "deploy nft": "10149", + "batch deploy nft": "640504" + } } ] } diff --git a/src/benchmarks/nft/size.json b/src/benchmarks/nft/size.json index 7a19fcca05..5d4df21981 100644 --- a/src/benchmarks/nft/size.json +++ b/src/benchmarks/nft/size.json @@ -199,6 +199,16 @@ "item cells": "10", "item bits": "5217" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "size": { + "collection cells": "35", + "collection bits": "19460", + "item cells": "9", + "item bits": "5169" + } } ] } diff --git a/src/benchmarks/notcoin/gas.json b/src/benchmarks/notcoin/gas.json index 1de1f3e584..05d86eeecf 100644 --- a/src/benchmarks/notcoin/gas.json +++ b/src/benchmarks/notcoin/gas.json @@ -107,6 +107,15 @@ "burn": "12027", "discovery": "5818" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "transfer": "15239", + "burn": "11823", + "discovery": "5656" + } } ] } diff --git a/src/benchmarks/notcoin/size.json b/src/benchmarks/notcoin/size.json index 2ed21ef6a0..0862b4e6ae 100644 --- a/src/benchmarks/notcoin/size.json +++ b/src/benchmarks/notcoin/size.json @@ -129,6 +129,16 @@ "wallet cells": "13", "wallet bits": "8020" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "size": { + "minter cells": "29", + "minter bits": "15863", + "wallet cells": "13", + "wallet bits": "7964" + } } ] } diff --git a/src/benchmarks/sbt/gas.json b/src/benchmarks/sbt/gas.json index 56e33496cf..241c031b58 100644 --- a/src/benchmarks/sbt/gas.json +++ b/src/benchmarks/sbt/gas.json @@ -168,6 +168,19 @@ "revoke": "3850", "take excess": "5577" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "deploy": "3986", + "request owner": "4722", + "prove ownership": "4928", + "get static data": "4652", + "destroy": "6163", + "revoke": "3816", + "take excess": "5443" + } } ] } diff --git a/src/benchmarks/sbt/size.json b/src/benchmarks/sbt/size.json index 2024808e94..1951ff9c5a 100644 --- a/src/benchmarks/sbt/size.json +++ b/src/benchmarks/sbt/size.json @@ -101,7 +101,7 @@ "pr": "https://github.com/tact-lang/tact/pull/2993", "size": { "item cells": "17", - "item bits": "9353" + "item bits": "9305" } } ] diff --git a/src/benchmarks/wallet-v4/gas.json b/src/benchmarks/wallet-v4/gas.json index 2c99495571..1846e1e61d 100644 --- a/src/benchmarks/wallet-v4/gas.json +++ b/src/benchmarks/wallet-v4/gas.json @@ -125,6 +125,15 @@ "addPlugin": "7399", "pluginTransfer": "3709" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "externalTransfer": "3383", + "addPlugin": "7083", + "pluginTransfer": "3819" + } } ] } diff --git a/src/benchmarks/wallet-v5/gas.json b/src/benchmarks/wallet-v5/gas.json index 3cf3626264..6e42b95bb8 100644 --- a/src/benchmarks/wallet-v5/gas.json +++ b/src/benchmarks/wallet-v5/gas.json @@ -149,6 +149,16 @@ "internalTransfer": "5724", "extensionTransfer": "4656" } + }, + { + "label": "1.6.13 with preview of deep selector hack", + "pr": null, + "gas": { + "externalTransfer": "4771", + "addExtension": "5434", + "internalTransfer": "5862", + "extensionTransfer": "4794" + } } ] } diff --git a/src/generator/writers/writeContract.ts b/src/generator/writers/writeContract.ts index 9a3e55bf9a..67e5fcf62d 100644 --- a/src/generator/writers/writeContract.ts +++ b/src/generator/writers/writeContract.ts @@ -16,6 +16,7 @@ import { resolveFuncTypeUnpack } from "@/generator/writers/resolveFuncTypeUnpack import { writeValue } from "@/generator/writers/writeExpression"; import { writeGetter, writeStatement } from "@/generator/writers/writeFunction"; import { writeInterfaces } from "@/generator/writers/writeInterfaces"; +import type { ContractReceivers } from "@/generator/writers/writeRouter"; import { groupContractReceivers, writeBouncedRouter, @@ -344,6 +345,335 @@ export function writeInit( }); } +function writeInternalBody( + contract: TypeDescription, + contractReceivers: ContractReceivers, + wCtx: WriterContext, +) { + wCtx.append(`;; Context`); + wCtx.append(`var cs = in_msg_cell.begin_parse();`); + wCtx.append(`cs~skip_bits(2);`); // skip int_msg_info$0 ihr_disabled:Bool + wCtx.append(`var msg_bounceable = cs~load_int(1);`); // bounce:Bool + wCtx.append(`var msg_bounced = cs~load_int(1);`); // bounced:Bool + wCtx.append(`slice msg_sender_addr = cs~load_msg_addr();`); + + if (contract.globalVariables.has("context")) { + wCtx.append( + `__tact_context = (msg_bounceable, msg_sender_addr, msg_value, cs);`, + ); + } + if (contract.globalVariables.has("sender")) { + wCtx.append(`__tact_context_sender = msg_sender_addr;`); + } + if (contract.globalVariables.has("inMsg")) { + wCtx.append(`__tact_in_msg = in_msg;`); + } + + wCtx.append(); + + writeLoadContractVariables(contract, wCtx); + + writeBouncedRouter(contractReceivers.bounced, contract, wCtx); + + writeNonBouncedRouter(contractReceivers.internal, contract, wCtx); +} + +function writeExternalBody( + contract: TypeDescription, + contractReceivers: ContractReceivers, + wCtx: WriterContext, +) { + if (contract.globalVariables.has("inMsg")) { + wCtx.append(`__tact_in_msg = in_msg;`); + } + + writeLoadContractVariables(contract, wCtx); + + writeNonBouncedRouter(contractReceivers.external, contract, wCtx); +} + +function writeContractReseiversSelectorHack( + contract: TypeDescription, + contractReceivers: ContractReceivers, + wCtx: WriterContext, +) { + const hasExternal = !( + contractReceivers.external.binary.length === 0 && + contractReceivers.external.comment.length === 0 && + typeof contractReceivers.external.commentFallback === "undefined" && + typeof contractReceivers.external.empty === "undefined" && + typeof contractReceivers.external.fallback === "undefined" + ); + + // Load opcodes + writeLoadOpcode(contractReceivers.internal, wCtx); + wCtx.append(); + + if (hasExternal) { + writeLoadOpcode(contractReceivers.external, wCtx); + wCtx.append(); + } + + // Render fake internal receiver for setting using-flag for used procedures (fift-level hack) + wCtx.inBlock( + "() fake_recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure method_id(-65533)", + () => { + writeInternalBody(contract, contractReceivers, wCtx); + }, + ); + wCtx.append(); + + if (hasExternal) { + // Render fake external receiver for setting using-flag for used procedures (fift-level hack) + wCtx.inBlock( + "() fake_recv_external(slice in_msg) impure method_id(-65534)", + () => { + writeExternalBody(contract, contractReceivers, wCtx); + }, + ); + wCtx.append(); + } + + // Prepare @getters and @procs + wCtx.append(` +() _prepare_dicts() impure asm +""" +-65533 =: fake_recv_internal +-65534 =: fake_recv_external + +variable @tempdict +variable @getters +variable @procs +variable @has-external + +{ @procdict @ @tempdict ! } : @tempdict!init +{ fake_recv_external @tempdict @ @procdictkeylen idict@ dup { nip } if @has-external ! } : @has-external!init + +{ + @tempdict!init + @has-external!init +} : init-variables + + +// proc_flags -- f +{ 0x1a and 2 = } : (proc_flags)is-unused? +// proc_idx -- f +{ 65535 > } : (proc_idx)is-getter? + +// f(key value) dict keylen -- +{ rot 1 { execute -1 } does idictforeach drop } : *idict@foreach +// f(key value) -- +{ @tempdict @ @procdictkeylen *idict@foreach } : @tempdict@foreach +{ @procinfo @ @procdictkeylen *idict@foreach } : @procinfo@foreach + + +// key value -- +{ swap @getters @ @procdictkeylen idict! drop @getters ! } : @getters!set-proc +{ swap @procs @ @procdictkeylen idict! drop @procs ! } : @procs!set-proc + +// -- f +{ @getters @ null? } : @getters@empty? +{ @procs @ null? } : @procs@empty? + +// proc_idx -- +{ @tempdict @ @procdictkeylen idict- drop @tempdict ! } : @tempdict!remove-proc + +// proc_idx proc_flags -- +{ + (proc_flags)is-unused? + { @tempdict!remove-proc } + { drop } + cond +} : @tempdict!remove-proc-if-unused + +// -- +{ + { 16 i@ @tempdict!remove-proc-if-unused } + @procinfo@foreach + + fake_recv_internal @tempdict!remove-proc + fake_recv_external @tempdict!remove-proc + recv_internal @tempdict!remove-proc + recv_external @tempdict!remove-proc +} : @tempdict!remove-unused-procs + +// -- +{ + @tempdict!remove-unused-procs + + { + over (proc_idx)is-getter? + { @getters!set-proc } + { @procs!set-proc } + cond + } + @tempdict@foreach +} : prepare-dicts + +init-variables +prepare-dicts +"""; +`); + + wCtx.append(` +() _internal_selector_part() impure asm +""" + PUSHCONT + c3 POP +} ifnot + +// selector +@getters@empty? +{ DUP 11 THROWARGIF } +{ + DUP // selector selector + <{ + @getters @ @procdictkeylen DICTPUSHCONST + DICTIGETJMPZ + 11 THROWARG + }> PUSHCONT // selector selector cont + IFJMP // selector + DROP +} +cond + +swap b> { + wCtx.append(`_prepare_dicts();`); + wCtx.append(`_internal_selector_part();`); + writeInternalBody(contract, contractReceivers, wCtx); + }, + ); + + if (hasExternal) { + wCtx.append(` +() _external_selector_part() impure asm +""" + PUSHCONT + c3 POP +} ifnot + +// selector +DUP INC <{ recv_internal INLINECALL }>c IFJMPREF DROP + +swap b> { + wCtx.inBlock("", () => { + wCtx.append(`_external_selector_part();`); + }); + writeExternalBody(contract, contractReceivers, wCtx); + }); + } + + wCtx.append(` +() __tact_selector_hack_asm() impure asm """ + variable @tempdict + variable @internal + variable @external + + { b> init-variables + <{ + has-external { external, } { internal, } cond + }> b> + } : }END>c + current@ context! current! + } does @atend ! +""";`); + + wCtx.append(` +() __tact_selector_hack() method_id(-65535) { + return __tact_selector_hack_asm(); +}`); +} + +function writeContractReseivers( + contract: TypeDescription, + contractReceivers: ContractReceivers, + wCtx: WriterContext, +) { + const hasExternal = !( + contractReceivers.external.binary.length === 0 && + contractReceivers.external.comment.length === 0 && + typeof contractReceivers.external.commentFallback === "undefined" && + typeof contractReceivers.external.empty === "undefined" && + typeof contractReceivers.external.fallback === "undefined" + ); + + writeLoadOpcode(contractReceivers.internal, wCtx); + wCtx.append(); + + wCtx.inBlock( + "() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure", + () => { + writeInternalBody(contract, contractReceivers, wCtx); + }, + ); + wCtx.append(); + + if (hasExternal) { + writeLoadOpcode(contractReceivers.external, wCtx); + wCtx.append(); + + wCtx.inBlock("() recv_external(slice in_msg) impure", () => { + writeExternalBody(contract, contractReceivers, wCtx); + }); + wCtx.append(); + } +} + export function writeMainContract( contract: TypeDescription, abiLink: string, @@ -398,176 +728,15 @@ export function writeMainContract( const contractReceivers = groupContractReceivers(contract); - writeLoadOpcode(contractReceivers.internal, wCtx); - wCtx.append(); - - // Render internal receiver - wCtx.inBlock( - "() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure", - () => { - wCtx.append(); - wCtx.append(`;; Context`); - wCtx.append(`var cs = in_msg_cell.begin_parse();`); - wCtx.append(`cs~skip_bits(2);`); // skip int_msg_info$0 ihr_disabled:Bool - wCtx.append(`var msg_bounceable = cs~load_int(1);`); // bounce:Bool - wCtx.append(`var msg_bounced = cs~load_int(1);`); // bounced:Bool - wCtx.append(`slice msg_sender_addr = cs~load_msg_addr();`); - - if (contract.globalVariables.has("context")) { - wCtx.append( - `__tact_context = (msg_bounceable, msg_sender_addr, msg_value, cs);`, - ); - } - if (contract.globalVariables.has("sender")) { - wCtx.append(`__tact_context_sender = msg_sender_addr;`); - } - if (contract.globalVariables.has("inMsg")) { - wCtx.append(`__tact_in_msg = in_msg;`); - } - - wCtx.append(); - - writeLoadContractVariables(contract, wCtx); - - writeBouncedRouter(contractReceivers.bounced, contract, wCtx); - - writeNonBouncedRouter( - contractReceivers.internal, - contract, - wCtx, - ); - }, - ); - wCtx.append(); - - // Render external receiver - const hasExternal = !( - contractReceivers.external.binary.length === 0 && - contractReceivers.external.comment.length === 0 && - typeof contractReceivers.external.commentFallback === "undefined" && - typeof contractReceivers.external.empty === "undefined" && - typeof contractReceivers.external.fallback === "undefined" - ); - if (hasExternal) { - writeLoadOpcode(contractReceivers.external, wCtx); - wCtx.append(); - - wCtx.inBlock("() recv_external(slice in_msg) impure", () => { - if (contract.globalVariables.has("inMsg")) { - wCtx.append(`__tact_in_msg = in_msg;`); - } - - writeLoadContractVariables(contract, wCtx); - - writeNonBouncedRouter( - contractReceivers.external, - contract, - wCtx, - ); - }); - } - // fift injection, protected by a feature flag if (enabledInternalExternalReceiversOutsideMethodsMap(wCtx.ctx)) { - wCtx.append(` -() __tact_selector_hack_asm() impure asm """ -@atend @ 1 { - execute current@ context@ current! - { - // The core idea of this function is to save gas by avoiding unnecessary dict jump, when recv_internal/recv_external is called - // We want to extract recv_internal/recv_external from the dict and select needed function - // not by jumping to the needed function by it's index, but by using usual IF statements. - - }END> b> // Close previous builder, now we have a cell of previous code on top of the stack - - <{ // Start of the new code builder - SETCP0 - // Swap the new code builder with the previous code, now we have previous code on top of the stack - swap - // Transform cell to slice and load first ref from the previous code, now we have the dict on top of the stack - PUSHCONT - // Store the continuation in c3 - c3 POP - } cond - - // Function id is on top of the (runtime) stack - DUP IFNOTJMP:<{ - // place recv_internal here - DROP swap @addop - }>`); - - if (hasExternal) { - wCtx.append(` - DUP INC IFNOTJMP:<{ - // place recv_external here - DROP swap @addop - }>`); - } - - wCtx.append(` - // Bring back the flag, indicating if the dict is empty or not from the bottom of the stack - depth 1- roll - { - // If the dict is empty, throw 11 - 11 THROWARG - } - { - // If the dict is not empty, jump to continuation from c3 - c3 PUSH JMPX - } cond - }> b> - } : }END>c - current@ context! current! - } does @atend ! -""";`); - - wCtx.append(` -() __tact_selector_hack() method_id(65535) { - return __tact_selector_hack_asm(); -}`); + writeContractReseiversSelectorHack( + contract, + contractReceivers, + wCtx, + ); + } else { + writeContractReseivers(contract, contractReceivers, wCtx); } }); } diff --git a/src/generator/writers/writeRouter.ts b/src/generator/writers/writeRouter.ts index 3474b7860d..2fcfacf441 100644 --- a/src/generator/writers/writeRouter.ts +++ b/src/generator/writers/writeRouter.ts @@ -29,7 +29,7 @@ import { prettyPrint } from "@/ast/ast-printer"; import { escapeUnicodeControlCodes } from "@/utils/text"; import { writeCellParser } from "@/generator/writers/writeSerialization"; -type ContractReceivers = { +export type ContractReceivers = { readonly internal: Receivers; readonly external: Receivers; readonly bounced: BouncedReceivers; diff --git a/src/pipeline/__snapshots__/packaging.spec.ts.snap b/src/pipeline/__snapshots__/packaging.spec.ts.snap index 687f282074..0c374fada1 100644 --- a/src/pipeline/__snapshots__/packaging.spec.ts.snap +++ b/src/pipeline/__snapshots__/packaging.spec.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`should correctly generate .pkg file: Windows uses Unix-like paths 1`] = `"{"name":"Echo","code":"te6ccgECCwEAAfwAAij/AI6I9KQT9LzyyAvtUyDjA+1D2QECAgN44AMEA/Qw7aLt+wHQctch0gDSAPpAIRA0UGZvBPhhAvhi7UTQ0gAwkW2RbeICkVvgcCHXSSDCH+MAAcAAjrnCH460gCDXIds8+EJ/cFADgEIBUDMEyM+FgMoAz4RAzgH6AoBqz0D0AMkB+wAwyH8BygDJ7VTbMeCRMOLIAc8WyQcICQEjudPu1E0NIAMJFtkW3iAds8MYBQEjuDYu1E0NIAMJFtkW3iAds8MYBgAKqgmAILACUshvAAFvjG1vjIt0hlbGxvLCCNs8Ads8byIByZMhbrOWAW8iWczJ6DHQCgoAoDEh1wsfIIIQe6INwbqOP18DbwDIATCCEHuiDcEByx/J+EJ/cFADgEIBUDMEyM+FgMoAz4RAzgH6AoBqz0D0AMkB+wAwyH8BygDJ7VTbMeABAULIcAHLH28AAW+MbW+MAds8byIByZMhbrOWAW8iWczJ6DEKAFj4Qn9wUAOAQgFQMwTIz4WAygDPhEDOAfoCgGrPQPQAyQH7ADDIfwHKAMntVAC2INdKIddJlyDCACLCALGOSANvIoB/Is8xqwKhBasCUVW2CCDCAJogqgIV1xgDzkAU3llvAlNBocIAmcgBbwJQRKGqAo4SMTPCAJnUMNAg10oh10mScCDi4uhfAw==","abi":"{\\"name\\":\\"Echo\\",\\"types\\":[{\\"name\\":\\"DataSize\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"cells\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"bits\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"refs\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}]},{\\"name\\":\\"SignedBundle\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"signature\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"fixed-bytes\\",\\"optional\\":false,\\"format\\":64}},{\\"name\\":\\"signedData\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false,\\"format\\":\\"remainder\\"}}]},{\\"name\\":\\"StateInit\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"code\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":false}},{\\"name\\":\\"data\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":false}}]},{\\"name\\":\\"Context\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"bounceable\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}},{\\"name\\":\\"sender\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"raw\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false}}]},{\\"name\\":\\"SendParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"code\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"data\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"to\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}}]},{\\"name\\":\\"MessageParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"to\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}}]},{\\"name\\":\\"DeployParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}},{\\"name\\":\\"init\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"StateInit\\",\\"optional\\":false}}]},{\\"name\\":\\"StdAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"workchain\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":8}},{\\"name\\":\\"address\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"uint\\",\\"optional\\":false,\\"format\\":256}}]},{\\"name\\":\\"VarAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"workchain\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":32}},{\\"name\\":\\"address\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false}}]},{\\"name\\":\\"BasechainAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"hash\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":true,\\"format\\":257}}]},{\\"name\\":\\"EchoMessage\\",\\"header\\":2074217921,\\"fields\\":[]},{\\"name\\":\\"Echo$Data\\",\\"header\\":null,\\"fields\\":[]}],\\"receivers\\":[{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"typed\\",\\"type\\":\\"EchoMessage\\"}},{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"text\\"}},{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"any\\"}}],\\"getters\\":[{\\"name\\":\\"hello\\",\\"methodId\\":115554,\\"arguments\\":[{\\"name\\":\\"src\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"string\\",\\"optional\\":false}}],\\"returnType\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"string\\",\\"optional\\":false}},{\\"name\\":\\"hello2\\",\\"methodId\\":105790,\\"arguments\\":[{\\"name\\":\\"src\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}],\\"returnType\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}],\\"errors\\":{\\"2\\":{\\"message\\":\\"Stack underflow\\"},\\"3\\":{\\"message\\":\\"Stack overflow\\"},\\"4\\":{\\"message\\":\\"Integer overflow\\"},\\"5\\":{\\"message\\":\\"Integer out of expected range\\"},\\"6\\":{\\"message\\":\\"Invalid opcode\\"},\\"7\\":{\\"message\\":\\"Type check error\\"},\\"8\\":{\\"message\\":\\"Cell overflow\\"},\\"9\\":{\\"message\\":\\"Cell underflow\\"},\\"10\\":{\\"message\\":\\"Dictionary error\\"},\\"11\\":{\\"message\\":\\"'Unknown' error\\"},\\"12\\":{\\"message\\":\\"Fatal error\\"},\\"13\\":{\\"message\\":\\"Out of gas error\\"},\\"14\\":{\\"message\\":\\"Virtualization error\\"},\\"32\\":{\\"message\\":\\"Action list is invalid\\"},\\"33\\":{\\"message\\":\\"Action list is too long\\"},\\"34\\":{\\"message\\":\\"Action is invalid or not supported\\"},\\"35\\":{\\"message\\":\\"Invalid source address in outbound message\\"},\\"36\\":{\\"message\\":\\"Invalid destination address in outbound message\\"},\\"37\\":{\\"message\\":\\"Not enough Toncoin\\"},\\"38\\":{\\"message\\":\\"Not enough extra currencies\\"},\\"39\\":{\\"message\\":\\"Outbound message does not fit into a cell after rewriting\\"},\\"40\\":{\\"message\\":\\"Cannot process a message\\"},\\"41\\":{\\"message\\":\\"Library reference is null\\"},\\"42\\":{\\"message\\":\\"Library change action error\\"},\\"43\\":{\\"message\\":\\"Exceeded maximum number of cells in the library or the maximum depth of the Merkle tree\\"},\\"50\\":{\\"message\\":\\"Account state size exceeded limits\\"},\\"128\\":{\\"message\\":\\"Null reference exception\\"},\\"129\\":{\\"message\\":\\"Invalid serialization prefix\\"},\\"130\\":{\\"message\\":\\"Invalid incoming message\\"},\\"131\\":{\\"message\\":\\"Constraints error\\"},\\"132\\":{\\"message\\":\\"Access denied\\"},\\"133\\":{\\"message\\":\\"Contract stopped\\"},\\"134\\":{\\"message\\":\\"Invalid argument\\"},\\"135\\":{\\"message\\":\\"Code of a contract was not found\\"},\\"136\\":{\\"message\\":\\"Invalid standard address\\"},\\"138\\":{\\"message\\":\\"Not a basechain address\\"}},\\"interfaces\\":[\\"org.ton.introspection.v0\\",\\"org.ton.abi.ipfs.v0\\",\\"org.ton.deploy.lazy.v0\\"]}","init":{"kind":"direct","args":[],"prefix":{"bits":1,"value":0},"deployment":{"kind":"system-cell","system":null}},"sources":{"packaging.tact":"bWVzc2FnZSgweDdiYTIwZGMxKSBFY2hvTWVzc2FnZSB7fQoKY29udHJhY3QgRWNobyB7CiAgICByZWNlaXZlKG1zZzogRWNob01lc3NhZ2UpIHsKICAgICAgICBzZWxmLnJlcGx5KG1zZy50b0NlbGwoKSk7CiAgICB9CiAgICAKICAgIHJlY2VpdmUobXNnOiBTdHJpbmcpIHsKICAgICAgICBzZWxmLnJlcGx5KG1zZy5hc0NvbW1lbnQoKSk7CiAgICB9CiAgICAKICAgIHJlY2VpdmUobXNnOiBTbGljZSkgewogICAgICAgIHNlbGYucmVwbHkobXNnLmFzQ2VsbCgpKTsKICAgIH0KCiAgICBnZXQgZnVuIGhlbGxvKHNyYzogU3RyaW5nKTogU3RyaW5nIHsKICAgICAgICBsZXQgYnVpbGRlcjogU3RyaW5nQnVpbGRlciA9IGJlZ2luU3RyaW5nKCk7CiAgICAgICAgYnVpbGRlci5hcHBlbmQoIkhlbGxvLCAiKTsKICAgICAgICBidWlsZGVyLmFwcGVuZChzcmMpOwogICAgICAgIHJldHVybiBidWlsZGVyLnRvU3RyaW5nKCk7CiAgICB9CgogICAgZ2V0IGZ1biBoZWxsbzIoc3JjOiBJbnQpOiBJbnQgewogICAgICAgIHJldHVybiBzcmMgPDwgMTAgJiAzMjsKICAgIH0KfQ=="},"compiler":{"name":"tact","version":"1.6.13","parameters":"{\\"entrypoint\\":\\"./packaging.tact\\",\\"options\\":{}}"}}"`; +exports[`should correctly generate .pkg file: Windows uses Unix-like paths 1`] = `"{"name":"Echo","code":"te6ccgECCgEAAfIAA/T/ACCOiPSkE/S88sgL4DDtou37AdBy1yHSANIA+kAhEDRQZm8E+GEC+GLtRNDSADCRbZFt4gKRW+BwIddJIMIf4wABwACRMOMNyAHPFsn4Qn9wUAOAQgFQMwTIz4WAygDPhEDOAfoCgGrPQPQAyQH7ADDIfwHKAMntVAECAwIDeOAEBQCgMSHXCx8gghB7og3Buo4/XwNvAMgBMIIQe6INwQHLH8n4Qn9wUAOAQgFQMwTIz4WAygDPhEDOAfoCgGrPQPQAyQH7ADDIfwHKAMntVNsx4AEBcsIfjrSAINch2zz4Qn9wUAOAQgFQMwTIz4WAygDPhEDOAfoCgGrPQPQAyQH7ADDIfwHKAMntVNsx4AgBI7nT7tRNDSADCRbZFt4gHbPDGAYBI7g2LtRNDSADCRbZFt4gHbPDGAcACqoJgCCwAlLIbwABb4xtb4yLdIZWxsbywgjbPAHbPG8iAcmTIW6zlgFvIlnMyegx0AkJAULIcAHLH28AAW+MbW+MAds8byIByZMhbrOWAW8iWczJ6DEJALYg10oh10mXIMIAIsIAsY5IA28igH8izzGrAqEFqwJRVbYIIMIAmiCqAhXXGAPOQBTeWW8CU0GhwgCZyAFvAlBEoaoCjhIxM8IAmdQw0CDXSiHXSZJwIOLi6F8D","abi":"{\\"name\\":\\"Echo\\",\\"types\\":[{\\"name\\":\\"DataSize\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"cells\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"bits\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"refs\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}]},{\\"name\\":\\"SignedBundle\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"signature\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"fixed-bytes\\",\\"optional\\":false,\\"format\\":64}},{\\"name\\":\\"signedData\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false,\\"format\\":\\"remainder\\"}}]},{\\"name\\":\\"StateInit\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"code\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":false}},{\\"name\\":\\"data\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":false}}]},{\\"name\\":\\"Context\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"bounceable\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}},{\\"name\\":\\"sender\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"raw\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false}}]},{\\"name\\":\\"SendParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"code\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"data\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"to\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}}]},{\\"name\\":\\"MessageParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"to\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"address\\",\\"optional\\":false}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}}]},{\\"name\\":\\"DeployParameters\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"mode\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"body\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"cell\\",\\"optional\\":true}},{\\"name\\":\\"value\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}},{\\"name\\":\\"bounce\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"bool\\",\\"optional\\":false}},{\\"name\\":\\"init\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"StateInit\\",\\"optional\\":false}}]},{\\"name\\":\\"StdAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"workchain\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":8}},{\\"name\\":\\"address\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"uint\\",\\"optional\\":false,\\"format\\":256}}]},{\\"name\\":\\"VarAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"workchain\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":32}},{\\"name\\":\\"address\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"slice\\",\\"optional\\":false}}]},{\\"name\\":\\"BasechainAddress\\",\\"header\\":null,\\"fields\\":[{\\"name\\":\\"hash\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":true,\\"format\\":257}}]},{\\"name\\":\\"EchoMessage\\",\\"header\\":2074217921,\\"fields\\":[]},{\\"name\\":\\"Echo$Data\\",\\"header\\":null,\\"fields\\":[]}],\\"receivers\\":[{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"typed\\",\\"type\\":\\"EchoMessage\\"}},{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"text\\"}},{\\"receiver\\":\\"internal\\",\\"message\\":{\\"kind\\":\\"any\\"}}],\\"getters\\":[{\\"name\\":\\"hello\\",\\"methodId\\":115554,\\"arguments\\":[{\\"name\\":\\"src\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"string\\",\\"optional\\":false}}],\\"returnType\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"string\\",\\"optional\\":false}},{\\"name\\":\\"hello2\\",\\"methodId\\":105790,\\"arguments\\":[{\\"name\\":\\"src\\",\\"type\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}],\\"returnType\\":{\\"kind\\":\\"simple\\",\\"type\\":\\"int\\",\\"optional\\":false,\\"format\\":257}}],\\"errors\\":{\\"2\\":{\\"message\\":\\"Stack underflow\\"},\\"3\\":{\\"message\\":\\"Stack overflow\\"},\\"4\\":{\\"message\\":\\"Integer overflow\\"},\\"5\\":{\\"message\\":\\"Integer out of expected range\\"},\\"6\\":{\\"message\\":\\"Invalid opcode\\"},\\"7\\":{\\"message\\":\\"Type check error\\"},\\"8\\":{\\"message\\":\\"Cell overflow\\"},\\"9\\":{\\"message\\":\\"Cell underflow\\"},\\"10\\":{\\"message\\":\\"Dictionary error\\"},\\"11\\":{\\"message\\":\\"'Unknown' error\\"},\\"12\\":{\\"message\\":\\"Fatal error\\"},\\"13\\":{\\"message\\":\\"Out of gas error\\"},\\"14\\":{\\"message\\":\\"Virtualization error\\"},\\"32\\":{\\"message\\":\\"Action list is invalid\\"},\\"33\\":{\\"message\\":\\"Action list is too long\\"},\\"34\\":{\\"message\\":\\"Action is invalid or not supported\\"},\\"35\\":{\\"message\\":\\"Invalid source address in outbound message\\"},\\"36\\":{\\"message\\":\\"Invalid destination address in outbound message\\"},\\"37\\":{\\"message\\":\\"Not enough Toncoin\\"},\\"38\\":{\\"message\\":\\"Not enough extra currencies\\"},\\"39\\":{\\"message\\":\\"Outbound message does not fit into a cell after rewriting\\"},\\"40\\":{\\"message\\":\\"Cannot process a message\\"},\\"41\\":{\\"message\\":\\"Library reference is null\\"},\\"42\\":{\\"message\\":\\"Library change action error\\"},\\"43\\":{\\"message\\":\\"Exceeded maximum number of cells in the library or the maximum depth of the Merkle tree\\"},\\"50\\":{\\"message\\":\\"Account state size exceeded limits\\"},\\"128\\":{\\"message\\":\\"Null reference exception\\"},\\"129\\":{\\"message\\":\\"Invalid serialization prefix\\"},\\"130\\":{\\"message\\":\\"Invalid incoming message\\"},\\"131\\":{\\"message\\":\\"Constraints error\\"},\\"132\\":{\\"message\\":\\"Access denied\\"},\\"133\\":{\\"message\\":\\"Contract stopped\\"},\\"134\\":{\\"message\\":\\"Invalid argument\\"},\\"135\\":{\\"message\\":\\"Code of a contract was not found\\"},\\"136\\":{\\"message\\":\\"Invalid standard address\\"},\\"138\\":{\\"message\\":\\"Not a basechain address\\"}},\\"interfaces\\":[\\"org.ton.introspection.v0\\",\\"org.ton.abi.ipfs.v0\\",\\"org.ton.deploy.lazy.v0\\"]}","init":{"kind":"direct","args":[],"prefix":{"bits":1,"value":0},"deployment":{"kind":"system-cell","system":null}},"sources":{"packaging.tact":"bWVzc2FnZSgweDdiYTIwZGMxKSBFY2hvTWVzc2FnZSB7fQoKY29udHJhY3QgRWNobyB7CiAgICByZWNlaXZlKG1zZzogRWNob01lc3NhZ2UpIHsKICAgICAgICBzZWxmLnJlcGx5KG1zZy50b0NlbGwoKSk7CiAgICB9CiAgICAKICAgIHJlY2VpdmUobXNnOiBTdHJpbmcpIHsKICAgICAgICBzZWxmLnJlcGx5KG1zZy5hc0NvbW1lbnQoKSk7CiAgICB9CiAgICAKICAgIHJlY2VpdmUobXNnOiBTbGljZSkgewogICAgICAgIHNlbGYucmVwbHkobXNnLmFzQ2VsbCgpKTsKICAgIH0KCiAgICBnZXQgZnVuIGhlbGxvKHNyYzogU3RyaW5nKTogU3RyaW5nIHsKICAgICAgICBsZXQgYnVpbGRlcjogU3RyaW5nQnVpbGRlciA9IGJlZ2luU3RyaW5nKCk7CiAgICAgICAgYnVpbGRlci5hcHBlbmQoIkhlbGxvLCAiKTsKICAgICAgICBidWlsZGVyLmFwcGVuZChzcmMpOwogICAgICAgIHJldHVybiBidWlsZGVyLnRvU3RyaW5nKCk7CiAgICB9CgogICAgZ2V0IGZ1biBoZWxsbzIoc3JjOiBJbnQpOiBJbnQgewogICAgICAgIHJldHVybiBzcmMgPDwgMTAgJiAzMjsKICAgIH0KfQ=="},"compiler":{"name":"tact","version":"1.6.13","parameters":"{\\"entrypoint\\":\\"./packaging.tact\\",\\"options\\":{}}"}}"`; diff --git a/src/test/codegen-check/__snapshots__/codegen.test.ts.snap b/src/test/codegen-check/__snapshots__/codegen.test.ts.snap index d7f423091a..23fad20db9 100644 --- a/src/test/codegen-check/__snapshots__/codegen.test.ts.snap +++ b/src/test/codegen-check/__snapshots__/codegen.test.ts.snap @@ -561,8 +561,7 @@ _ %asSlice() method_id(68231) { ;; Returns 32 bit message opcode, otherwise throws the "Invalid incoming message" exit code (slice, int) ~load_opcode_internal(slice s) asm( -> 1 0) "32 LDUQ 130 THROWIFNOT"; -() recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure { - +() fake_recv_internal(int msg_value, cell in_msg_cell, slice in_msg) impure method_id(-65533) { ;; Context var cs = in_msg_cell.begin_parse(); cs~skip_bits(2); @@ -637,85 +636,232 @@ _ %asSlice() method_id(68231) { } +() _prepare_dicts() impure asm +""" +-65533 =: fake_recv_internal +-65534 =: fake_recv_external + +variable @tempdict +variable @getters +variable @procs +variable @has-external + +{ @procdict @ @tempdict ! } : @tempdict!init +{ fake_recv_external @tempdict @ @procdictkeylen idict@ dup { nip } if @has-external ! } : @has-external!init + +{ + @tempdict!init + @has-external!init +} : init-variables + + +// proc_flags -- f +{ 0x1a and 2 = } : (proc_flags)is-unused? +// proc_idx -- f +{ 65535 > } : (proc_idx)is-getter? + +// f(key value) dict keylen -- +{ rot 1 { execute -1 } does idictforeach drop } : *idict@foreach +// f(key value) -- +{ @tempdict @ @procdictkeylen *idict@foreach } : @tempdict@foreach +{ @procinfo @ @procdictkeylen *idict@foreach } : @procinfo@foreach + + +// key value -- +{ swap @getters @ @procdictkeylen idict! drop @getters ! } : @getters!set-proc +{ swap @procs @ @procdictkeylen idict! drop @procs ! } : @procs!set-proc + +// -- f +{ @getters @ null? } : @getters@empty? +{ @procs @ null? } : @procs@empty? + +// proc_idx -- +{ @tempdict @ @procdictkeylen idict- drop @tempdict ! } : @tempdict!remove-proc + +// proc_idx proc_flags -- +{ + (proc_flags)is-unused? + { @tempdict!remove-proc } + { drop } + cond +} : @tempdict!remove-proc-if-unused + +// -- +{ + { 16 i@ @tempdict!remove-proc-if-unused } + @procinfo@foreach + + fake_recv_internal @tempdict!remove-proc + fake_recv_external @tempdict!remove-proc + recv_internal @tempdict!remove-proc + recv_external @tempdict!remove-proc +} : @tempdict!remove-unused-procs + +// -- +{ + @tempdict!remove-unused-procs + + { + over (proc_idx)is-getter? + { @getters!set-proc } + { @procs!set-proc } + cond + } + @tempdict@foreach +} : prepare-dicts + +init-variables +prepare-dicts +"""; + + +() _internal_selector_part() impure asm +""" + PUSHCONT + c3 POP +} ifnot + +// selector +@getters@empty? +{ DUP 11 THROWARGIF } +{ + DUP // selector selector + <{ + @getters @ @procdictkeylen DICTPUSHCONST + DICTIGETJMPZ + 11 THROWARG + }> PUSHCONT // selector selector cont + IFJMP // selector + DROP +} +cond + +swap b> = 32) { + op = in_msg~load_uint(32); + ;; Receive Bin message + if (op == 0x2) { + var $m = empty_tuple(); + throw_unless(53588, (0x2 == 2)); + $MainContract$_contract_store(($self'field, $self'value, $self'data, $self'mapping)); + return (); + } + + ;; Receive Message1 message + if (op == 3110385022) { + var $msg'a = in_msg~load_int(257); + throw($msg'a); + $MainContract$_contract_store(($self'field, $self'value, $self'data, $self'mapping)); + return (); + } + + ;; Receive Message2 message + if (op == 797349837) { + var $msg'value = in_msg~load_ref(); + var $msg'value2 = in_msg~load_ref().begin_parse(); + int $sc_1 = 10; + int $sc_2 = 20; + int $in_msg = ($sc_1 + $sc_2); + throw_if($in_msg, ($in_msg == 0)); + throw(($Cell$_fun_depth($msg'value) + $Slice$_fun_depth($msg'value2))); + $MainContract$_contract_store(($self'field, $self'value, $self'data, $self'mapping)); + return (); + } + + ;; Receive Message3 message + if (op == 1120645875) { + var $msg'val1 = in_msg~load_int(257); + var $msg'val2 = in_msg~load_int(257); + var $msg'val3 = in_msg~load_int(257); + slice sc_1 = in_msg~load_ref().begin_parse(); + var $msg'val4 = sc_1~load_int(257); + var $msg'val5 = sc_1~load_int(257); + var $msg'val6 = sc_1~load_int(257); + throw(((((($msg'val1 + $msg'val2) + $msg'val3) + $msg'val4) + $msg'val5) + $msg'val6)); + $MainContract$_contract_store(($self'field, $self'value, $self'data, $self'mapping)); + return (); + } + + } + ;; Empty Receiver and Text Receivers + var text_op = slice_hash(in_msg); + ;; Receive "Text\\x00receiver\\x01.\\x0aThis \\x07 is \\x0d a \\x1f test \\x7f comment \\x9f with \\x08 bad \\x0c chars" message + if (text_op == 0x384726d137b7c49fbc0d7801f7781fe550ac11c0c968cd9fb66c25c2a00e1365) { + $MainContract$_contract_store(($self'field, $self'value, $self'data, $self'mapping)); + return (); + } + ;; Throw if not handled + throw(130); +} + () __tact_selector_hack_asm() impure asm """ -@atend @ 1 { + variable @tempdict + variable @internal + variable @external + + { b> // Close previous builder, now we have a cell of previous code on top of the stack - - <{ // Start of the new code builder - SETCP0 - // Swap the new code builder with the previous code, now we have previous code on top of the stack - swap - // Transform cell to slice and load first ref from the previous code, now we have the dict on top of the stack - PUSHCONT - // Store the continuation in c3 - c3 POP - } cond - - // Function id is on top of the (runtime) stack - DUP IFNOTJMP:<{ - // place recv_internal here - DROP swap @addop - }> - - // Bring back the flag, indicating if the dict is empty or not from the bottom of the stack - depth 1- roll - { - // If the dict is empty, throw 11 - 11 THROWARG - } - { - // If the dict is not empty, jump to continuation from c3 - c3 PUSH JMPX - } cond - }> b> - } : }END>c - current@ context! current! - } does @atend ! + }END> b> init-variables + <{ + has-external { external, } { internal, } cond + }> b> + } : }END>c + current@ context! current! + } does @atend ! """; -() __tact_selector_hack() method_id(65535) { +() __tact_selector_hack() method_id(-65535) { return __tact_selector_hack_asm(); }" `; diff --git a/src/test/e2e-emulated/debug/__snapshots__/dump.spec.ts.snap b/src/test/e2e-emulated/debug/__snapshots__/dump.spec.ts.snap index 3c74954e84..d20f1d80cb 100644 --- a/src/test/e2e-emulated/debug/__snapshots__/dump.spec.ts.snap +++ b/src/test/e2e-emulated/debug/__snapshots__/dump.spec.ts.snap @@ -3,7 +3,7 @@ exports[`dump should dump values correctly in a receiver 1`] = ` "#DEBUG#: File src/test/e2e-emulated/debug/dump.tact:2:5: #DEBUG#: dumpStack() -#DEBUG#: stack(1 values) : 10999604800 +#DEBUG#: stack(1 values) : 10999625600 #DEBUG#: File src/test/e2e-emulated/debug/dump.tact:3:5: #DEBUG#: dump("Hello world!") #DEBUG#: Hello world! @@ -21,13 +21,13 @@ exports[`dump should dump values correctly in a receiver 1`] = ` #DEBUG#: null #DEBUG#: File src/test/e2e-emulated/debug/dump.tact:8:5: #DEBUG#: dump(myAddress()) -#DEBUG#: EQBW6PMGWgu6Gmg_pFckrGpQxm2ImeVELrquQXN0FaneV9fj +#DEBUG#: EQAN8wS2DjqgYuinZOxwOs9cJ23ZXoRHydMtyCYxNuqUeAsZ #DEBUG#: File src/test/e2e-emulated/debug/dump.tact:10:5: #DEBUG#: dump(address) #DEBUG#: EQCD39VS5jcptHL8vMjEXrzGaRcCVYto7HUn4bpAOg8xqB2N #DEBUG#: File src/test/e2e-emulated/debug/dump.tact:11:5: #DEBUG#: dump(myBalance()) -#DEBUG#: 10999604800 +#DEBUG#: 10999625600 #DEBUG#: File src/test/e2e-emulated/debug/dump.tact:15:5: #DEBUG#: dump(maybeBool1) #DEBUG#: null diff --git a/src/test/e2e-emulated/stdlib/__snapshots__/stdlib.spec.ts.snap b/src/test/e2e-emulated/stdlib/__snapshots__/stdlib.spec.ts.snap index ac22698da7..e0e71c067b 100644 --- a/src/test/e2e-emulated/stdlib/__snapshots__/stdlib.spec.ts.snap +++ b/src/test/e2e-emulated/stdlib/__snapshots__/stdlib.spec.ts.snap @@ -1,5 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`stdlib should execute stdlib methods correctly: Gas consumed in segGasLimit() 1`] = `3881`; +exports[`stdlib should execute stdlib methods correctly: Gas consumed in segGasLimit() 1`] = `3785`; -exports[`stdlib should execute stdlib methods correctly: tvm_2023_07Upgrade 1`] = `1439`; +exports[`stdlib should execute stdlib methods correctly: tvm_2023_07Upgrade 1`] = `1343`; diff --git a/src/test/gas-consumption/__snapshots__/gas.spec.ts.snap b/src/test/gas-consumption/__snapshots__/gas.spec.ts.snap index 240d1f8e8d..d7b6044c8a 100644 --- a/src/test/gas-consumption/__snapshots__/gas.spec.ts.snap +++ b/src/test/gas-consumption/__snapshots__/gas.spec.ts.snap @@ -1,85 +1,85 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`benchmarks benchmark BaseTrait: code size 1`] = `352`; +exports[`benchmarks benchmark BaseTrait: code size 1`] = `348`; -exports[`benchmarks benchmark BaseTrait: gas used for ForwardMessage 1`] = `3586`; +exports[`benchmarks benchmark BaseTrait: gas used for ForwardMessage 1`] = `3558`; -exports[`benchmarks benchmark BaseTrait: gas used for NotifyMessage 1`] = `3393`; +exports[`benchmarks benchmark BaseTrait: gas used for NotifyMessage 1`] = `3365`; -exports[`benchmarks benchmark BaseTrait: gas used for ReplyMessage 1`] = `3460`; +exports[`benchmarks benchmark BaseTrait: gas used for ReplyMessage 1`] = `3432`; -exports[`benchmarks benchmark cashback: gas used cashback 1`] = `3337`; +exports[`benchmarks benchmark cashback: gas used cashback 1`] = `3309`; -exports[`benchmarks benchmark cells creation: gas used emptyCell 1`] = `750n`; +exports[`benchmarks benchmark cells creation: gas used emptyCell 1`] = `654n`; -exports[`benchmarks benchmark cells creation: gas used emptySlice 1`] = `754n`; +exports[`benchmarks benchmark cells creation: gas used emptySlice 1`] = `658n`; -exports[`benchmarks benchmark codeOf vs initOf: gas used withCodeOf 1`] = `850n`; +exports[`benchmarks benchmark codeOf vs initOf: gas used withCodeOf 1`] = `754n`; -exports[`benchmarks benchmark codeOf vs initOf: gas used withInitOf 1`] = `1502n`; +exports[`benchmarks benchmark codeOf vs initOf: gas used withInitOf 1`] = `1406n`; -exports[`benchmarks benchmark codeOf vs myCode(): gas used codeOf for current contract 1`] = `858n`; +exports[`benchmarks benchmark codeOf vs myCode(): gas used codeOf for current contract 1`] = `762n`; -exports[`benchmarks benchmark codeOf vs myCode(): gas used myCode 1`] = `858n`; +exports[`benchmarks benchmark codeOf vs myCode(): gas used myCode 1`] = `762n`; -exports[`benchmarks benchmark contractAddressExt: gas used contractAddressExt 1`] = `2516n`; +exports[`benchmarks benchmark contractAddressExt: gas used contractAddressExt 1`] = `2420n`; -exports[`benchmarks benchmark deployable trait vs raw deploy: gas used deploy trait 1`] = `3837`; +exports[`benchmarks benchmark deployable trait vs raw deploy: gas used deploy trait 1`] = `3809`; -exports[`benchmarks benchmark deployable trait vs raw deploy: gas used raw deploy 1`] = `1505`; +exports[`benchmarks benchmark deployable trait vs raw deploy: gas used raw deploy 1`] = `1477`; -exports[`benchmarks benchmark functions: code size 1`] = `170`; +exports[`benchmarks benchmark functions: code size 1`] = `166`; -exports[`benchmarks benchmark functions: gas used 1`] = `1979`; +exports[`benchmarks benchmark functions: gas used 1`] = `1951`; -exports[`benchmarks benchmark log: gas used log 1`] = `1884n`; +exports[`benchmarks benchmark log: gas used log 1`] = `1788n`; -exports[`benchmarks benchmark readFwdFee: code size 1`] = `116`; +exports[`benchmarks benchmark readFwdFee: code size 1`] = `112`; -exports[`benchmarks benchmark readFwdFee: gas used 1`] = `1968`; +exports[`benchmarks benchmark readFwdFee: gas used 1`] = `1940`; -exports[`benchmarks benchmark sha256: gas hash string big 1`] = `2154`; +exports[`benchmarks benchmark sha256: gas hash string big 1`] = `2020`; -exports[`benchmarks benchmark sha256: gas hash string big repeated 1`] = `2155`; +exports[`benchmarks benchmark sha256: gas hash string big repeated 1`] = `2021`; -exports[`benchmarks benchmark sha256: gas hash string big repeated more 1`] = `2157`; +exports[`benchmarks benchmark sha256: gas hash string big repeated more 1`] = `2023`; -exports[`benchmarks benchmark sha256: gas hash string slice 1`] = `2154`; +exports[`benchmarks benchmark sha256: gas hash string slice 1`] = `2020`; -exports[`benchmarks benchmark sha256: gas hash string slice repeated 1`] = `2155`; +exports[`benchmarks benchmark sha256: gas hash string slice repeated 1`] = `2021`; -exports[`benchmarks benchmark sha256: gas hash string slice repeated more 1`] = `2157`; +exports[`benchmarks benchmark sha256: gas hash string slice repeated more 1`] = `2023`; -exports[`benchmarks benchmark sha256: gas hash string small 1`] = `1975`; +exports[`benchmarks benchmark sha256: gas hash string small 1`] = `1841`; -exports[`benchmarks benchmark sha256: gas hash string small repeated 1`] = `1975`; +exports[`benchmarks benchmark sha256: gas hash string small repeated 1`] = `1841`; -exports[`benchmarks benchmark sha256: gas hash string small repeated more 1`] = `1975`; +exports[`benchmarks benchmark sha256: gas hash string small repeated more 1`] = `1841`; -exports[`benchmarks benchmark sqrt via geom mean: code size 1`] = `265`; +exports[`benchmarks benchmark sqrt via geom mean: code size 1`] = `261`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 0 1`] = `2086`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 0 1`] = `2058`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 100 1`] = `2978`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 100 1`] = `2950`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 1000000000 1`] = `2978`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 1000000000 1`] = `2950`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 10000000000 1`] = `3185`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 10000000000 1`] = `3157`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 57896044618658097711785492504343953926634992332820282019728792003956564819968 1`] = `3806`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 57896044618658097711785492504343953926634992332820282019728792003956564819968 1`] = `3778`; -exports[`benchmarks benchmark sqrt via geom mean: gas used for value 115792089237316195423570985008687907853269984665640564039457584007913129639935 1`] = `2564`; +exports[`benchmarks benchmark sqrt via geom mean: gas used for value 115792089237316195423570985008687907853269984665640564039457584007913129639935 1`] = `2536`; -exports[`benchmarks benchmark sqrt: code size 1`] = `265`; +exports[`benchmarks benchmark sqrt: code size 1`] = `261`; -exports[`benchmarks benchmark sqrt: gas used for value 0 1`] = `1916`; +exports[`benchmarks benchmark sqrt: gas used for value 0 1`] = `1888`; -exports[`benchmarks benchmark sqrt: gas used for value 100 1`] = `3305`; +exports[`benchmarks benchmark sqrt: gas used for value 100 1`] = `3277`; -exports[`benchmarks benchmark sqrt: gas used for value 1000000000 1`] = `3398`; +exports[`benchmarks benchmark sqrt: gas used for value 1000000000 1`] = `3370`; -exports[`benchmarks benchmark sqrt: gas used for value 10000000000 1`] = `3398`; +exports[`benchmarks benchmark sqrt: gas used for value 10000000000 1`] = `3370`; -exports[`benchmarks benchmark sqrt: gas used for value 57896044618658097711785492504343953926634992332820282019728792003956564819968 1`] = `3711`; +exports[`benchmarks benchmark sqrt: gas used for value 57896044618658097711785492504343953926634992332820282019728792003956564819968 1`] = `3683`; -exports[`benchmarks benchmark sqrt: gas used for value 115792089237316195423570985008687907853269984665640564039457584007913129639935 1`] = `3711`; +exports[`benchmarks benchmark sqrt: gas used for value 115792089237316195423570985008687907853269984665640564039457584007913129639935 1`] = `3683`;